-
-
Notifications
You must be signed in to change notification settings - Fork 32.2k
bpo-42888: Remove PyThread_exit_thread() calls from top-level thread … #24241
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…functions PyThread_exit_thread() uses pthread_exit() on POSIX systems. In glibc, pthread_exit() is implemented in terms of pthread_cancel(), requiring the stack unwinder implemented in libgcc. Further, in dynamically linked applications, calls of pthread_exit() in source code do not make libgcc_s.so a startup dependency: instead, it's lazily loaded by glibc via dlopen() when pthread_exit() is called the first time[1]. All of this makes otherwise finely working CPython fail in multithreaded applications on thread exit if dlopen() fails for any reason. While providing libgcc_s.so is the reponsibility of the user (or their package manager), this hidden dependency has been the source of countless frustrations(e.g. [2]) and, further, dlopen() may fail for other reasons([3]). But most calls to PyThread_exit_thread() in CPython are useless because they're done from the top-level thread function and hence are equivalent to simply returning. So remove all such calls, thereby avoiding the glibc cancellation machinery. The only exception are calls in take_gil() (Python/ceval_gil.h) which serve as a safety net for daemon threads attempting to acquire the GIL after Py_Finalize(). Unless a better model for daemon threads is devised or support for them is removed, those calls have to be preserved since we need to terminate the thread right now without touching any interpreter state. Of course, since PyThread_exit_thread() is a public API, any extension module can still call it and trip over the same issue. [1] https://sourceware.org/legacy-ml/libc-help/2014-07/msg00000.html [2] https://stackoverflow.com/questions/64797838/libgcc-s-so-1-must-be-installed-for-pthread-cancel-to-work [3] https://www.sourceware.org/bugzilla/show_bug.cgi?id=13119
This PR is stale because it has been open for 30 days with no activity. |
Those changes preserve the debug output ( |
I never ever used PYTHONTHREADDEBUG=1. I just tried:
This debug mode produces so many logs that it looks basically useless :-( |
I started "Does anyone use threading debug PYTHONTHREADDEBUG=1 env var? Can I remove it?" thread on python-dev: |
I created https://bugs.python.org/issue44584 "Deprecate thread debugging PYTHONTHREADDEBUG=1". |
…functions
PyThread_exit_thread() uses pthread_exit() on POSIX systems. In glibc,
pthread_exit() is implemented in terms of pthread_cancel(), requiring
the stack unwinder implemented in libgcc. Further, in dynamically
linked applications, calls of pthread_exit() in source code do not
make libgcc_s.so a startup dependency: instead, it's lazily loaded
by glibc via dlopen() when pthread_exit() is called the first time[1].
All of this makes otherwise finely working CPython fail in multithreaded
applications on thread exit if dlopen() fails for any reason.
While providing libgcc_s.so is the reponsibility of the user
(or their package manager), this hidden dependency has been
the source of countless frustrations(e.g. [2]) and, further,
dlopen() may fail for other reasons([3]). But most calls
to PyThread_exit_thread() in CPython are useless because they're done
from the top-level thread function and hence are equivalent
to simply returning. So remove all such calls, thereby avoiding
the glibc cancellation machinery.
The only exception are calls in take_gil() (Python/ceval_gil.h)
which serve as a safety net for daemon threads attempting
to acquire the GIL after Py_Finalize(). Unless a better model for
daemon threads is devised or support for them is removed,
those calls have to be preserved since we need to terminate
the thread right now without touching any interpreter state.
Of course, since PyThread_exit_thread() is a public API,
any extension module can still call it and trip over the same issue.
[1] https://sourceware.org/legacy-ml/libc-help/2014-07/msg00000.html
[2] https://stackoverflow.com/questions/64797838/libgcc-s-so-1-must-be-installed-for-pthread-cancel-to-work
[3] https://www.sourceware.org/bugzilla/show_bug.cgi?id=13119
https://bugs.python.org/issue42888