Skip to content

Commit 1a2e7a7

Browse files
authored
gh-120837: Update _Py_DumpExtensionModules to be async-signal-safe (gh-121051)
1 parent 237baf4 commit 1a2e7a7

File tree

1 file changed

+36
-2
lines changed

1 file changed

+36
-2
lines changed

Python/pylifecycle.c

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3035,6 +3035,30 @@ fatal_error_exit(int status)
30353035
}
30363036
}
30373037

3038+
static inline int
3039+
acquire_dict_lock_for_dump(PyObject *obj)
3040+
{
3041+
#ifdef Py_GIL_DISABLED
3042+
PyMutex *mutex = &obj->ob_mutex;
3043+
if (_PyMutex_LockTimed(mutex, 0, 0) == PY_LOCK_ACQUIRED) {
3044+
return 1;
3045+
}
3046+
return 0;
3047+
#else
3048+
return 1;
3049+
#endif
3050+
}
3051+
3052+
static inline void
3053+
release_dict_lock_for_dump(PyObject *obj)
3054+
{
3055+
#ifdef Py_GIL_DISABLED
3056+
PyMutex *mutex = &obj->ob_mutex;
3057+
// We can not call PyMutex_Unlock because it's not async-signal-safe.
3058+
// So not to wake up other threads, we just use a simple atomic store in here.
3059+
_Py_atomic_store_uint8(&mutex->_bits, _Py_UNLOCKED);
3060+
#endif
3061+
}
30383062

30393063
// Dump the list of extension modules of sys.modules, excluding stdlib modules
30403064
// (sys.stdlib_module_names), into fd file descriptor.
@@ -3062,13 +3086,18 @@ _Py_DumpExtensionModules(int fd, PyInterpreterState *interp)
30623086
PyObject *stdlib_module_names = NULL;
30633087
if (interp->sysdict != NULL) {
30643088
pos = 0;
3065-
while (PyDict_Next(interp->sysdict, &pos, &key, &value)) {
3089+
if (!acquire_dict_lock_for_dump(interp->sysdict)) {
3090+
// If we cannot acquire the lock, just don't dump the list of extension modules.
3091+
return;
3092+
}
3093+
while (_PyDict_Next(interp->sysdict, &pos, &key, &value, NULL)) {
30663094
if (PyUnicode_Check(key)
30673095
&& PyUnicode_CompareWithASCIIString(key, "stdlib_module_names") == 0) {
30683096
stdlib_module_names = value;
30693097
break;
30703098
}
30713099
}
3100+
release_dict_lock_for_dump(interp->sysdict);
30723101
}
30733102
// If we failed to get sys.stdlib_module_names or it's not a frozenset,
30743103
// don't exclude stdlib modules.
@@ -3080,7 +3109,11 @@ _Py_DumpExtensionModules(int fd, PyInterpreterState *interp)
30803109
int header = 1;
30813110
Py_ssize_t count = 0;
30823111
pos = 0;
3083-
while (PyDict_Next(modules, &pos, &key, &value)) {
3112+
if (!acquire_dict_lock_for_dump(modules)) {
3113+
// If we cannot acquire the lock, just don't dump the list of extension modules.
3114+
return;
3115+
}
3116+
while (_PyDict_Next(modules, &pos, &key, &value, NULL)) {
30843117
if (!PyUnicode_Check(key)) {
30853118
continue;
30863119
}
@@ -3121,6 +3154,7 @@ _Py_DumpExtensionModules(int fd, PyInterpreterState *interp)
31213154
_Py_DumpASCII(fd, key);
31223155
count++;
31233156
}
3157+
release_dict_lock_for_dump(modules);
31243158

31253159
if (count) {
31263160
PUTS(fd, " (total: ");

0 commit comments

Comments
 (0)