-
-
Notifications
You must be signed in to change notification settings - Fork 34.6k
Deadlock at shutdown with stop-the-world and daemon threads #137433
Copy link
Copy link
Closed
Labels
3.13bugs and security fixesbugs and security fixes3.14bugs and security fixesbugs and security fixes3.15pre-release feature fixes, bugs and security fixespre-release feature fixes, bugs and security fixesinterpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)topic-free-threadingtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
Metadata
Metadata
Assignees
Labels
3.13bugs and security fixesbugs and security fixes3.14bugs and security fixesbugs and security fixes3.15pre-release feature fixes, bugs and security fixespre-release feature fixes, bugs and security fixesinterpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)topic-free-threadingtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
Bug report
Bug description:
Reported by @pablogsal / @godlygeek from memray
Stack trace:
https://gist.github.com/pablogsal/513fa8b0c29cda852ce11c86ce3b1345
We have two threads, the main thread (M) and a daemon thread (D). The main thread starts
_Py_Finalize()and performs a global stop the world. The daemon thread is disabling profiling and so tries to performa a stop-the-world specific to it's interpreter:cpython/Python/pystate.c
Lines 2256 to 2267 in 9745976
M:
_PyEval_StopTheWorldAll():M: acquires
runtime->stoptheworld->mutexM: acquires RW lock
runtime->stoptheworld_mutexin W (exclusive) modeM: ... waits on threads
D:
_PyEval_StopTheWorld(interp):D: acquires
interp->stoptheworld->mutexD: ... blocks trying to acquire
runtime->stoptheworld_mutexin R mode. Later, the daemon thread will hang in_PyThreadState_HangThread()when trying to re-attach it's thread state.M:
_PyEval_StopTheWorldAll()finishes, marks the interpreter as finalizingM: ...
M: calls
_PyGC_CollectNoFail()which tries to run_PyEval_StopTheWorld(interp)M: ... blocks trying to acquire
interp->stoptheworld->mutex, which is still held by the daemon thread!Deadlock! Summary:
The daemon thread holds
interp->stoptheworld->mutexand is hanging because the interpreter is shutting down.The main thread is trying to perform the shutdown procedure, including calling the GC a few times, which requires
interp->stoptheworld->mutex.Fix???
interp->stoptheworld->mutexwhen hanging the thread if necessary? Crosses a bunch of abstraction barriers, which is messy and trickyCPython versions tested on:
CPython main branch
Operating systems tested on:
No response
Linked PRs