-
-
Notifications
You must be signed in to change notification settings - Fork 32k
gh-120837: Update _Py_DumpExtensionModules to be async-signal-safe #121051
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
Changes from 4 commits
8430508
07962e5
1f56fcc
e7f24af
ed9bb3b
136e8d1
61de424
2d31780
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 |
---|---|---|
|
@@ -2897,6 +2897,31 @@ fatal_error_exit(int status) | |
} | ||
} | ||
|
||
static inline int | ||
acquire_dict_lock_for_dump(PyObject *obj) { | ||
#ifdef Py_GIL_DISABLED | ||
PyMutex *mutex = &obj->ob_mutex; | ||
if (_PyMutex_LockTimed(mutex, 0, 0) == PY_LOCK_ACQUIRED) { | ||
return 0; | ||
colesbury marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
return -1; | ||
#else | ||
return 0; | ||
#endif | ||
} | ||
|
||
static inline void | ||
release_dict_lock_for_dump(PyObject *obj) { | ||
colesbury marked this conversation as resolved.
Show resolved
Hide resolved
|
||
#ifdef Py_GIL_DISABLED | ||
PyMutex *mutex = &obj->ob_mutex; | ||
uint8_t expected = _Py_LOCKED; | ||
// We can not call PyMutex_Unlock because it's not async-signal-safe. | ||
// So not to wake up other threads, we just use a simple CAS in here. | ||
_Py_atomic_compare_exchange_uint8(&mutex->_bits, &expected, _Py_UNLOCKED); | ||
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. Do we have to run for loop to prevent CAS failure? 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 this should be a |
||
#else | ||
return; | ||
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. The 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. Done! |
||
#endif | ||
} | ||
|
||
// Dump the list of extension modules of sys.modules, excluding stdlib modules | ||
// (sys.stdlib_module_names), into fd file descriptor. | ||
|
@@ -2924,12 +2949,18 @@ _Py_DumpExtensionModules(int fd, PyInterpreterState *interp) | |
PyObject *stdlib_module_names = NULL; | ||
if (interp->sysdict != NULL) { | ||
pos = 0; | ||
while (PyDict_Next(interp->sysdict, &pos, &key, &value)) { | ||
if (PyUnicode_Check(key) | ||
&& PyUnicode_CompareWithASCIIString(key, "stdlib_module_names") == 0) { | ||
stdlib_module_names = value; | ||
break; | ||
if (acquire_dict_lock_for_dump(interp->sysdict) == 0) { | ||
while (_PyDict_Next(interp->sysdict, &pos, &key, &value, NULL)) { | ||
if (PyUnicode_Check(key) | ||
&& PyUnicode_CompareWithASCIIString(key, "stdlib_module_names") == 0) { | ||
stdlib_module_names = value; | ||
break; | ||
} | ||
} | ||
release_dict_lock_for_dump(interp->sysdict); | ||
} | ||
else { | ||
return; | ||
} | ||
} | ||
// If we failed to get sys.stdlib_module_names or it's not a frozenset, | ||
|
@@ -2942,46 +2973,52 @@ _Py_DumpExtensionModules(int fd, PyInterpreterState *interp) | |
int header = 1; | ||
Py_ssize_t count = 0; | ||
pos = 0; | ||
while (PyDict_Next(modules, &pos, &key, &value)) { | ||
if (!PyUnicode_Check(key)) { | ||
continue; | ||
} | ||
if (!_PyModule_IsExtension(value)) { | ||
continue; | ||
} | ||
// Use the module name from the sys.modules key, | ||
// don't attempt to get the module object name. | ||
if (stdlib_module_names != NULL) { | ||
int is_stdlib_ext = 0; | ||
|
||
Py_ssize_t i = 0; | ||
PyObject *item; | ||
Py_hash_t hash; | ||
// if stdlib_module_names is not NULL, it is always a frozenset. | ||
while (_PySet_NextEntry(stdlib_module_names, &i, &item, &hash)) { | ||
if (PyUnicode_Check(item) | ||
&& PyUnicode_Compare(key, item) == 0) | ||
{ | ||
is_stdlib_ext = 1; | ||
break; | ||
} | ||
if (acquire_dict_lock_for_dump(modules) == 0) { | ||
corona10 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
while (_PyDict_Next(modules, &pos, &key, &value, NULL)) { | ||
if (!PyUnicode_Check(key)) { | ||
continue; | ||
} | ||
if (is_stdlib_ext) { | ||
// Ignore stdlib extension | ||
if (!_PyModule_IsExtension(value)) { | ||
continue; | ||
} | ||
} | ||
// Use the module name from the sys.modules key, | ||
// don't attempt to get the module object name. | ||
if (stdlib_module_names != NULL) { | ||
int is_stdlib_ext = 0; | ||
|
||
Py_ssize_t i = 0; | ||
PyObject *item; | ||
Py_hash_t hash; | ||
// if stdlib_module_names is not NULL, it is always a frozenset. | ||
while (_PySet_NextEntry(stdlib_module_names, &i, &item, &hash)) { | ||
if (PyUnicode_Check(item) | ||
&& PyUnicode_Compare(key, item) == 0) | ||
{ | ||
is_stdlib_ext = 1; | ||
break; | ||
} | ||
} | ||
if (is_stdlib_ext) { | ||
// Ignore stdlib extension | ||
continue; | ||
} | ||
} | ||
|
||
if (header) { | ||
PUTS(fd, "\nExtension modules: "); | ||
header = 0; | ||
} | ||
else { | ||
PUTS(fd, ", "); | ||
} | ||
if (header) { | ||
PUTS(fd, "\nExtension modules: "); | ||
header = 0; | ||
} | ||
else { | ||
PUTS(fd, ", "); | ||
} | ||
|
||
_Py_DumpASCII(fd, key); | ||
count++; | ||
_Py_DumpASCII(fd, key); | ||
count++; | ||
} | ||
release_dict_lock_for_dump(modules); | ||
} | ||
else { | ||
return; | ||
} | ||
|
||
if (count) { | ||
|
Uh oh!
There was an error while loading. Please reload this page.