mirror of
https://github.com/python/cpython.git
synced 2025-08-14 13:59:20 +00:00
[3.12] gh-105699: Use a Thread-Local Variable for PKGCONTEXT (gh-105740) (gh-105765)
This fixes a race during import. The existing _PyRuntimeState.imports.pkgcontext is shared between interpreters, and occasionally this would cause a crash when multiple interpreters were importing extensions modules at the same time. To solve this we add a thread-local variable for the value. We also leave the existing state (and infrequent race) in place for platforms that do not support thread-local variables.
(cherry picked from commit b87d288275
)
Co-authored-by: Eric Snow <ericsnowcurrently@gmail.com>
This commit is contained in:
parent
26bc2cc061
commit
bc997b38b6
4 changed files with 24 additions and 1 deletions
|
@ -703,10 +703,19 @@ _PyImport_ClearModulesByIndex(PyInterpreterState *interp)
|
||||||
_PyRuntime.imports.pkgcontext, and PyModule_Create*() will
|
_PyRuntime.imports.pkgcontext, and PyModule_Create*() will
|
||||||
substitute this (if the name actually matches).
|
substitute this (if the name actually matches).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_THREAD_LOCAL
|
||||||
|
_Py_thread_local const char *pkgcontext = NULL;
|
||||||
|
# undef PKGCONTEXT
|
||||||
|
# define PKGCONTEXT pkgcontext
|
||||||
|
#endif
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
_PyImport_ResolveNameWithPackageContext(const char *name)
|
_PyImport_ResolveNameWithPackageContext(const char *name)
|
||||||
{
|
{
|
||||||
|
#ifndef HAVE_THREAD_LOCAL
|
||||||
PyThread_acquire_lock(EXTENSIONS.mutex, WAIT_LOCK);
|
PyThread_acquire_lock(EXTENSIONS.mutex, WAIT_LOCK);
|
||||||
|
#endif
|
||||||
if (PKGCONTEXT != NULL) {
|
if (PKGCONTEXT != NULL) {
|
||||||
const char *p = strrchr(PKGCONTEXT, '.');
|
const char *p = strrchr(PKGCONTEXT, '.');
|
||||||
if (p != NULL && strcmp(name, p+1) == 0) {
|
if (p != NULL && strcmp(name, p+1) == 0) {
|
||||||
|
@ -714,17 +723,23 @@ _PyImport_ResolveNameWithPackageContext(const char *name)
|
||||||
PKGCONTEXT = NULL;
|
PKGCONTEXT = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#ifndef HAVE_THREAD_LOCAL
|
||||||
PyThread_release_lock(EXTENSIONS.mutex);
|
PyThread_release_lock(EXTENSIONS.mutex);
|
||||||
|
#endif
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
_PyImport_SwapPackageContext(const char *newcontext)
|
_PyImport_SwapPackageContext(const char *newcontext)
|
||||||
{
|
{
|
||||||
|
#ifndef HAVE_THREAD_LOCAL
|
||||||
PyThread_acquire_lock(EXTENSIONS.mutex, WAIT_LOCK);
|
PyThread_acquire_lock(EXTENSIONS.mutex, WAIT_LOCK);
|
||||||
|
#endif
|
||||||
const char *oldcontext = PKGCONTEXT;
|
const char *oldcontext = PKGCONTEXT;
|
||||||
PKGCONTEXT = newcontext;
|
PKGCONTEXT = newcontext;
|
||||||
|
#ifndef HAVE_THREAD_LOCAL
|
||||||
PyThread_release_lock(EXTENSIONS.mutex);
|
PyThread_release_lock(EXTENSIONS.mutex);
|
||||||
|
#endif
|
||||||
return oldcontext;
|
return oldcontext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,6 +58,7 @@ _KEYWORD = textwrap.dedent(r'''
|
||||||
extern |
|
extern |
|
||||||
register |
|
register |
|
||||||
static |
|
static |
|
||||||
|
_Thread_local |
|
||||||
typedef |
|
typedef |
|
||||||
|
|
||||||
const |
|
const |
|
||||||
|
@ -137,7 +138,7 @@ COMPOUND_TYPE_KIND = r'(?: \b (?: struct | union | enum ) \b )'
|
||||||
#######################################
|
#######################################
|
||||||
# variable declarations
|
# variable declarations
|
||||||
|
|
||||||
_STORAGE = 'auto register static extern'.split()
|
_STORAGE = 'auto register static extern _Thread_local'.split()
|
||||||
STORAGE_CLASS = rf'(?: \b (?: {" | ".join(_STORAGE)} ) \b )'
|
STORAGE_CLASS = rf'(?: \b (?: {" | ".join(_STORAGE)} ) \b )'
|
||||||
TYPE_QUALIFIER = r'(?: \b (?: const | volatile ) \b )'
|
TYPE_QUALIFIER = r'(?: \b (?: const | volatile ) \b )'
|
||||||
PTR_QUALIFIER = rf'(?: [*] (?: \s* {TYPE_QUALIFIER} )? )'
|
PTR_QUALIFIER = rf'(?: [*] (?: \s* {TYPE_QUALIFIER} )? )'
|
||||||
|
|
|
@ -219,6 +219,7 @@ def _strip_directives(line, partial=0):
|
||||||
line = line[m.end():]
|
line = line[m.end():]
|
||||||
|
|
||||||
line = re.sub(r'__extension__', '', line)
|
line = re.sub(r'__extension__', '', line)
|
||||||
|
line = re.sub(r'__thread\b', '_Thread_local', line)
|
||||||
|
|
||||||
while (m := COMPILER_DIRECTIVE_RE.match(line)):
|
while (m := COMPILER_DIRECTIVE_RE.match(line)):
|
||||||
before, _, _, closed = m.groups()
|
before, _, _, closed = m.groups()
|
||||||
|
|
|
@ -168,6 +168,12 @@ Modules/_xxinterpchannelsmodule.c - _globals -
|
||||||
|
|
||||||
Python/pyfpe.c - PyFPE_counter -
|
Python/pyfpe.c - PyFPE_counter -
|
||||||
|
|
||||||
|
##-----------------------
|
||||||
|
## thread-local variables
|
||||||
|
|
||||||
|
Python/import.c - pkgcontext -
|
||||||
|
Python/pystate.c - _Py_tss_tstate -
|
||||||
|
|
||||||
##-----------------------
|
##-----------------------
|
||||||
## should be const
|
## should be const
|
||||||
# XXX Make them const.
|
# XXX Make them const.
|
||||||
|
|
Can't render this file because it has a wrong number of fields in line 4.
|
Loading…
Add table
Add a link
Reference in a new issue