diff options
author | Eric Snow <ericsnowcurrently@gmail.com> | 2019-03-09 06:44:33 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-03-09 06:44:33 (GMT) |
commit | 8479a3426eb7d1840473f7788e639954363ed37e (patch) | |
tree | 9d588c5c30e29d0ab6d6aa0e25c53caba8c5b593 /Python | |
parent | 5be45a6105d656c551adeee7770afdc3b806fbb5 (diff) | |
download | cpython-8479a3426eb7d1840473f7788e639954363ed37e.zip cpython-8479a3426eb7d1840473f7788e639954363ed37e.tar.gz cpython-8479a3426eb7d1840473f7788e639954363ed37e.tar.bz2 |
bpo-33608: Make sure locks in the runtime are properly re-created. (gh-12245)
Diffstat (limited to 'Python')
-rw-r--r-- | Python/ceval.c | 49 | ||||
-rw-r--r-- | Python/pystate.c | 29 |
2 files changed, 38 insertions, 40 deletions
diff --git a/Python/ceval.c b/Python/ceval.c index 356335a..373cde9 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -174,10 +174,10 @@ PyEval_InitThreads(void) PyThread_init_thread(); create_gil(); take_gil(_PyThreadState_GET()); - // Set it to the ID of the main thread of the main interpreter. - _PyRuntime.main_thread = PyThread_get_thread_ident(); - if (!_PyRuntime.ceval.pending.lock) { - _PyRuntime.ceval.pending.lock = PyThread_allocate_lock(); + + _PyRuntime.ceval.pending.lock = PyThread_allocate_lock(); + if (_PyRuntime.ceval.pending.lock == NULL) { + return Py_FatalError("Can't initialize threads for pending calls"); } } @@ -246,8 +246,11 @@ PyEval_ReInitThreads(void) return; recreate_gil(); take_gil(current_tstate); - _PyRuntime.main_thread = PyThread_get_thread_ident(); + _PyRuntime.ceval.pending.lock = PyThread_allocate_lock(); + if (_PyRuntime.ceval.pending.lock == NULL) { + Py_FatalError("Can't initialize threads for pending calls"); + } /* Destroy all threads except the current one */ _PyThreadState_DeleteExcept(current_tstate); @@ -362,35 +365,12 @@ _pop_pending_call(int (**func)(void *), void **arg) int Py_AddPendingCall(int (*func)(void *), void *arg) { - PyThread_type_lock lock = _PyRuntime.ceval.pending.lock; - - /* try a few times for the lock. Since this mechanism is used - * for signal handling (on the main thread), there is a (slim) - * chance that a signal is delivered on the same thread while we - * hold the lock during the Py_MakePendingCalls() function. - * This avoids a deadlock in that case. - * Note that signals can be delivered on any thread. In particular, - * on Windows, a SIGINT is delivered on a system-created worker - * thread. - * We also check for lock being NULL, in the unlikely case that - * this function is called before any bytecode evaluation takes place. - */ - if (lock != NULL) { - int i; - for (i = 0; i<100; i++) { - if (PyThread_acquire_lock(lock, NOWAIT_LOCK)) - break; - } - if (i == 100) - return -1; - } - + PyThread_acquire_lock(_PyRuntime.ceval.pending.lock, WAIT_LOCK); int result = _push_pending_call(func, arg); + PyThread_release_lock(_PyRuntime.ceval.pending.lock); /* signal main loop */ SIGNAL_PENDING_CALLS(); - if (lock != NULL) - PyThread_release_lock(lock); return result; } @@ -439,15 +419,6 @@ make_pending_calls(void) UNSIGNAL_PENDING_CALLS(); int res = 0; - if (!_PyRuntime.ceval.pending.lock) { - /* initial allocation of the lock */ - _PyRuntime.ceval.pending.lock = PyThread_allocate_lock(); - if (_PyRuntime.ceval.pending.lock == NULL) { - res = -1; - goto error; - } - } - /* perform a bounded number of calls, in case of recursion */ for (int i=0; i<NPENDINGCALLS; i++) { int (*func)(void *) = NULL; diff --git a/Python/pystate.c b/Python/pystate.c index ec8dba8..3978baa 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -60,7 +60,8 @@ _PyRuntimeState_Init_impl(_PyRuntimeState *runtime) return _Py_INIT_ERR("Can't initialize threads for cross-interpreter data registry"); } - // runtime->main_thread is set in PyEval_InitThreads(). + // Set it to the ID of the main thread of the main interpreter. + runtime->main_thread = PyThread_get_thread_ident(); return _Py_INIT_OK(); } @@ -94,6 +95,32 @@ _PyRuntimeState_Fini(_PyRuntimeState *runtime) PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); } +/* This function is called from PyOS_AfterFork_Child to ensure that + * newly created child processes do not share locks with the parent. + */ + +void +_PyRuntimeState_ReInitThreads(void) +{ + // This was initially set in _PyRuntimeState_Init(). + _PyRuntime.main_thread = PyThread_get_thread_ident(); + + _PyRuntime.interpreters.mutex = PyThread_allocate_lock(); + if (_PyRuntime.interpreters.mutex == NULL) { + Py_FatalError("Can't initialize lock for runtime interpreters"); + } + + _PyRuntime.interpreters.main->id_mutex = PyThread_allocate_lock(); + if (_PyRuntime.interpreters.main->id_mutex == NULL) { + Py_FatalError("Can't initialize ID lock for main interpreter"); + } + + _PyRuntime.xidregistry.mutex = PyThread_allocate_lock(); + if (_PyRuntime.xidregistry.mutex == NULL) { + Py_FatalError("Can't initialize lock for cross-interpreter data registry"); + } +} + #define HEAD_LOCK() PyThread_acquire_lock(_PyRuntime.interpreters.mutex, \ WAIT_LOCK) #define HEAD_UNLOCK() PyThread_release_lock(_PyRuntime.interpreters.mutex) |