Skip to content

Fix potential deadlock in PyFutureAwaitable callback dispatch#802

Merged
gi0baro merged 2 commits intoemmett-framework:masterfrom
ColemanDunn:lockup-fix
Feb 8, 2026
Merged

Fix potential deadlock in PyFutureAwaitable callback dispatch#802
gi0baro merged 2 commits intoemmett-framework:masterfrom
ColemanDunn:lockup-fix

Conversation

@ColemanDunn
Copy link
Contributor

fixes #750

Reproduction of the issue can be found at: https://github.com/ColemanDunn/granian-channels-lock-up

Change is to not hold the RwLock across call_soon_threadsafe. The comment is somewhat self documenting of what this change does. I can take it out if needed. Perhaps there is a better fix than this in the underlying code, but I am now unable to reproduce the lockup.

@gi0baro
Copy link
Member

gi0baro commented Feb 8, 2026

I'm prone to consider this as a random effect, other than the actual solution.

I'm not exactly sure how the RwLock from PyFutureAwaitable.ack can led to deadlocks, given:

  • all the calls to code interacting with that lock are performed holding the GIL, thus:
    • none of the involved code can actually access that lock concurrently
    • the main thread is detached from the GIL (with the event loop in idle) when set_result gets called
  • call_soon_threadsafe doesn't really block, it simply add the callback to the loop "queue" and write a wake event

I'm going to still review the code and possibly merge it, as it might be a valid concern for the free-threaded builds, but again, it's hard to think this can be the actual solution on whatever the problem in #750 is, and more like a coincidence.

@gi0baro gi0baro merged commit 1a5a8c3 into emmett-framework:master Feb 8, 2026
20 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Server freeze with Django Channels and WebSocket under low load

2 participants