You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
test_asyncio.test_subprocess leaked dangling threads on PPC64LE Fedora Stable 3.x: #110205
Sorry, this is not fixed. The PR attempting to fix it was not merged.
I'm not interested to fix this issue anymore. If you consider that it's important issue, you can fix it. I close again the issue and unsubscribe from the issue.
Sorry to the audience for the waffling. Victor doesn't want anything to do with this issue any more. But I will fix it (starting with his PR). So reopening one more time (it's not completed yet.)
Warning -- threading_cleanup() failed to cleanup 1 threads (count: 1, dangling: 2)
Warning -- Dangling thread: <_MainThread(MainThread, started 140735686786240)>
Warning -- Dangling thread: <Thread(waitpid-0, started daemon 140735332413728)>
(which sets the "environment changed" flag, causing CI to fail) still occurs when _join_threads() is fixed to close all threads. The messages are printed from threading_cleanup() in test/support/threading_helper.py. Looking at the code and the output it's clear that it's the waitpid-0 thread that wasn't there before. The PR renames it to asyncio-waitpid-0, and I still see that output here.
It looks like the work to delete references to the watcher's threads is gone to waste because the code in ThreadedChildWatcher._join_threads() only joins (waits for) non-daemon threads, but the child handler thread is a daemon thread. There was a discussion about this very cleanup when the join code was added -- it was proposed to use self._threads.pop(pid) but that was never implemented. The child watcher thread has been a daemon thread since it was introduced by gh-14344, so I'm not sure that the join code ever did what it was supposed to do.
In conclusion, I think there's an old bug (_join_threads() doesn't join daemon threads, but watcher threads are daemon threads), and and a new bug in this PR (close_loop() used to join all threads, but the refactored logic only waits for non-daemon threads).
We need to ask ourselves, why do we sometimes find a dangling waitpid thread? The only reason I can see would be that the process hasn't exited -- then the thread will be hanging in the os.waitpid() call in ThreadedChildWatcher_do_waitpid(). And how can we prevent this situation from happening, or recover from it? IIUC we have no way to kill a thread, so calling join() on the blocked thread won't help (unless the process is about to exit).
IMO _join_threads() is always a no-op, we might as well get rid of it. One could argue that waiting for the watcher's thread in TestCase.close_loop() is the right thing, possibly with a 30s timeout, as long as it includes daemon threads, which are the only threads created by the watcher. The remaining embellishments currently in the PR aren't needed.
Activity
pythongh-110205: Fix asyncio ThreadedChildWatcher._join_threads()
pythongh-110205: Fix asyncio ThreadedChildWatcher._join_threads()
pythongh-110205: Fix asyncio ThreadedChildWatcher._join_threads()
pythongh-110205: Fix asyncio ThreadedChildWatcher._join_threads()
gvanrossum commentedon Oct 13, 2023
Sorry, this is not fixed. The PR attempting to fix it was not merged.
vstinner commentedon Oct 14, 2023
I'm not interested to fix this issue anymore. If you consider that it's important issue, you can fix it. I close again the issue and unsubscribe from the issue.
1 remaining item
gvanrossum commentedon Oct 14, 2023
Sorry to the audience for the waffling. Victor doesn't want anything to do with this issue any more. But I will fix it (starting with his PR). So reopening one more time (it's not completed yet.)
gvanrossum commentedon Oct 15, 2023
Interestingly, this test output quoted above:
(which sets the "environment changed" flag, causing CI to fail) still occurs when
_join_threads()is fixed to close all threads. The messages are printed fromthreading_cleanup()in test/support/threading_helper.py. Looking at the code and the output it's clear that it's the waitpid-0 thread that wasn't there before. The PR renames it to asyncio-waitpid-0, and I still see that output here.It looks like the work to delete references to the watcher's threads is gone to waste because the code in
ThreadedChildWatcher._join_threads()only joins (waits for) non-daemon threads, but the child handler thread is a daemon thread. There was a discussion about this very cleanup when the join code was added -- it was proposed to useself._threads.pop(pid)but that was never implemented. The child watcher thread has been a daemon thread since it was introduced by gh-14344, so I'm not sure that the join code ever did what it was supposed to do.In conclusion, I think there's an old bug (
_join_threads()doesn't join daemon threads, but watcher threads are daemon threads), and and a new bug in this PR (close_loop()used to join all threads, but the refactored logic only waits for non-daemon threads).We need to ask ourselves, why do we sometimes find a dangling waitpid thread? The only reason I can see would be that the process hasn't exited -- then the thread will be hanging in the
os.waitpid()call inThreadedChildWatcher_do_waitpid(). And how can we prevent this situation from happening, or recover from it? IIUC we have no way to kill a thread, so callingjoin()on the blocked thread won't help (unless the process is about to exit).IMO
_join_threads()is always a no-op, we might as well get rid of it. One could argue that waiting for the watcher's thread inTestCase.close_loop()is the right thing, possibly with a 30s timeout, as long as it includes daemon threads, which are the only threads created by the watcher. The remaining embellishments currently in the PR aren't needed.gh-110205: Fix asyncio ThreadedChildWatcher._join_threads() (#110884)
pythongh-110205: Fix asyncio ThreadedChildWatcher._join_threads() (py…
pythongh-110205: Fix asyncio ThreadedChildWatcher._join_threads() (py…
[3.12] gh-110205: Fix asyncio ThreadedChildWatcher._join_threads() (G…
[3.11] gh-110205: Fix asyncio ThreadedChildWatcher._join_threads() (G…
pythongh-110205: Fix asyncio ThreadedChildWatcher._join_threads() (py…
pythongh-110205: Fix asyncio ThreadedChildWatcher._join_threads() (py…
pythongh-110205: Fix asyncio ThreadedChildWatcher._join_threads() (py…