GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | ||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | ||||||||
GeezerVison is showing github.com — bpo-39877: Fix PyEval_RestoreThread() for daemon threads by vstinner · Pull Request #18811 · python/cpython Conversation
|
|
Without this change, after Py_Finalize() has been called, daemon threads are not exited by exit_thread_if_finalizing(): exit_thread_if_finalizing() is not called. Instead, daemon threads loop on attempting to take the GIL :-( With this PR, daemon threads exit before attempting to take the GIL. Moreover, the PR better validates tstate which can help to detect misusage of modified functions of the C API like PyEval_RestoreThread(). |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
@ericsnowcurrently @nanjekyejoannah @pablogsal @pitrou @methane @serhiy-storchaka: Would you mind to review this PR? In short, this PR fix the code to exit daemon threads after Py_Finalize() has been called. Currently, it's broken in multiple different ways. But it worked somehow before my latest refactoring (see https://bugs.python.org/issue39877 for the cause of the regression). Main changes:
I chose to include "cleanup" changes in the PR: harden checks on tstate. I prefer to change all code at once. It should help to detect future bugs. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Looks good on the principle, some comments below.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Why does this function always return 1?
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
It's to be able to use it with assert(...). I like to use assert(), since it's removed in release mode. I'm using this pattern with _PyObject_CheckConsistency() and similar _PyXXX_CheckConsistency() functions.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
If an assertion fails, the function displays the expression which is false with the expected line number. That's why the function does use assert() directly rather than returning a value.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Since you're now accessing this without the GIL, should this field be manipulated only with atomic ops?
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
I don't think that it's worth it. If you consider that it should be done: can it be done in a separated PR after this one is merged? Does atomic operations provide any additional warranty compared to regular variables?
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
If you're not using an atomic variable, you may be getting a partially written value (it's very unlikely for a pointer-sized value, but theoretically possible). In other words, the code here is probably incorrect (ThreadSanitizer may help detect this).
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
|
When you're done making the requested changes, leave the comment: |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
I have made the requested changes; please review again. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Thanks for making the requested changes! @pitrou: please review the changes made to this pull request. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
* exit_thread_if_finalizing() does now access directly _PyRuntime variable, rather than using tstate->interp->runtime since tstate can be a dangling pointer after Py_Finalize() has been called. * exit_thread_if_finalizing() is now called *before* calling take_gil(). There is no need to protect the call with the GIL. * Add ensure_tstate_not_null() function to check that tstate is not NULL at runtime. Check tstate earlier. take_gil() is now responsible to check that tstate is not NULL. Cleanup: * PyEval_RestoreThread() no longer saves/restores errno: it's already done inside take_gil(). * PyEval_AcquireLock(), PyEval_AcquireThread(), PyEval_RestoreThread() and _PyEval_EvalFrameDefault() now check if tstate is valid with the new is_tstate_valid() function which uses _PyMem_IsPtrFreed().
|
@pitrou: _PyRuntime.finalizing is now atomic. Would you mind to review the updated PR? |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Thanks for the review @python/buildbot-owners Daemon threads should be a little bit more reliable during Python finalization with this change. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
Oops, I wanted to write: Thanks for the review @pitrou! (Firefox picked the wrong completion, sorry.) |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
bpo-39877: Fix PyEval_RestoreThread() for daemon threads (pythonGH-18811)
There was an error while loading. Please reload this page.
Successfully merging this pull request may close these issues.
There was an error while loading. Please reload this page.