Skip to content

Commit

Permalink
pythongh-120837: Update _Py_DumpExtensionModules to be async-signal-safe
Browse files Browse the repository at this point in the history
  • Loading branch information
corona10 committed Jun 26, 2024
1 parent 44eafd6 commit 8430508
Showing 1 changed file with 76 additions and 40 deletions.
116 changes: 76 additions & 40 deletions Python/pylifecycle.c
Original file line number Diff line number Diff line change
Expand Up @@ -2897,6 +2897,30 @@ 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;
}
return -1;
#else
return 0;
#endif
}

static inline void
release_dict_lock_for_dump(PyObject *obj) {
#ifdef Py_GIL_DISABLED
PyMutex *mutex = &obj->ob_mutex;
uint8_t expected = _Py_UNLOCKED;
// Do not wake up other threads.
_Py_atomic_compare_exchange_uint8(&mutex->_bits, &expected, _Py_UNLOCKED);
#else
return;
#endif
}

// Dump the list of extension modules of sys.modules, excluding stdlib modules
// (sys.stdlib_module_names), into fd file descriptor.
Expand Down Expand Up @@ -2924,12 +2948,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,
Expand All @@ -2942,46 +2972,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) {
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) {
Expand Down

0 comments on commit 8430508

Please sign in to comment.