summaryrefslogtreecommitdiffstats
path: root/Python
diff options
context:
space:
mode:
authorDonghee Na <donghee.na@python.org>2024-06-27 21:46:46 (GMT)
committerGitHub <noreply@github.com>2024-06-27 21:46:46 (GMT)
commit1a2e7a747540f74414e7c50556bcb2cc127e9d1c (patch)
tree2c72cc114b1195a92c5b9b51894d3bf024b3b136 /Python
parent237baf4d7a789deb153fbc1fc3863550949d5da2 (diff)
downloadcpython-1a2e7a747540f74414e7c50556bcb2cc127e9d1c.zip
cpython-1a2e7a747540f74414e7c50556bcb2cc127e9d1c.tar.gz
cpython-1a2e7a747540f74414e7c50556bcb2cc127e9d1c.tar.bz2
gh-120837: Update _Py_DumpExtensionModules to be async-signal-safe (gh-121051)
Diffstat (limited to 'Python')
-rw-r--r--Python/pylifecycle.c38
1 files changed, 36 insertions, 2 deletions
diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c
index 9bbfa83..39eaa86 100644
--- a/Python/pylifecycle.c
+++ b/Python/pylifecycle.c
@@ -3035,6 +3035,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 1;
+ }
+ return 0;
+#else
+ return 1;
+#endif
+}
+
+static inline void
+release_dict_lock_for_dump(PyObject *obj)
+{
+#ifdef Py_GIL_DISABLED
+ PyMutex *mutex = &obj->ob_mutex;
+ // 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 atomic store in here.
+ _Py_atomic_store_uint8(&mutex->_bits, _Py_UNLOCKED);
+#endif
+}
// Dump the list of extension modules of sys.modules, excluding stdlib modules
// (sys.stdlib_module_names), into fd file descriptor.
@@ -3062,13 +3086,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 (!acquire_dict_lock_for_dump(interp->sysdict)) {
+ // If we cannot acquire the lock, just don't dump the list of extension modules.
+ return;
+ }
+ 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);
}
// If we failed to get sys.stdlib_module_names or it's not a frozenset,
// don't exclude stdlib modules.
@@ -3080,7 +3109,11 @@ _Py_DumpExtensionModules(int fd, PyInterpreterState *interp)
int header = 1;
Py_ssize_t count = 0;
pos = 0;
- while (PyDict_Next(modules, &pos, &key, &value)) {
+ if (!acquire_dict_lock_for_dump(modules)) {
+ // If we cannot acquire the lock, just don't dump the list of extension modules.
+ return;
+ }
+ while (_PyDict_Next(modules, &pos, &key, &value, NULL)) {
if (!PyUnicode_Check(key)) {
continue;
}
@@ -3121,6 +3154,7 @@ _Py_DumpExtensionModules(int fd, PyInterpreterState *interp)
_Py_DumpASCII(fd, key);
count++;
}
+ release_dict_lock_for_dump(modules);
if (count) {
PUTS(fd, " (total: ");