summaryrefslogtreecommitdiffstats
path: root/Include
diff options
context:
space:
mode:
authorEric Snow <ericsnowcurrently@gmail.com>2023-07-28 23:16:12 (GMT)
committerGitHub <noreply@github.com>2023-07-28 23:16:12 (GMT)
commitda151fdc7ac4a6d30740e4ef18071936a136790d (patch)
tree539f4fca2d647e02d9efeb9ddac8006c83c8f82a /Include
parente5ca2aa2c6d86842183565606afcd0f85ed3eac9 (diff)
downloadcpython-da151fdc7ac4a6d30740e4ef18071936a136790d.zip
cpython-da151fdc7ac4a6d30740e4ef18071936a136790d.tar.gz
cpython-da151fdc7ac4a6d30740e4ef18071936a136790d.tar.bz2
[3.12] gh-105699: Use a _Py_hashtable_t for the PyModuleDef Cache (gh-106974) (gh-107412)
gh-105699: Use a _Py_hashtable_t for the PyModuleDef Cache (gh-106974) This fixes a crasher due to a race condition, triggered infrequently when two isolated (own GIL) subinterpreters simultaneously initialize their sys or builtins modules. The crash happened due the combination of the "detached" thread state we were using and the "last holder" logic we use for the GIL. It turns out it's tricky to use the same thread state for different threads. Who could have guessed? We solve the problem by eliminating the one object we were still sharing between interpreters. We replace it with a low-level hashtable, using the "raw" allocator to avoid tying it to the main interpreter. We also remove the accommodations for "detached" thread states, which were a dubious idea to start with. (cherry picked from commit 8ba4df91ae60833723d8d3b9afeb2b642f7176d5)
Diffstat (limited to 'Include')
-rw-r--r--Include/internal/pycore_import.h13
-rw-r--r--Include/internal/pycore_pystate.h5
-rw-r--r--Include/internal/pycore_runtime_init.h5
3 files changed, 6 insertions, 17 deletions
diff --git a/Include/internal/pycore_import.h b/Include/internal/pycore_import.h
index 0a9f24e..376957b 100644
--- a/Include/internal/pycore_import.h
+++ b/Include/internal/pycore_import.h
@@ -5,6 +5,9 @@
extern "C" {
#endif
+#include "pycore_hashtable.h" // _Py_hashtable_t
+#include "pycore_time.h" // _PyTime_t
+
struct _import_runtime_state {
/* The builtin modules (defined in config.c). */
@@ -15,19 +18,15 @@ struct _import_runtime_state {
See PyInterpreterState.modules_by_index for more info. */
Py_ssize_t last_module_index;
struct {
- /* A thread state tied to the main interpreter,
- used exclusively for when the extensions dict is access/modified
- from an arbitrary thread. */
- PyThreadState main_tstate;
- /* A lock to guard the dict. */
+ /* A lock to guard the cache. */
PyThread_type_lock mutex;
- /* A dict mapping (filename, name) to PyModuleDef for modules.
+ /* The actual cache of (filename, name, PyModuleDef) for modules.
Only legacy (single-phase init) extension modules are added
and only if they support multiple initialization (m_size >- 0)
or are imported in the main interpreter.
This is initialized lazily in _PyImport_FixupExtensionObject().
Modules are added there and looked up in _imp.find_extension(). */
- PyObject *dict;
+ _Py_hashtable_t *hashtable;
} extensions;
/* Package context -- the full module name for package imports */
const char * pkgcontext;
diff --git a/Include/internal/pycore_pystate.h b/Include/internal/pycore_pystate.h
index 43652c4..ccfc258 100644
--- a/Include/internal/pycore_pystate.h
+++ b/Include/internal/pycore_pystate.h
@@ -128,11 +128,6 @@ PyAPI_FUNC(void) _PyThreadState_Init(
PyThreadState *tstate);
PyAPI_FUNC(void) _PyThreadState_DeleteExcept(PyThreadState *tstate);
-extern void _PyThreadState_InitDetached(PyThreadState *, PyInterpreterState *);
-extern void _PyThreadState_ClearDetached(PyThreadState *);
-extern void _PyThreadState_BindDetached(PyThreadState *);
-extern void _PyThreadState_UnbindDetached(PyThreadState *);
-
/* Other */
diff --git a/Include/internal/pycore_runtime_init.h b/Include/internal/pycore_runtime_init.h
index b507de0..4130188 100644
--- a/Include/internal/pycore_runtime_init.h
+++ b/Include/internal/pycore_runtime_init.h
@@ -41,11 +41,6 @@ extern PyTypeObject _PyExc_MemoryError;
in accordance with the specification. */ \
.autoTSSkey = Py_tss_NEEDS_INIT, \
.parser = _parser_runtime_state_INIT, \
- .imports = { \
- .extensions = { \
- .main_tstate = _PyThreadState_INIT, \
- }, \
- }, \
.ceval = { \
.perf = _PyEval_RUNTIME_PERF_INIT, \
}, \