mirror of
https://github.com/python/cpython
synced 2024-09-05 00:05:39 +00:00
gh-111924: Use PyMutex for Runtime-global Locks. (gh-112207)
This replaces some usages of PyThread_type_lock with PyMutex, which does not require memory allocation to initialize. This simplifies some of the runtime initialization and is also one step towards avoiding changing the default raw memory allocator during initialize/finalization, which can be non-thread-safe in some circumstances.
This commit is contained in:
parent
db460735af
commit
cf6110ba13
|
@ -1,5 +1,8 @@
|
||||||
#ifndef Py_INTERNAL_ATEXIT_H
|
#ifndef Py_INTERNAL_ATEXIT_H
|
||||||
#define Py_INTERNAL_ATEXIT_H
|
#define Py_INTERNAL_ATEXIT_H
|
||||||
|
|
||||||
|
#include "pycore_lock.h" // PyMutex
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
@ -15,7 +18,7 @@ extern "C" {
|
||||||
typedef void (*atexit_callbackfunc)(void);
|
typedef void (*atexit_callbackfunc)(void);
|
||||||
|
|
||||||
struct _atexit_runtime_state {
|
struct _atexit_runtime_state {
|
||||||
PyThread_type_lock mutex;
|
PyMutex mutex;
|
||||||
#define NEXITFUNCS 32
|
#define NEXITFUNCS 32
|
||||||
atexit_callbackfunc callbacks[NEXITFUNCS];
|
atexit_callbackfunc callbacks[NEXITFUNCS];
|
||||||
int ncallbacks;
|
int ncallbacks;
|
||||||
|
|
|
@ -41,8 +41,7 @@ PyAPI_FUNC(int) _PyEval_MakePendingCalls(PyThreadState *);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern void _Py_FinishPendingCalls(PyThreadState *tstate);
|
extern void _Py_FinishPendingCalls(PyThreadState *tstate);
|
||||||
extern void _PyEval_InitState(PyInterpreterState *, PyThread_type_lock);
|
extern void _PyEval_InitState(PyInterpreterState *);
|
||||||
extern void _PyEval_FiniState(struct _ceval_state *ceval);
|
|
||||||
extern void _PyEval_SignalReceived(PyInterpreterState *interp);
|
extern void _PyEval_SignalReceived(PyInterpreterState *interp);
|
||||||
|
|
||||||
// bitwise flags:
|
// bitwise flags:
|
||||||
|
|
|
@ -8,6 +8,7 @@ extern "C" {
|
||||||
# error "this header requires Py_BUILD_CORE define"
|
# error "this header requires Py_BUILD_CORE define"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "pycore_lock.h" // PyMutex
|
||||||
#include "pycore_gil.h" // struct _gil_runtime_state
|
#include "pycore_gil.h" // struct _gil_runtime_state
|
||||||
|
|
||||||
|
|
||||||
|
@ -15,7 +16,7 @@ typedef int (*_Py_pending_call_func)(void *);
|
||||||
|
|
||||||
struct _pending_calls {
|
struct _pending_calls {
|
||||||
int busy;
|
int busy;
|
||||||
PyThread_type_lock lock;
|
PyMutex mutex;
|
||||||
/* Request for running pending calls. */
|
/* Request for running pending calls. */
|
||||||
int32_t calls_to_do;
|
int32_t calls_to_do;
|
||||||
#define NPENDINGCALLS 32
|
#define NPENDINGCALLS 32
|
||||||
|
|
|
@ -8,6 +8,7 @@ extern "C" {
|
||||||
# error "this header requires Py_BUILD_CORE define"
|
# error "this header requires Py_BUILD_CORE define"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "pycore_lock.h" // PyMutex
|
||||||
#include "pycore_pyerrors.h"
|
#include "pycore_pyerrors.h"
|
||||||
|
|
||||||
|
|
||||||
|
@ -128,7 +129,7 @@ struct _xidregitem {
|
||||||
struct _xidregistry {
|
struct _xidregistry {
|
||||||
int global; /* builtin types or heap types */
|
int global; /* builtin types or heap types */
|
||||||
int initialized;
|
int initialized;
|
||||||
PyThread_type_lock mutex;
|
PyMutex mutex;
|
||||||
struct _xidregitem *head;
|
struct _xidregitem *head;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ extern "C" {
|
||||||
# error "this header requires Py_BUILD_CORE define"
|
# error "this header requires Py_BUILD_CORE define"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "pycore_lock.h" // PyMutex
|
||||||
#include "pycore_hashtable.h" // _Py_hashtable_t
|
#include "pycore_hashtable.h" // _Py_hashtable_t
|
||||||
#include "pycore_time.h" // _PyTime_t
|
#include "pycore_time.h" // _PyTime_t
|
||||||
|
|
||||||
|
@ -47,7 +48,7 @@ struct _import_runtime_state {
|
||||||
Py_ssize_t last_module_index;
|
Py_ssize_t last_module_index;
|
||||||
struct {
|
struct {
|
||||||
/* A lock to guard the cache. */
|
/* A lock to guard the cache. */
|
||||||
PyThread_type_lock mutex;
|
PyMutex mutex;
|
||||||
/* The actual cache of (filename, name, PyModuleDef) for modules.
|
/* The actual cache of (filename, name, PyModuleDef) for modules.
|
||||||
Only legacy (single-phase init) extension modules are added
|
Only legacy (single-phase init) extension modules are added
|
||||||
and only if they support multiple initialization (m_size >- 0)
|
and only if they support multiple initialization (m_size >- 0)
|
||||||
|
|
|
@ -92,6 +92,13 @@ PyMutex_IsLocked(PyMutex *m)
|
||||||
return (_Py_atomic_load_uint8(&m->v) & _Py_LOCKED) != 0;
|
return (_Py_atomic_load_uint8(&m->v) & _Py_LOCKED) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Re-initializes the mutex after a fork to the unlocked state.
|
||||||
|
static inline void
|
||||||
|
_PyMutex_at_fork_reinit(PyMutex *m)
|
||||||
|
{
|
||||||
|
memset(m, 0, sizeof(*m));
|
||||||
|
}
|
||||||
|
|
||||||
typedef enum _PyLockFlags {
|
typedef enum _PyLockFlags {
|
||||||
// Do not detach/release the GIL when waiting on the lock.
|
// Do not detach/release the GIL when waiting on the lock.
|
||||||
_Py_LOCK_DONT_DETACH = 0,
|
_Py_LOCK_DONT_DETACH = 0,
|
||||||
|
@ -108,6 +115,16 @@ typedef enum _PyLockFlags {
|
||||||
extern PyLockStatus
|
extern PyLockStatus
|
||||||
_PyMutex_LockTimed(PyMutex *m, _PyTime_t timeout_ns, _PyLockFlags flags);
|
_PyMutex_LockTimed(PyMutex *m, _PyTime_t timeout_ns, _PyLockFlags flags);
|
||||||
|
|
||||||
|
// Lock a mutex with aditional options. See _PyLockFlags for details.
|
||||||
|
static inline void
|
||||||
|
PyMutex_LockFlags(PyMutex *m, _PyLockFlags flags)
|
||||||
|
{
|
||||||
|
uint8_t expected = _Py_UNLOCKED;
|
||||||
|
if (!_Py_atomic_compare_exchange_uint8(&m->v, &expected, _Py_LOCKED)) {
|
||||||
|
_PyMutex_LockTimed(m, -1, flags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Unlock a mutex, returns 0 if the mutex is not locked (used for improved
|
// Unlock a mutex, returns 0 if the mutex is not locked (used for improved
|
||||||
// error messages).
|
// error messages).
|
||||||
extern int _PyMutex_TryUnlock(PyMutex *m);
|
extern int _PyMutex_TryUnlock(PyMutex *m);
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
#ifndef Py_INTERNAL_PYMEM_H
|
#ifndef Py_INTERNAL_PYMEM_H
|
||||||
#define Py_INTERNAL_PYMEM_H
|
#define Py_INTERNAL_PYMEM_H
|
||||||
|
|
||||||
|
#include "pycore_lock.h" // PyMutex
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
@ -30,7 +33,7 @@ typedef struct {
|
||||||
} debug_alloc_api_t;
|
} debug_alloc_api_t;
|
||||||
|
|
||||||
struct _pymem_allocators {
|
struct _pymem_allocators {
|
||||||
PyThread_type_lock mutex;
|
PyMutex mutex;
|
||||||
struct {
|
struct {
|
||||||
PyMemAllocatorEx raw;
|
PyMemAllocatorEx raw;
|
||||||
PyMemAllocatorEx mem;
|
PyMemAllocatorEx mem;
|
||||||
|
|
|
@ -220,9 +220,9 @@ PyAPI_FUNC(int) _PyState_AddModule(
|
||||||
extern int _PyOS_InterruptOccurred(PyThreadState *tstate);
|
extern int _PyOS_InterruptOccurred(PyThreadState *tstate);
|
||||||
|
|
||||||
#define HEAD_LOCK(runtime) \
|
#define HEAD_LOCK(runtime) \
|
||||||
PyThread_acquire_lock((runtime)->interpreters.mutex, WAIT_LOCK)
|
PyMutex_LockFlags(&(runtime)->interpreters.mutex, _Py_LOCK_DONT_DETACH)
|
||||||
#define HEAD_UNLOCK(runtime) \
|
#define HEAD_UNLOCK(runtime) \
|
||||||
PyThread_release_lock((runtime)->interpreters.mutex)
|
PyMutex_Unlock(&(runtime)->interpreters.mutex)
|
||||||
|
|
||||||
// Get the configuration of the current interpreter.
|
// Get the configuration of the current interpreter.
|
||||||
// The caller must hold the GIL.
|
// The caller must hold the GIL.
|
||||||
|
|
|
@ -173,7 +173,7 @@ typedef struct pyruntimestate {
|
||||||
unsigned long _finalizing_id;
|
unsigned long _finalizing_id;
|
||||||
|
|
||||||
struct pyinterpreters {
|
struct pyinterpreters {
|
||||||
PyThread_type_lock mutex;
|
PyMutex mutex;
|
||||||
/* The linked list of interpreters, newest first. */
|
/* The linked list of interpreters, newest first. */
|
||||||
PyInterpreterState *head;
|
PyInterpreterState *head;
|
||||||
/* The runtime's initial interpreter, which has a special role
|
/* The runtime's initial interpreter, which has a special role
|
||||||
|
@ -234,7 +234,7 @@ typedef struct pyruntimestate {
|
||||||
Py_OpenCodeHookFunction open_code_hook;
|
Py_OpenCodeHookFunction open_code_hook;
|
||||||
void *open_code_userdata;
|
void *open_code_userdata;
|
||||||
struct {
|
struct {
|
||||||
PyThread_type_lock mutex;
|
PyMutex mutex;
|
||||||
_Py_AuditHookEntry *head;
|
_Py_AuditHookEntry *head;
|
||||||
} audit_hooks;
|
} audit_hooks;
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ extern "C" {
|
||||||
# error "this header requires Py_BUILD_CORE define"
|
# error "this header requires Py_BUILD_CORE define"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "pycore_lock.h" // PyMutex
|
||||||
#include "pycore_fileutils.h" // _Py_error_handler
|
#include "pycore_fileutils.h" // _Py_error_handler
|
||||||
#include "pycore_identifier.h" // _Py_Identifier
|
#include "pycore_identifier.h" // _Py_Identifier
|
||||||
#include "pycore_ucnhash.h" // _PyUnicode_Name_CAPI
|
#include "pycore_ucnhash.h" // _PyUnicode_Name_CAPI
|
||||||
|
@ -277,7 +278,7 @@ extern PyTypeObject _PyUnicodeASCIIIter_Type;
|
||||||
/* --- Other API ---------------------------------------------------------- */
|
/* --- Other API ---------------------------------------------------------- */
|
||||||
|
|
||||||
struct _Py_unicode_runtime_ids {
|
struct _Py_unicode_runtime_ids {
|
||||||
PyThread_type_lock lock;
|
PyMutex mutex;
|
||||||
// next_index value must be preserved when Py_Initialize()/Py_Finalize()
|
// next_index value must be preserved when Py_Initialize()/Py_Finalize()
|
||||||
// is called multiple times: see _PyUnicode_FromId() implementation.
|
// is called multiple times: see _PyUnicode_FromId() implementation.
|
||||||
Py_ssize_t next_index;
|
Py_ssize_t next_index;
|
||||||
|
|
|
@ -329,13 +329,9 @@ int
|
||||||
_PyMem_SetDefaultAllocator(PyMemAllocatorDomain domain,
|
_PyMem_SetDefaultAllocator(PyMemAllocatorDomain domain,
|
||||||
PyMemAllocatorEx *old_alloc)
|
PyMemAllocatorEx *old_alloc)
|
||||||
{
|
{
|
||||||
if (ALLOCATORS_MUTEX == NULL) {
|
PyMutex_Lock(&ALLOCATORS_MUTEX);
|
||||||
/* The runtime must be initializing. */
|
|
||||||
return set_default_allocator_unlocked(domain, pydebug, old_alloc);
|
|
||||||
}
|
|
||||||
PyThread_acquire_lock(ALLOCATORS_MUTEX, WAIT_LOCK);
|
|
||||||
int res = set_default_allocator_unlocked(domain, pydebug, old_alloc);
|
int res = set_default_allocator_unlocked(domain, pydebug, old_alloc);
|
||||||
PyThread_release_lock(ALLOCATORS_MUTEX);
|
PyMutex_Unlock(&ALLOCATORS_MUTEX);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -467,9 +463,9 @@ set_up_allocators_unlocked(PyMemAllocatorName allocator)
|
||||||
int
|
int
|
||||||
_PyMem_SetupAllocators(PyMemAllocatorName allocator)
|
_PyMem_SetupAllocators(PyMemAllocatorName allocator)
|
||||||
{
|
{
|
||||||
PyThread_acquire_lock(ALLOCATORS_MUTEX, WAIT_LOCK);
|
PyMutex_Lock(&ALLOCATORS_MUTEX);
|
||||||
int res = set_up_allocators_unlocked(allocator);
|
int res = set_up_allocators_unlocked(allocator);
|
||||||
PyThread_release_lock(ALLOCATORS_MUTEX);
|
PyMutex_Unlock(&ALLOCATORS_MUTEX);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -554,9 +550,9 @@ get_current_allocator_name_unlocked(void)
|
||||||
const char*
|
const char*
|
||||||
_PyMem_GetCurrentAllocatorName(void)
|
_PyMem_GetCurrentAllocatorName(void)
|
||||||
{
|
{
|
||||||
PyThread_acquire_lock(ALLOCATORS_MUTEX, WAIT_LOCK);
|
PyMutex_Lock(&ALLOCATORS_MUTEX);
|
||||||
const char *name = get_current_allocator_name_unlocked();
|
const char *name = get_current_allocator_name_unlocked();
|
||||||
PyThread_release_lock(ALLOCATORS_MUTEX);
|
PyMutex_Unlock(&ALLOCATORS_MUTEX);
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -653,14 +649,9 @@ set_up_debug_hooks_unlocked(void)
|
||||||
void
|
void
|
||||||
PyMem_SetupDebugHooks(void)
|
PyMem_SetupDebugHooks(void)
|
||||||
{
|
{
|
||||||
if (ALLOCATORS_MUTEX == NULL) {
|
PyMutex_Lock(&ALLOCATORS_MUTEX);
|
||||||
/* The runtime must not be completely initialized yet. */
|
|
||||||
set_up_debug_hooks_unlocked();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
PyThread_acquire_lock(ALLOCATORS_MUTEX, WAIT_LOCK);
|
|
||||||
set_up_debug_hooks_unlocked();
|
set_up_debug_hooks_unlocked();
|
||||||
PyThread_release_lock(ALLOCATORS_MUTEX);
|
PyMutex_Unlock(&ALLOCATORS_MUTEX);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -696,53 +687,33 @@ set_allocator_unlocked(PyMemAllocatorDomain domain, PyMemAllocatorEx *allocator)
|
||||||
void
|
void
|
||||||
PyMem_GetAllocator(PyMemAllocatorDomain domain, PyMemAllocatorEx *allocator)
|
PyMem_GetAllocator(PyMemAllocatorDomain domain, PyMemAllocatorEx *allocator)
|
||||||
{
|
{
|
||||||
if (ALLOCATORS_MUTEX == NULL) {
|
PyMutex_Lock(&ALLOCATORS_MUTEX);
|
||||||
/* The runtime must not be completely initialized yet. */
|
|
||||||
get_allocator_unlocked(domain, allocator);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
PyThread_acquire_lock(ALLOCATORS_MUTEX, WAIT_LOCK);
|
|
||||||
get_allocator_unlocked(domain, allocator);
|
get_allocator_unlocked(domain, allocator);
|
||||||
PyThread_release_lock(ALLOCATORS_MUTEX);
|
PyMutex_Unlock(&ALLOCATORS_MUTEX);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PyMem_SetAllocator(PyMemAllocatorDomain domain, PyMemAllocatorEx *allocator)
|
PyMem_SetAllocator(PyMemAllocatorDomain domain, PyMemAllocatorEx *allocator)
|
||||||
{
|
{
|
||||||
if (ALLOCATORS_MUTEX == NULL) {
|
PyMutex_Lock(&ALLOCATORS_MUTEX);
|
||||||
/* The runtime must not be completely initialized yet. */
|
|
||||||
set_allocator_unlocked(domain, allocator);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
PyThread_acquire_lock(ALLOCATORS_MUTEX, WAIT_LOCK);
|
|
||||||
set_allocator_unlocked(domain, allocator);
|
set_allocator_unlocked(domain, allocator);
|
||||||
PyThread_release_lock(ALLOCATORS_MUTEX);
|
PyMutex_Unlock(&ALLOCATORS_MUTEX);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PyObject_GetArenaAllocator(PyObjectArenaAllocator *allocator)
|
PyObject_GetArenaAllocator(PyObjectArenaAllocator *allocator)
|
||||||
{
|
{
|
||||||
if (ALLOCATORS_MUTEX == NULL) {
|
PyMutex_Lock(&ALLOCATORS_MUTEX);
|
||||||
/* The runtime must not be completely initialized yet. */
|
|
||||||
*allocator = _PyObject_Arena;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
PyThread_acquire_lock(ALLOCATORS_MUTEX, WAIT_LOCK);
|
|
||||||
*allocator = _PyObject_Arena;
|
*allocator = _PyObject_Arena;
|
||||||
PyThread_release_lock(ALLOCATORS_MUTEX);
|
PyMutex_Unlock(&ALLOCATORS_MUTEX);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PyObject_SetArenaAllocator(PyObjectArenaAllocator *allocator)
|
PyObject_SetArenaAllocator(PyObjectArenaAllocator *allocator)
|
||||||
{
|
{
|
||||||
if (ALLOCATORS_MUTEX == NULL) {
|
PyMutex_Lock(&ALLOCATORS_MUTEX);
|
||||||
/* The runtime must not be completely initialized yet. */
|
|
||||||
_PyObject_Arena = *allocator;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
PyThread_acquire_lock(ALLOCATORS_MUTEX, WAIT_LOCK);
|
|
||||||
_PyObject_Arena = *allocator;
|
_PyObject_Arena = *allocator;
|
||||||
PyThread_release_lock(ALLOCATORS_MUTEX);
|
PyMutex_Unlock(&ALLOCATORS_MUTEX);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1904,7 +1904,7 @@ _PyUnicode_FromId(_Py_Identifier *id)
|
||||||
if (index < 0) {
|
if (index < 0) {
|
||||||
struct _Py_unicode_runtime_ids *rt_ids = &interp->runtime->unicode_state.ids;
|
struct _Py_unicode_runtime_ids *rt_ids = &interp->runtime->unicode_state.ids;
|
||||||
|
|
||||||
PyThread_acquire_lock(rt_ids->lock, WAIT_LOCK);
|
PyMutex_Lock(&rt_ids->mutex);
|
||||||
// Check again to detect concurrent access. Another thread can have
|
// Check again to detect concurrent access. Another thread can have
|
||||||
// initialized the index while this thread waited for the lock.
|
// initialized the index while this thread waited for the lock.
|
||||||
index = _Py_atomic_load_ssize(&id->index);
|
index = _Py_atomic_load_ssize(&id->index);
|
||||||
|
@ -1914,7 +1914,7 @@ _PyUnicode_FromId(_Py_Identifier *id)
|
||||||
rt_ids->next_index++;
|
rt_ids->next_index++;
|
||||||
_Py_atomic_store_ssize(&id->index, index);
|
_Py_atomic_store_ssize(&id->index, index);
|
||||||
}
|
}
|
||||||
PyThread_release_lock(rt_ids->lock);
|
PyMutex_Unlock(&rt_ids->mutex);
|
||||||
}
|
}
|
||||||
assert(index >= 0);
|
assert(index >= 0);
|
||||||
|
|
||||||
|
|
|
@ -589,9 +589,7 @@ _PyEval_ReInitThreads(PyThreadState *tstate)
|
||||||
take_gil(tstate);
|
take_gil(tstate);
|
||||||
|
|
||||||
struct _pending_calls *pending = &tstate->interp->ceval.pending;
|
struct _pending_calls *pending = &tstate->interp->ceval.pending;
|
||||||
if (_PyThread_at_fork_reinit(&pending->lock) < 0) {
|
_PyMutex_at_fork_reinit(&pending->mutex);
|
||||||
return _PyStatus_ERR("Can't reinitialize pending calls lock");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Destroy all threads except the current one */
|
/* Destroy all threads except the current one */
|
||||||
_PyThreadState_DeleteExcept(tstate);
|
_PyThreadState_DeleteExcept(tstate);
|
||||||
|
@ -720,13 +718,10 @@ _PyEval_AddPendingCall(PyInterpreterState *interp,
|
||||||
assert(_Py_IsMainInterpreter(interp));
|
assert(_Py_IsMainInterpreter(interp));
|
||||||
pending = &_PyRuntime.ceval.pending_mainthread;
|
pending = &_PyRuntime.ceval.pending_mainthread;
|
||||||
}
|
}
|
||||||
/* Ensure that _PyEval_InitState() was called
|
|
||||||
and that _PyEval_FiniState() is not called yet. */
|
|
||||||
assert(pending->lock != NULL);
|
|
||||||
|
|
||||||
PyThread_acquire_lock(pending->lock, WAIT_LOCK);
|
PyMutex_Lock(&pending->mutex);
|
||||||
int result = _push_pending_call(pending, func, arg, flags);
|
int result = _push_pending_call(pending, func, arg, flags);
|
||||||
PyThread_release_lock(pending->lock);
|
PyMutex_Unlock(&pending->mutex);
|
||||||
|
|
||||||
/* signal main loop */
|
/* signal main loop */
|
||||||
SIGNAL_PENDING_CALLS(interp);
|
SIGNAL_PENDING_CALLS(interp);
|
||||||
|
@ -768,9 +763,9 @@ _make_pending_calls(struct _pending_calls *pending)
|
||||||
int flags = 0;
|
int flags = 0;
|
||||||
|
|
||||||
/* pop one item off the queue while holding the lock */
|
/* pop one item off the queue while holding the lock */
|
||||||
PyThread_acquire_lock(pending->lock, WAIT_LOCK);
|
PyMutex_Lock(&pending->mutex);
|
||||||
_pop_pending_call(pending, &func, &arg, &flags);
|
_pop_pending_call(pending, &func, &arg, &flags);
|
||||||
PyThread_release_lock(pending->lock);
|
PyMutex_Unlock(&pending->mutex);
|
||||||
|
|
||||||
/* having released the lock, perform the callback */
|
/* having released the lock, perform the callback */
|
||||||
if (func == NULL) {
|
if (func == NULL) {
|
||||||
|
@ -795,7 +790,7 @@ make_pending_calls(PyInterpreterState *interp)
|
||||||
|
|
||||||
/* Only one thread (per interpreter) may run the pending calls
|
/* Only one thread (per interpreter) may run the pending calls
|
||||||
at once. In the same way, we don't do recursive pending calls. */
|
at once. In the same way, we don't do recursive pending calls. */
|
||||||
PyThread_acquire_lock(pending->lock, WAIT_LOCK);
|
PyMutex_Lock(&pending->mutex);
|
||||||
if (pending->busy) {
|
if (pending->busy) {
|
||||||
/* A pending call was added after another thread was already
|
/* A pending call was added after another thread was already
|
||||||
handling the pending calls (and had already "unsignaled").
|
handling the pending calls (and had already "unsignaled").
|
||||||
|
@ -807,11 +802,11 @@ make_pending_calls(PyInterpreterState *interp)
|
||||||
care of any remaining pending calls. Until then, though,
|
care of any remaining pending calls. Until then, though,
|
||||||
all the interpreter's threads will be tripping the eval
|
all the interpreter's threads will be tripping the eval
|
||||||
breaker every time it's checked. */
|
breaker every time it's checked. */
|
||||||
PyThread_release_lock(pending->lock);
|
PyMutex_Unlock(&pending->mutex);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
pending->busy = 1;
|
pending->busy = 1;
|
||||||
PyThread_release_lock(pending->lock);
|
PyMutex_Unlock(&pending->mutex);
|
||||||
|
|
||||||
/* unsignal before starting to call callbacks, so that any callback
|
/* unsignal before starting to call callbacks, so that any callback
|
||||||
added in-between re-signals */
|
added in-between re-signals */
|
||||||
|
@ -892,23 +887,9 @@ Py_MakePendingCalls(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
_PyEval_InitState(PyInterpreterState *interp, PyThread_type_lock pending_lock)
|
_PyEval_InitState(PyInterpreterState *interp)
|
||||||
{
|
{
|
||||||
_gil_initialize(&interp->_gil);
|
_gil_initialize(&interp->_gil);
|
||||||
|
|
||||||
struct _pending_calls *pending = &interp->ceval.pending;
|
|
||||||
assert(pending->lock == NULL);
|
|
||||||
pending->lock = pending_lock;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
_PyEval_FiniState(struct _ceval_state *ceval)
|
|
||||||
{
|
|
||||||
struct _pending_calls *pending = &ceval->pending;
|
|
||||||
if (pending->lock != NULL) {
|
|
||||||
PyThread_free_lock(pending->lock);
|
|
||||||
pending->lock = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -456,16 +456,17 @@ _xidregistry_clear(struct _xidregistry *xidregistry)
|
||||||
static void
|
static void
|
||||||
_xidregistry_lock(struct _xidregistry *registry)
|
_xidregistry_lock(struct _xidregistry *registry)
|
||||||
{
|
{
|
||||||
if (registry->mutex != NULL) {
|
if (registry->global) {
|
||||||
PyThread_acquire_lock(registry->mutex, WAIT_LOCK);
|
PyMutex_Lock(®istry->mutex);
|
||||||
}
|
}
|
||||||
|
// else: Within an interpreter we rely on the GIL instead of a separate lock.
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_xidregistry_unlock(struct _xidregistry *registry)
|
_xidregistry_unlock(struct _xidregistry *registry)
|
||||||
{
|
{
|
||||||
if (registry->mutex != NULL) {
|
if (registry->global) {
|
||||||
PyThread_release_lock(registry->mutex);
|
PyMutex_Unlock(®istry->mutex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -874,19 +875,10 @@ _xidregistry_init(struct _xidregistry *registry)
|
||||||
registry->initialized = 1;
|
registry->initialized = 1;
|
||||||
|
|
||||||
if (registry->global) {
|
if (registry->global) {
|
||||||
// We manage the mutex lifecycle in pystate.c.
|
|
||||||
assert(registry->mutex != NULL);
|
|
||||||
|
|
||||||
// Registering the builtins is cheap so we don't bother doing it lazily.
|
// Registering the builtins is cheap so we don't bother doing it lazily.
|
||||||
assert(registry->head == NULL);
|
assert(registry->head == NULL);
|
||||||
_register_builtins_for_crossinterpreter_data(registry);
|
_register_builtins_for_crossinterpreter_data(registry);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
// Within an interpreter we rely on the GIL instead of a separate lock.
|
|
||||||
assert(registry->mutex == NULL);
|
|
||||||
|
|
||||||
// There's nothing else to initialize.
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -898,17 +890,6 @@ _xidregistry_fini(struct _xidregistry *registry)
|
||||||
registry->initialized = 0;
|
registry->initialized = 0;
|
||||||
|
|
||||||
_xidregistry_clear(registry);
|
_xidregistry_clear(registry);
|
||||||
|
|
||||||
if (registry->global) {
|
|
||||||
// We manage the mutex lifecycle in pystate.c.
|
|
||||||
assert(registry->mutex != NULL);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// There's nothing else to finalize.
|
|
||||||
|
|
||||||
// Within an interpreter we rely on the GIL instead of a separate lock.
|
|
||||||
assert(registry->mutex == NULL);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -418,11 +418,7 @@ remove_module(PyThreadState *tstate, PyObject *name)
|
||||||
Py_ssize_t
|
Py_ssize_t
|
||||||
_PyImport_GetNextModuleIndex(void)
|
_PyImport_GetNextModuleIndex(void)
|
||||||
{
|
{
|
||||||
PyThread_acquire_lock(EXTENSIONS.mutex, WAIT_LOCK);
|
return _Py_atomic_add_ssize(&LAST_MODULE_INDEX, 1) + 1;
|
||||||
LAST_MODULE_INDEX++;
|
|
||||||
Py_ssize_t index = LAST_MODULE_INDEX;
|
|
||||||
PyThread_release_lock(EXTENSIONS.mutex);
|
|
||||||
return index;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *
|
static const char *
|
||||||
|
@ -882,13 +878,13 @@ gets even messier.
|
||||||
static inline void
|
static inline void
|
||||||
extensions_lock_acquire(void)
|
extensions_lock_acquire(void)
|
||||||
{
|
{
|
||||||
PyThread_acquire_lock(_PyRuntime.imports.extensions.mutex, WAIT_LOCK);
|
PyMutex_Lock(&_PyRuntime.imports.extensions.mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
extensions_lock_release(void)
|
extensions_lock_release(void)
|
||||||
{
|
{
|
||||||
PyThread_release_lock(_PyRuntime.imports.extensions.mutex);
|
PyMutex_Unlock(&_PyRuntime.imports.extensions.mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Magic for extension modules (built-in as well as dynamically
|
/* Magic for extension modules (built-in as well as dynamically
|
||||||
|
|
|
@ -3056,13 +3056,13 @@ wait_for_thread_shutdown(PyThreadState *tstate)
|
||||||
int Py_AtExit(void (*func)(void))
|
int Py_AtExit(void (*func)(void))
|
||||||
{
|
{
|
||||||
struct _atexit_runtime_state *state = &_PyRuntime.atexit;
|
struct _atexit_runtime_state *state = &_PyRuntime.atexit;
|
||||||
PyThread_acquire_lock(state->mutex, WAIT_LOCK);
|
PyMutex_Lock(&state->mutex);
|
||||||
if (state->ncallbacks >= NEXITFUNCS) {
|
if (state->ncallbacks >= NEXITFUNCS) {
|
||||||
PyThread_release_lock(state->mutex);
|
PyMutex_Unlock(&state->mutex);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
state->callbacks[state->ncallbacks++] = func;
|
state->callbacks[state->ncallbacks++] = func;
|
||||||
PyThread_release_lock(state->mutex);
|
PyMutex_Unlock(&state->mutex);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3072,18 +3072,18 @@ call_ll_exitfuncs(_PyRuntimeState *runtime)
|
||||||
atexit_callbackfunc exitfunc;
|
atexit_callbackfunc exitfunc;
|
||||||
struct _atexit_runtime_state *state = &runtime->atexit;
|
struct _atexit_runtime_state *state = &runtime->atexit;
|
||||||
|
|
||||||
PyThread_acquire_lock(state->mutex, WAIT_LOCK);
|
PyMutex_Lock(&state->mutex);
|
||||||
while (state->ncallbacks > 0) {
|
while (state->ncallbacks > 0) {
|
||||||
/* pop last function from the list */
|
/* pop last function from the list */
|
||||||
state->ncallbacks--;
|
state->ncallbacks--;
|
||||||
exitfunc = state->callbacks[state->ncallbacks];
|
exitfunc = state->callbacks[state->ncallbacks];
|
||||||
state->callbacks[state->ncallbacks] = NULL;
|
state->callbacks[state->ncallbacks] = NULL;
|
||||||
|
|
||||||
PyThread_release_lock(state->mutex);
|
PyMutex_Unlock(&state->mutex);
|
||||||
exitfunc();
|
exitfunc();
|
||||||
PyThread_acquire_lock(state->mutex, WAIT_LOCK);
|
PyMutex_Lock(&state->mutex);
|
||||||
}
|
}
|
||||||
PyThread_release_lock(state->mutex);
|
PyMutex_Unlock(&state->mutex);
|
||||||
|
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
fflush(stderr);
|
fflush(stderr);
|
||||||
|
|
121
Python/pystate.c
121
Python/pystate.c
|
@ -379,49 +379,23 @@ _Py_COMP_DIAG_IGNORE_DEPR_DECLS
|
||||||
static const _PyRuntimeState initial = _PyRuntimeState_INIT(_PyRuntime);
|
static const _PyRuntimeState initial = _PyRuntimeState_INIT(_PyRuntime);
|
||||||
_Py_COMP_DIAG_POP
|
_Py_COMP_DIAG_POP
|
||||||
|
|
||||||
#define NUMLOCKS 8
|
|
||||||
#define LOCKS_INIT(runtime) \
|
#define LOCKS_INIT(runtime) \
|
||||||
{ \
|
{ \
|
||||||
&(runtime)->interpreters.mutex, \
|
&(runtime)->interpreters.mutex, \
|
||||||
&(runtime)->xi.registry.mutex, \
|
&(runtime)->xi.registry.mutex, \
|
||||||
&(runtime)->unicode_state.ids.lock, \
|
&(runtime)->unicode_state.ids.mutex, \
|
||||||
&(runtime)->imports.extensions.mutex, \
|
&(runtime)->imports.extensions.mutex, \
|
||||||
&(runtime)->ceval.pending_mainthread.lock, \
|
&(runtime)->ceval.pending_mainthread.mutex, \
|
||||||
&(runtime)->atexit.mutex, \
|
&(runtime)->atexit.mutex, \
|
||||||
&(runtime)->audit_hooks.mutex, \
|
&(runtime)->audit_hooks.mutex, \
|
||||||
&(runtime)->allocators.mutex, \
|
&(runtime)->allocators.mutex, \
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
alloc_for_runtime(PyThread_type_lock locks[NUMLOCKS])
|
|
||||||
{
|
|
||||||
/* Force default allocator, since _PyRuntimeState_Fini() must
|
|
||||||
use the same allocator than this function. */
|
|
||||||
PyMemAllocatorEx old_alloc;
|
|
||||||
_PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
|
|
||||||
|
|
||||||
for (int i = 0; i < NUMLOCKS; i++) {
|
|
||||||
PyThread_type_lock lock = PyThread_allocate_lock();
|
|
||||||
if (lock == NULL) {
|
|
||||||
for (int j = 0; j < i; j++) {
|
|
||||||
PyThread_free_lock(locks[j]);
|
|
||||||
locks[j] = NULL;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
locks[i] = lock;
|
|
||||||
}
|
|
||||||
|
|
||||||
PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
init_runtime(_PyRuntimeState *runtime,
|
init_runtime(_PyRuntimeState *runtime,
|
||||||
void *open_code_hook, void *open_code_userdata,
|
void *open_code_hook, void *open_code_userdata,
|
||||||
_Py_AuditHookEntry *audit_hook_head,
|
_Py_AuditHookEntry *audit_hook_head,
|
||||||
Py_ssize_t unicode_next_index,
|
Py_ssize_t unicode_next_index)
|
||||||
PyThread_type_lock locks[NUMLOCKS])
|
|
||||||
{
|
{
|
||||||
assert(!runtime->preinitializing);
|
assert(!runtime->preinitializing);
|
||||||
assert(!runtime->preinitialized);
|
assert(!runtime->preinitialized);
|
||||||
|
@ -435,12 +409,6 @@ init_runtime(_PyRuntimeState *runtime,
|
||||||
|
|
||||||
PyPreConfig_InitPythonConfig(&runtime->preconfig);
|
PyPreConfig_InitPythonConfig(&runtime->preconfig);
|
||||||
|
|
||||||
PyThread_type_lock *lockptrs[NUMLOCKS] = LOCKS_INIT(runtime);
|
|
||||||
for (int i = 0; i < NUMLOCKS; i++) {
|
|
||||||
assert(locks[i] != NULL);
|
|
||||||
*lockptrs[i] = locks[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set it to the ID of the main thread of the main interpreter.
|
// Set it to the ID of the main thread of the main interpreter.
|
||||||
runtime->main_thread = PyThread_get_thread_ident();
|
runtime->main_thread = PyThread_get_thread_ident();
|
||||||
|
|
||||||
|
@ -466,11 +434,6 @@ _PyRuntimeState_Init(_PyRuntimeState *runtime)
|
||||||
// is called multiple times.
|
// is called multiple times.
|
||||||
Py_ssize_t unicode_next_index = runtime->unicode_state.ids.next_index;
|
Py_ssize_t unicode_next_index = runtime->unicode_state.ids.next_index;
|
||||||
|
|
||||||
PyThread_type_lock locks[NUMLOCKS];
|
|
||||||
if (alloc_for_runtime(locks) != 0) {
|
|
||||||
return _PyStatus_NO_MEMORY();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (runtime->_initialized) {
|
if (runtime->_initialized) {
|
||||||
// Py_Initialize() must be running again.
|
// Py_Initialize() must be running again.
|
||||||
// Reset to _PyRuntimeState_INIT.
|
// Reset to _PyRuntimeState_INIT.
|
||||||
|
@ -489,7 +452,7 @@ _PyRuntimeState_Init(_PyRuntimeState *runtime)
|
||||||
}
|
}
|
||||||
|
|
||||||
init_runtime(runtime, open_code_hook, open_code_userdata, audit_hook_head,
|
init_runtime(runtime, open_code_hook, open_code_userdata, audit_hook_head,
|
||||||
unicode_next_index, locks);
|
unicode_next_index);
|
||||||
|
|
||||||
return _PyStatus_OK();
|
return _PyStatus_OK();
|
||||||
}
|
}
|
||||||
|
@ -509,23 +472,6 @@ _PyRuntimeState_Fini(_PyRuntimeState *runtime)
|
||||||
if (PyThread_tss_is_created(&runtime->trashTSSkey)) {
|
if (PyThread_tss_is_created(&runtime->trashTSSkey)) {
|
||||||
PyThread_tss_delete(&runtime->trashTSSkey);
|
PyThread_tss_delete(&runtime->trashTSSkey);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Force the allocator used by _PyRuntimeState_Init(). */
|
|
||||||
PyMemAllocatorEx old_alloc;
|
|
||||||
_PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
|
|
||||||
#define FREE_LOCK(LOCK) \
|
|
||||||
if (LOCK != NULL) { \
|
|
||||||
PyThread_free_lock(LOCK); \
|
|
||||||
LOCK = NULL; \
|
|
||||||
}
|
|
||||||
|
|
||||||
PyThread_type_lock *lockptrs[NUMLOCKS] = LOCKS_INIT(runtime);
|
|
||||||
for (int i = 0; i < NUMLOCKS; i++) {
|
|
||||||
FREE_LOCK(*lockptrs[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef FREE_LOCK
|
|
||||||
PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_FORK
|
#ifdef HAVE_FORK
|
||||||
|
@ -537,28 +483,19 @@ _PyRuntimeState_ReInitThreads(_PyRuntimeState *runtime)
|
||||||
// This was initially set in _PyRuntimeState_Init().
|
// This was initially set in _PyRuntimeState_Init().
|
||||||
runtime->main_thread = PyThread_get_thread_ident();
|
runtime->main_thread = PyThread_get_thread_ident();
|
||||||
|
|
||||||
/* Force default allocator, since _PyRuntimeState_Fini() must
|
|
||||||
use the same allocator than this function. */
|
|
||||||
PyMemAllocatorEx old_alloc;
|
|
||||||
_PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
|
|
||||||
|
|
||||||
PyThread_type_lock *lockptrs[NUMLOCKS] = LOCKS_INIT(runtime);
|
|
||||||
int reinit_err = 0;
|
|
||||||
for (int i = 0; i < NUMLOCKS; i++) {
|
|
||||||
reinit_err += _PyThread_at_fork_reinit(lockptrs[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
|
|
||||||
|
|
||||||
// Clears the parking lot. Any waiting threads are dead. This must be
|
// Clears the parking lot. Any waiting threads are dead. This must be
|
||||||
// called before releasing any locks that use the parking lot.
|
// called before releasing any locks that use the parking lot.
|
||||||
_PyParkingLot_AfterFork();
|
_PyParkingLot_AfterFork();
|
||||||
|
|
||||||
|
// Re-initialize global locks
|
||||||
|
PyMutex *locks[] = LOCKS_INIT(runtime);
|
||||||
|
for (size_t i = 0; i < Py_ARRAY_LENGTH(locks); i++) {
|
||||||
|
_PyMutex_at_fork_reinit(locks[i]);
|
||||||
|
}
|
||||||
|
|
||||||
/* bpo-42540: id_mutex is freed by _PyInterpreterState_Delete, which does
|
/* bpo-42540: id_mutex is freed by _PyInterpreterState_Delete, which does
|
||||||
* not force the default allocator. */
|
* not force the default allocator. */
|
||||||
reinit_err += _PyThread_at_fork_reinit(&runtime->interpreters.main->id_mutex);
|
if (_PyThread_at_fork_reinit(&runtime->interpreters.main->id_mutex) < 0) {
|
||||||
|
|
||||||
if (reinit_err < 0) {
|
|
||||||
return _PyStatus_ERR("Failed to reinitialize runtime locks");
|
return _PyStatus_ERR("Failed to reinitialize runtime locks");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -594,24 +531,6 @@ _PyInterpreterState_Enable(_PyRuntimeState *runtime)
|
||||||
{
|
{
|
||||||
struct pyinterpreters *interpreters = &runtime->interpreters;
|
struct pyinterpreters *interpreters = &runtime->interpreters;
|
||||||
interpreters->next_id = 0;
|
interpreters->next_id = 0;
|
||||||
|
|
||||||
/* Py_Finalize() calls _PyRuntimeState_Fini() which clears the mutex.
|
|
||||||
Create a new mutex if needed. */
|
|
||||||
if (interpreters->mutex == NULL) {
|
|
||||||
/* Force default allocator, since _PyRuntimeState_Fini() must
|
|
||||||
use the same allocator than this function. */
|
|
||||||
PyMemAllocatorEx old_alloc;
|
|
||||||
_PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
|
|
||||||
|
|
||||||
interpreters->mutex = PyThread_allocate_lock();
|
|
||||||
|
|
||||||
PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
|
|
||||||
|
|
||||||
if (interpreters->mutex == NULL) {
|
|
||||||
return _PyStatus_ERR("Can't initialize threads for interpreter");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return _PyStatus_OK();
|
return _PyStatus_OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -654,8 +573,7 @@ free_interpreter(PyInterpreterState *interp)
|
||||||
static PyStatus
|
static PyStatus
|
||||||
init_interpreter(PyInterpreterState *interp,
|
init_interpreter(PyInterpreterState *interp,
|
||||||
_PyRuntimeState *runtime, int64_t id,
|
_PyRuntimeState *runtime, int64_t id,
|
||||||
PyInterpreterState *next,
|
PyInterpreterState *next)
|
||||||
PyThread_type_lock pending_lock)
|
|
||||||
{
|
{
|
||||||
if (interp->_initialized) {
|
if (interp->_initialized) {
|
||||||
return _PyStatus_ERR("interpreter already initialized");
|
return _PyStatus_ERR("interpreter already initialized");
|
||||||
|
@ -684,7 +602,7 @@ init_interpreter(PyInterpreterState *interp,
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
_PyEval_InitState(interp, pending_lock);
|
_PyEval_InitState(interp);
|
||||||
_PyGC_InitState(&interp->gc);
|
_PyGC_InitState(&interp->gc);
|
||||||
PyConfig_InitPythonConfig(&interp->config);
|
PyConfig_InitPythonConfig(&interp->config);
|
||||||
_PyType_InitCache(interp);
|
_PyType_InitCache(interp);
|
||||||
|
@ -730,11 +648,6 @@ _PyInterpreterState_New(PyThreadState *tstate, PyInterpreterState **pinterp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PyThread_type_lock pending_lock = PyThread_allocate_lock();
|
|
||||||
if (pending_lock == NULL) {
|
|
||||||
return _PyStatus_NO_MEMORY();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We completely serialize creation of multiple interpreters, since
|
/* We completely serialize creation of multiple interpreters, since
|
||||||
it simplifies things here and blocking concurrent calls isn't a problem.
|
it simplifies things here and blocking concurrent calls isn't a problem.
|
||||||
Regardless, we must fully block subinterpreter creation until
|
Regardless, we must fully block subinterpreter creation until
|
||||||
|
@ -781,11 +694,10 @@ _PyInterpreterState_New(PyThreadState *tstate, PyInterpreterState **pinterp)
|
||||||
interpreters->head = interp;
|
interpreters->head = interp;
|
||||||
|
|
||||||
status = init_interpreter(interp, runtime,
|
status = init_interpreter(interp, runtime,
|
||||||
id, old_head, pending_lock);
|
id, old_head);
|
||||||
if (_PyStatus_EXCEPTION(status)) {
|
if (_PyStatus_EXCEPTION(status)) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
pending_lock = NULL;
|
|
||||||
|
|
||||||
HEAD_UNLOCK(runtime);
|
HEAD_UNLOCK(runtime);
|
||||||
|
|
||||||
|
@ -796,9 +708,6 @@ _PyInterpreterState_New(PyThreadState *tstate, PyInterpreterState **pinterp)
|
||||||
error:
|
error:
|
||||||
HEAD_UNLOCK(runtime);
|
HEAD_UNLOCK(runtime);
|
||||||
|
|
||||||
if (pending_lock != NULL) {
|
|
||||||
PyThread_free_lock(pending_lock);
|
|
||||||
}
|
|
||||||
if (interp != NULL) {
|
if (interp != NULL) {
|
||||||
free_interpreter(interp);
|
free_interpreter(interp);
|
||||||
}
|
}
|
||||||
|
@ -1003,8 +912,6 @@ PyInterpreterState_Delete(PyInterpreterState *interp)
|
||||||
|
|
||||||
zapthreads(interp);
|
zapthreads(interp);
|
||||||
|
|
||||||
_PyEval_FiniState(&interp->ceval);
|
|
||||||
|
|
||||||
// XXX These two calls should be done at the end of clear_interpreter(),
|
// XXX These two calls should be done at the end of clear_interpreter(),
|
||||||
// but currently some objects get decref'ed after that.
|
// but currently some objects get decref'ed after that.
|
||||||
#ifdef Py_REF_DEBUG
|
#ifdef Py_REF_DEBUG
|
||||||
|
|
|
@ -451,15 +451,9 @@ PySys_AddAuditHook(Py_AuditHookFunction hook, void *userData)
|
||||||
e->hookCFunction = (Py_AuditHookFunction)hook;
|
e->hookCFunction = (Py_AuditHookFunction)hook;
|
||||||
e->userData = userData;
|
e->userData = userData;
|
||||||
|
|
||||||
if (runtime->audit_hooks.mutex == NULL) {
|
PyMutex_Lock(&runtime->audit_hooks.mutex);
|
||||||
/* The runtime must not be initialized yet. */
|
add_audit_hook_entry_unlocked(runtime, e);
|
||||||
add_audit_hook_entry_unlocked(runtime, e);
|
PyMutex_Unlock(&runtime->audit_hooks.mutex);
|
||||||
}
|
|
||||||
else {
|
|
||||||
PyThread_acquire_lock(runtime->audit_hooks.mutex, WAIT_LOCK);
|
|
||||||
add_audit_hook_entry_unlocked(runtime, e);
|
|
||||||
PyThread_release_lock(runtime->audit_hooks.mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue