-
Notifications
You must be signed in to change notification settings - Fork 36
Fix threading-related deadlocks, and also add support for Python's built-in listing of libraries #243
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
base: master
Are you sure you want to change the base?
Fix threading-related deadlocks, and also add support for Python's built-in listing of libraries #243
Changes from all commits
fa8717f
6bbb723
636a534
f80da80
69699b4
539c2ef
7fda3b8
2960ab3
d0bd959
c7e3945
479e156
6dcd6fd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -25,6 +25,12 @@ | |
| from functools import lru_cache | ||
| from contextlib import ContextDecorator | ||
|
|
||
| try: | ||
| from ctypes.util import dllist | ||
| except ImportError: | ||
| dllist = None | ||
|
|
||
|
|
||
| __version__ = "3.7.0.dev0" | ||
| __all__ = [ | ||
| "threadpool_limits", | ||
|
|
@@ -1122,15 +1128,63 @@ def __len__(self): | |
|
|
||
| def _load_libraries(self): | ||
| """Loop through loaded shared libraries and store the supported ones""" | ||
| if sys.platform == "darwin": | ||
| if sys.platform == "linux" and os.path.exists("/proc/self/maps"): | ||
| # On glibc, dl_iterate_phdr has an internal lock, and that plus | ||
| # calling back into Python and the need to (re)acquire the GIL | ||
| # results in deadlocks. To avoid that, use a Linux-specific | ||
| # mechanism that doesn't have these issues; since it's Linux, musl | ||
| # works fine too. | ||
| self._find_libraries_with_linux() | ||
| elif dllist is not None and sys.platform != "emscripten": | ||
| # On Python 3.14+, this functionality is built-in. Once Python 3.13 | ||
| # is no longer supported by threadpoolctl, most of the equivalent | ||
| # threadpoolctl implementations can be removed. | ||
| # | ||
| # We don't use this on Linux since it uses dl_iterate_phdr | ||
| # internally and so might still have deadlock issues. | ||
| self._find_libraries_with_python() | ||
| elif sys.platform == "darwin": | ||
| self._find_libraries_with_dyld() | ||
| elif sys.platform == "win32": | ||
| self._find_libraries_with_enum_process_module_ex() | ||
| elif "pyodide" in sys.modules: | ||
| self._find_libraries_pyodide() | ||
| else: | ||
| # Non-Linux Unix platforms. | ||
| self._find_libraries_with_dl_iterate_phdr() | ||
|
|
||
| def _find_libraries_with_linux(self): | ||
| """Loop through loaded libraries and return binders on supported ones | ||
|
|
||
| Uses a Linux-specific mechanism: | ||
| https://man7.org/linux/man-pages/man5/proc_pid_maps.5.html | ||
| """ | ||
| with open("/proc/self/maps") as f: | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you probably want to open in
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This matches previous behavior I think. And to be fair one could do better, but... not sure how one would know the actual encoding. And also in practice probably no one ever does that? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. UNIX paths don’t have any encoding, so just leaving everything as bytes should be fine. But also if it’s a preexisting issue it’s no biggie. |
||
| maps = f.read() | ||
| filepaths = set() | ||
| for line in maps.splitlines(): | ||
| start_index = line.find("/") | ||
| if start_index == -1 or ".so" not in line: | ||
| continue | ||
| filepath = line[start_index:] | ||
| if os.path.exists(filepath): | ||
| filepaths.add(filepath) | ||
|
|
||
| for filepath in filepaths: | ||
| self._make_controller_from_path(filepath) | ||
|
|
||
| def _find_libraries_with_python(self): | ||
| """Loop through loaded libraries and return binders on supported ones | ||
|
|
||
| Uses Python's built-in support for this functionality. | ||
| """ | ||
| assert dllist is not None | ||
| filepaths = dllist() | ||
| if filepaths and filepaths[0] in ("", sys.executable): | ||
| filepaths = filepaths[1:] | ||
| for filepath in filepaths: | ||
| self._make_controller_from_path(filepath) | ||
|
|
||
| def _find_libraries_with_dl_iterate_phdr(self): | ||
| """Loop through loaded libraries and return binders on supported ones | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.