Skip to content

Commit d5441f6

Browse files
[3.13] gh-120837: Update _Py_DumpExtensionModules to be async-signal-safe (gh-121051) (gh-121107)
gh-120837: Update _Py_DumpExtensionModules to be async-signal-safe (gh-121051) (cherry picked from commit 1a2e7a7) Co-authored-by: Donghee Na <[email protected]>
1 parent 49a01d6 commit d5441f6

File tree

1 file changed

+36
-2
lines changed

1 file changed

+36
-2
lines changed

Python/pylifecycle.c

+36-2
Original file line numberDiff line numberDiff line change
@@ -3036,6 +3036,30 @@ fatal_error_exit(int status)
30363036
}
30373037
}
30383038

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

30403064
// Dump the list of extension modules of sys.modules, excluding stdlib modules
30413065
// (sys.stdlib_module_names), into fd file descriptor.
@@ -3063,13 +3087,18 @@ _Py_DumpExtensionModules(int fd, PyInterpreterState *interp)
30633087
PyObject *stdlib_module_names = NULL;
30643088
if (interp->sysdict != NULL) {
30653089
pos = 0;
3066-
while (PyDict_Next(interp->sysdict, &pos, &key, &value)) {
3090+
if (!acquire_dict_lock_for_dump(interp->sysdict)) {
3091+
// If we cannot acquire the lock, just don't dump the list of extension modules.
3092+
return;
3093+
}
3094+
while (_PyDict_Next(interp->sysdict, &pos, &key, &value, NULL)) {
30673095
if (PyUnicode_Check(key)
30683096
&& PyUnicode_CompareWithASCIIString(key, "stdlib_module_names") == 0) {
30693097
stdlib_module_names = value;
30703098
break;
30713099
}
30723100
}
3101+
release_dict_lock_for_dump(interp->sysdict);
30733102
}
30743103
// If we failed to get sys.stdlib_module_names or it's not a frozenset,
30753104
// don't exclude stdlib modules.
@@ -3081,7 +3110,11 @@ _Py_DumpExtensionModules(int fd, PyInterpreterState *interp)
30813110
int header = 1;
30823111
Py_ssize_t count = 0;
30833112
pos = 0;
3084-
while (PyDict_Next(modules, &pos, &key, &value)) {
3113+
if (!acquire_dict_lock_for_dump(modules)) {
3114+
// If we cannot acquire the lock, just don't dump the list of extension modules.
3115+
return;
3116+
}
3117+
while (_PyDict_Next(modules, &pos, &key, &value, NULL)) {
30853118
if (!PyUnicode_Check(key)) {
30863119
continue;
30873120
}
@@ -3122,6 +3155,7 @@ _Py_DumpExtensionModules(int fd, PyInterpreterState *interp)
31223155
_Py_DumpASCII(fd, key);
31233156
count++;
31243157
}
3158+
release_dict_lock_for_dump(modules);
31253159

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

0 commit comments

Comments
 (0)