gh-100227: Use an Array for _PyRuntime's Set of Locks During Init (gh-103315)

This cleans things up a bit and simplifies adding new granular global locks.
This commit is contained in:
Eric Snow 2023-04-06 12:00:49 -06:00 committed by GitHub
parent 23cf1e20a6
commit 52e9b389a8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 48 additions and 60 deletions

View File

@ -354,47 +354,29 @@ _Py_COMP_DIAG_IGNORE_DEPR_DECLS
static const _PyRuntimeState initial = _PyRuntimeState_INIT(_PyRuntime);
_Py_COMP_DIAG_POP
#define NUMLOCKS 4
static int
alloc_for_runtime(PyThread_type_lock *plock1, PyThread_type_lock *plock2,
PyThread_type_lock *plock3, PyThread_type_lock *plock4)
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);
PyThread_type_lock lock1 = PyThread_allocate_lock();
if (lock1 == NULL) {
return -1;
}
PyThread_type_lock lock2 = PyThread_allocate_lock();
if (lock2 == NULL) {
PyThread_free_lock(lock1);
return -1;
}
PyThread_type_lock lock3 = PyThread_allocate_lock();
if (lock3 == NULL) {
PyThread_free_lock(lock1);
PyThread_free_lock(lock2);
return -1;
}
PyThread_type_lock lock4 = PyThread_allocate_lock();
if (lock4 == NULL) {
PyThread_free_lock(lock1);
PyThread_free_lock(lock2);
PyThread_free_lock(lock3);
return -1;
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);
*plock1 = lock1;
*plock2 = lock2;
*plock3 = lock3;
*plock4 = lock4;
return 0;
}
@ -403,10 +385,7 @@ init_runtime(_PyRuntimeState *runtime,
void *open_code_hook, void *open_code_userdata,
_Py_AuditHookEntry *audit_hook_head,
Py_ssize_t unicode_next_index,
PyThread_type_lock unicode_ids_mutex,
PyThread_type_lock interpreters_mutex,
PyThread_type_lock xidregistry_mutex,
PyThread_type_lock getargs_mutex)
PyThread_type_lock locks[NUMLOCKS])
{
if (runtime->_initialized) {
Py_FatalError("runtime already initialized");
@ -424,17 +403,21 @@ init_runtime(_PyRuntimeState *runtime,
PyPreConfig_InitPythonConfig(&runtime->preconfig);
runtime->interpreters.mutex = interpreters_mutex;
runtime->xidregistry.mutex = xidregistry_mutex;
runtime->getargs.mutex = getargs_mutex;
PyThread_type_lock *lockptrs[NUMLOCKS] = {
&runtime->interpreters.mutex,
&runtime->xidregistry.mutex,
&runtime->getargs.mutex,
&runtime->unicode_state.ids.lock,
};
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.
runtime->main_thread = PyThread_get_thread_ident();
runtime->unicode_state.ids.next_index = unicode_next_index;
runtime->unicode_state.ids.lock = unicode_ids_mutex;
runtime->_initialized = 1;
}
@ -452,8 +435,8 @@ _PyRuntimeState_Init(_PyRuntimeState *runtime)
// is called multiple times.
Py_ssize_t unicode_next_index = runtime->unicode_state.ids.next_index;
PyThread_type_lock lock1, lock2, lock3, lock4;
if (alloc_for_runtime(&lock1, &lock2, &lock3, &lock4) != 0) {
PyThread_type_lock locks[NUMLOCKS];
if (alloc_for_runtime(locks) != 0) {
return _PyStatus_NO_MEMORY();
}
@ -474,7 +457,7 @@ _PyRuntimeState_Init(_PyRuntimeState *runtime)
}
init_runtime(runtime, open_code_hook, open_code_userdata, audit_hook_head,
unicode_next_index, lock1, lock2, lock3, lock4);
unicode_next_index, locks);
return _PyStatus_OK();
}
@ -504,10 +487,15 @@ _PyRuntimeState_Fini(_PyRuntimeState *runtime)
LOCK = NULL; \
}
FREE_LOCK(runtime->interpreters.mutex);
FREE_LOCK(runtime->xidregistry.mutex);
FREE_LOCK(runtime->unicode_state.ids.lock);
FREE_LOCK(runtime->getargs.mutex);
PyThread_type_lock *lockptrs[NUMLOCKS] = {
&runtime->interpreters.mutex,
&runtime->xidregistry.mutex,
&runtime->getargs.mutex,
&runtime->unicode_state.ids.lock,
};
for (int i = 0; i < NUMLOCKS; i++) {
FREE_LOCK(*lockptrs[i]);
}
#undef FREE_LOCK
PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
@ -527,25 +515,25 @@ _PyRuntimeState_ReInitThreads(_PyRuntimeState *runtime)
PyMemAllocatorEx old_alloc;
_PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
int reinit_interp = _PyThread_at_fork_reinit(&runtime->interpreters.mutex);
int reinit_xidregistry = _PyThread_at_fork_reinit(&runtime->xidregistry.mutex);
int reinit_unicode_ids = _PyThread_at_fork_reinit(&runtime->unicode_state.ids.lock);
int reinit_getargs = _PyThread_at_fork_reinit(&runtime->getargs.mutex);
PyThread_type_lock *lockptrs[NUMLOCKS] = {
&runtime->interpreters.mutex,
&runtime->xidregistry.mutex,
&runtime->getargs.mutex,
&runtime->unicode_state.ids.lock,
};
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);
/* bpo-42540: id_mutex is freed by _PyInterpreterState_Delete, which does
* not force the default allocator. */
int reinit_main_id = _PyThread_at_fork_reinit(&runtime->interpreters.main->id_mutex);
reinit_err += _PyThread_at_fork_reinit(&runtime->interpreters.main->id_mutex);
if (reinit_interp < 0
|| reinit_main_id < 0
|| reinit_xidregistry < 0
|| reinit_unicode_ids < 0
|| reinit_getargs < 0)
{
if (reinit_err < 0) {
return _PyStatus_ERR("Failed to reinitialize runtime locks");
}
PyStatus status = gilstate_tss_reinit(runtime);