Skip to content

Commit b7a5dcf

Browse files
Move the import lock to PyInterpreterState.
1 parent b2fc549 commit b7a5dcf

File tree

5 files changed

+70
-60
lines changed

5 files changed

+70
-60
lines changed

Include/cpython/import.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ PyAPI_FUNC(PyObject *) _PyImport_GetModuleId(_Py_Identifier *name);
1010
PyAPI_FUNC(int) _PyImport_SetModule(PyObject *name, PyObject *module);
1111
PyAPI_FUNC(int) _PyImport_SetModuleString(const char *name, PyObject* module);
1212

13-
PyAPI_FUNC(void) _PyImport_AcquireLock(void);
14-
PyAPI_FUNC(int) _PyImport_ReleaseLock(void);
13+
PyAPI_FUNC(void) _PyImport_AcquireLock(PyInterpreterState *interp);
14+
PyAPI_FUNC(int) _PyImport_ReleaseLock(PyInterpreterState *interp);
1515

1616
PyAPI_FUNC(int) _PyImport_FixupBuiltin(
1717
PyObject *mod,

Include/internal/pycore_import.h

+12-8
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,6 @@ struct _import_runtime_state {
2121
This is initialized lazily in _PyImport_FixupExtensionObject().
2222
Modules are added there and looked up in _imp.find_extension(). */
2323
PyObject *extensions;
24-
/* The global import lock. */
25-
struct {
26-
PyThread_type_lock mutex;
27-
unsigned long thread;
28-
int level;
29-
} lock;
3024
struct {
3125
int import_level;
3226
_PyTime_t accumulated;
@@ -68,6 +62,12 @@ struct _import_state {
6862
int dlopenflags;
6963
#endif
7064
PyObject *import_func;
65+
/* The global import lock. */
66+
struct {
67+
PyThread_type_lock mutex;
68+
unsigned long thread;
69+
int level;
70+
} lock;
7171
};
7272

7373
#ifdef HAVE_DLOPEN
@@ -85,8 +85,12 @@ struct _import_state {
8585

8686
#define IMPORTS_INIT \
8787
{ \
88-
.override_frozen_modules = 0, \
8988
DLOPENFLAGS_INIT \
89+
.lock = { \
90+
.mutex = NULL, \
91+
.thread = PYTHREAD_INVALID_THREAD_ID, \
92+
.level = 0, \
93+
}, \
9094
}
9195

9296
extern void _PyImport_ClearCore(PyInterpreterState *interp);
@@ -137,7 +141,7 @@ extern void _PyImport_FiniExternal(PyInterpreterState *interp);
137141

138142

139143
#ifdef HAVE_FORK
140-
extern PyStatus _PyImport_ReInitLock(void);
144+
extern PyStatus _PyImport_ReInitLock(PyInterpreterState *interp);
141145
#endif
142146

143147

Include/internal/pycore_runtime_init.h

-5
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,6 @@ extern "C" {
3838
.autoTSSkey = Py_tss_NEEDS_INIT, \
3939
.parser = _parser_runtime_state_INIT, \
4040
.imports = { \
41-
.lock = { \
42-
.mutex = NULL, \
43-
.thread = PYTHREAD_INVALID_THREAD_ID, \
44-
.level = 0, \
45-
}, \
4641
.find_and_load = { \
4742
.header = 1, \
4843
}, \

Modules/posixmodule.c

+8-5
Original file line numberDiff line numberDiff line change
@@ -568,18 +568,21 @@ run_at_forkers(PyObject *lst, int reverse)
568568
void
569569
PyOS_BeforeFork(void)
570570
{
571-
run_at_forkers(_PyInterpreterState_GET()->before_forkers, 1);
571+
PyInterpreterState *interp = _PyInterpreterState_GET();
572+
run_at_forkers(interp->before_forkers, 1);
572573

573-
_PyImport_AcquireLock();
574+
_PyImport_AcquireLock(interp);
574575
}
575576

576577
void
577578
PyOS_AfterFork_Parent(void)
578579
{
579-
if (_PyImport_ReleaseLock() <= 0)
580+
PyInterpreterState *interp = _PyInterpreterState_GET();
581+
if (_PyImport_ReleaseLock(interp) <= 0) {
580582
Py_FatalError("failed releasing import lock after fork");
583+
}
581584

582-
run_at_forkers(_PyInterpreterState_GET()->after_forkers_parent, 0);
585+
run_at_forkers(interp->after_forkers_parent, 0);
583586
}
584587

585588
void
@@ -605,7 +608,7 @@ PyOS_AfterFork_Child(void)
605608
goto fatal_error;
606609
}
607610

608-
status = _PyImport_ReInitLock();
611+
status = _PyImport_ReInitLock(tstate->interp);
609612
if (_PyStatus_EXCEPTION(status)) {
610613
goto fatal_error;
611614
}

Python/import.c

+48-40
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,6 @@ static struct _inittab *inittab_copy = NULL;
5656
#define LAST_MODULE_INDEX _PyRuntime.imports.last_module_index
5757
#define EXTENSIONS _PyRuntime.imports.extensions
5858

59-
#define import_lock _PyRuntime.imports.lock.mutex
60-
#define import_lock_thread _PyRuntime.imports.lock.thread
61-
#define import_lock_level _PyRuntime.imports.lock.level
62-
6359
#define FIND_AND_LOAD _PyRuntime.imports.find_and_load
6460
#define PKGCONTEXT (_PyRuntime.imports.pkgcontext)
6561

@@ -83,6 +79,13 @@ static struct _inittab *inittab_copy = NULL;
8379
#define IMPORT_FUNC(interp) \
8480
(interp)->imports.import_func
8581

82+
#define IMPORT_LOCK(interp) \
83+
(interp)->imports.lock.mutex
84+
#define IMPORT_LOCK_THREAD(interp) \
85+
(interp)->imports.lock.thread
86+
#define IMPORT_LOCK_LEVEL(interp) \
87+
(interp)->imports.lock.level
88+
8689

8790
/*******************/
8891
/* the import lock */
@@ -93,45 +96,45 @@ static struct _inittab *inittab_copy = NULL;
9396
These calls are serialized by the global interpreter lock. */
9497

9598
void
96-
_PyImport_AcquireLock(void)
99+
_PyImport_AcquireLock(PyInterpreterState *interp)
97100
{
98101
unsigned long me = PyThread_get_thread_ident();
99102
if (me == PYTHREAD_INVALID_THREAD_ID)
100103
return; /* Too bad */
101-
if (import_lock == NULL) {
102-
import_lock = PyThread_allocate_lock();
103-
if (import_lock == NULL)
104+
if (IMPORT_LOCK(interp) == NULL) {
105+
IMPORT_LOCK(interp) = PyThread_allocate_lock();
106+
if (IMPORT_LOCK(interp) == NULL)
104107
return; /* Nothing much we can do. */
105108
}
106-
if (import_lock_thread == me) {
107-
import_lock_level++;
109+
if (IMPORT_LOCK_THREAD(interp) == me) {
110+
IMPORT_LOCK_LEVEL(interp)++;
108111
return;
109112
}
110-
if (import_lock_thread != PYTHREAD_INVALID_THREAD_ID ||
111-
!PyThread_acquire_lock(import_lock, 0))
113+
if (IMPORT_LOCK_THREAD(interp) != PYTHREAD_INVALID_THREAD_ID ||
114+
!PyThread_acquire_lock(IMPORT_LOCK(interp), 0))
112115
{
113116
PyThreadState *tstate = PyEval_SaveThread();
114-
PyThread_acquire_lock(import_lock, WAIT_LOCK);
117+
PyThread_acquire_lock(IMPORT_LOCK(interp), WAIT_LOCK);
115118
PyEval_RestoreThread(tstate);
116119
}
117-
assert(import_lock_level == 0);
118-
import_lock_thread = me;
119-
import_lock_level = 1;
120+
assert(IMPORT_LOCK_LEVEL(interp) == 0);
121+
IMPORT_LOCK_THREAD(interp) = me;
122+
IMPORT_LOCK_LEVEL(interp) = 1;
120123
}
121124

122125
int
123-
_PyImport_ReleaseLock(void)
126+
_PyImport_ReleaseLock(PyInterpreterState *interp)
124127
{
125128
unsigned long me = PyThread_get_thread_ident();
126-
if (me == PYTHREAD_INVALID_THREAD_ID || import_lock == NULL)
129+
if (me == PYTHREAD_INVALID_THREAD_ID || IMPORT_LOCK(interp) == NULL)
127130
return 0; /* Too bad */
128-
if (import_lock_thread != me)
131+
if (IMPORT_LOCK_THREAD(interp) != me)
129132
return -1;
130-
import_lock_level--;
131-
assert(import_lock_level >= 0);
132-
if (import_lock_level == 0) {
133-
import_lock_thread = PYTHREAD_INVALID_THREAD_ID;
134-
PyThread_release_lock(import_lock);
133+
IMPORT_LOCK_LEVEL(interp)--;
134+
assert(IMPORT_LOCK_LEVEL(interp) >= 0);
135+
if (IMPORT_LOCK_LEVEL(interp) == 0) {
136+
IMPORT_LOCK_THREAD(interp) = PYTHREAD_INVALID_THREAD_ID;
137+
PyThread_release_lock(IMPORT_LOCK(interp));
135138
}
136139
return 1;
137140
}
@@ -142,23 +145,23 @@ _PyImport_ReleaseLock(void)
142145
We now acquire the import lock around fork() calls but on some platforms
143146
(Solaris 9 and earlier? see isue7242) that still left us with problems. */
144147
PyStatus
145-
_PyImport_ReInitLock(void)
148+
_PyImport_ReInitLock(PyInterpreterState *interp)
146149
{
147-
if (import_lock != NULL) {
148-
if (_PyThread_at_fork_reinit(&import_lock) < 0) {
150+
if (IMPORT_LOCK(interp) != NULL) {
151+
if (_PyThread_at_fork_reinit(&IMPORT_LOCK(interp)) < 0) {
149152
return _PyStatus_ERR("failed to create a new lock");
150153
}
151154
}
152155

153-
if (import_lock_level > 1) {
156+
if (IMPORT_LOCK_LEVEL(interp) > 1) {
154157
/* Forked as a side effect of import */
155158
unsigned long me = PyThread_get_thread_ident();
156-
PyThread_acquire_lock(import_lock, WAIT_LOCK);
157-
import_lock_thread = me;
158-
import_lock_level--;
159+
PyThread_acquire_lock(IMPORT_LOCK(interp), WAIT_LOCK);
160+
IMPORT_LOCK_THREAD(interp) = me;
161+
IMPORT_LOCK_LEVEL(interp)--;
159162
} else {
160-
import_lock_thread = PYTHREAD_INVALID_THREAD_ID;
161-
import_lock_level = 0;
163+
IMPORT_LOCK_THREAD(interp) = PYTHREAD_INVALID_THREAD_ID;
164+
IMPORT_LOCK_LEVEL(interp) = 0;
162165
}
163166
return _PyStatus_OK();
164167
}
@@ -2634,10 +2637,6 @@ _PyImport_Fini(void)
26342637
{
26352638
/* Destroy the database used by _PyImport_{Fixup,Find}Extension */
26362639
_extensions_cache_clear();
2637-
if (import_lock != NULL) {
2638-
PyThread_free_lock(import_lock);
2639-
import_lock = NULL;
2640-
}
26412640

26422641
/* Use the same memory allocator as _PyImport_Init(). */
26432642
PyMemAllocatorEx old_alloc;
@@ -2726,6 +2725,11 @@ _PyImport_FiniCore(PyInterpreterState *interp)
27262725
PyErr_WriteUnraisable(NULL);
27272726
}
27282727

2728+
if (IMPORT_LOCK(interp) != NULL) {
2729+
PyThread_free_lock(IMPORT_LOCK(interp));
2730+
IMPORT_LOCK(interp) = NULL;
2731+
}
2732+
27292733
_PyImport_ClearCore(interp);
27302734
}
27312735

@@ -2857,7 +2861,9 @@ static PyObject *
28572861
_imp_lock_held_impl(PyObject *module)
28582862
/*[clinic end generated code: output=8b89384b5e1963fc input=9b088f9b217d9bdf]*/
28592863
{
2860-
return PyBool_FromLong(import_lock_thread != PYTHREAD_INVALID_THREAD_ID);
2864+
PyInterpreterState *interp = _PyInterpreterState_GET();
2865+
return PyBool_FromLong(
2866+
IMPORT_LOCK_THREAD(interp) != PYTHREAD_INVALID_THREAD_ID);
28612867
}
28622868

28632869
/*[clinic input]
@@ -2873,7 +2879,8 @@ static PyObject *
28732879
_imp_acquire_lock_impl(PyObject *module)
28742880
/*[clinic end generated code: output=1aff58cb0ee1b026 input=4a2d4381866d5fdc]*/
28752881
{
2876-
_PyImport_AcquireLock();
2882+
PyInterpreterState *interp = _PyInterpreterState_GET();
2883+
_PyImport_AcquireLock(interp);
28772884
Py_RETURN_NONE;
28782885
}
28792886

@@ -2889,7 +2896,8 @@ static PyObject *
28892896
_imp_release_lock_impl(PyObject *module)
28902897
/*[clinic end generated code: output=7faab6d0be178b0a input=934fb11516dd778b]*/
28912898
{
2892-
if (_PyImport_ReleaseLock() < 0) {
2899+
PyInterpreterState *interp = _PyInterpreterState_GET();
2900+
if (_PyImport_ReleaseLock(interp) < 0) {
28932901
PyErr_SetString(PyExc_RuntimeError,
28942902
"not holding the import lock");
28952903
return NULL;

0 commit comments

Comments
 (0)