Skip to content

Commit 52e9b38

Browse files
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.
1 parent 23cf1e2 commit 52e9b38

File tree

1 file changed

+48
-60
lines changed

1 file changed

+48
-60
lines changed

Python/pystate.c

Lines changed: 48 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -354,47 +354,29 @@ _Py_COMP_DIAG_IGNORE_DEPR_DECLS
354354
static const _PyRuntimeState initial = _PyRuntimeState_INIT(_PyRuntime);
355355
_Py_COMP_DIAG_POP
356356

357+
#define NUMLOCKS 4
358+
357359
static int
358-
alloc_for_runtime(PyThread_type_lock *plock1, PyThread_type_lock *plock2,
359-
PyThread_type_lock *plock3, PyThread_type_lock *plock4)
360+
alloc_for_runtime(PyThread_type_lock locks[NUMLOCKS])
360361
{
361362
/* Force default allocator, since _PyRuntimeState_Fini() must
362363
use the same allocator than this function. */
363364
PyMemAllocatorEx old_alloc;
364365
_PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
365366

366-
PyThread_type_lock lock1 = PyThread_allocate_lock();
367-
if (lock1 == NULL) {
368-
return -1;
369-
}
370-
371-
PyThread_type_lock lock2 = PyThread_allocate_lock();
372-
if (lock2 == NULL) {
373-
PyThread_free_lock(lock1);
374-
return -1;
375-
}
376-
377-
PyThread_type_lock lock3 = PyThread_allocate_lock();
378-
if (lock3 == NULL) {
379-
PyThread_free_lock(lock1);
380-
PyThread_free_lock(lock2);
381-
return -1;
382-
}
383-
384-
PyThread_type_lock lock4 = PyThread_allocate_lock();
385-
if (lock4 == NULL) {
386-
PyThread_free_lock(lock1);
387-
PyThread_free_lock(lock2);
388-
PyThread_free_lock(lock3);
389-
return -1;
367+
for (int i = 0; i < NUMLOCKS; i++) {
368+
PyThread_type_lock lock = PyThread_allocate_lock();
369+
if (lock == NULL) {
370+
for (int j = 0; j < i; j++) {
371+
PyThread_free_lock(locks[j]);
372+
locks[j] = NULL;
373+
}
374+
break;
375+
}
376+
locks[i] = lock;
390377
}
391378

392379
PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
393-
394-
*plock1 = lock1;
395-
*plock2 = lock2;
396-
*plock3 = lock3;
397-
*plock4 = lock4;
398380
return 0;
399381
}
400382

@@ -403,10 +385,7 @@ init_runtime(_PyRuntimeState *runtime,
403385
void *open_code_hook, void *open_code_userdata,
404386
_Py_AuditHookEntry *audit_hook_head,
405387
Py_ssize_t unicode_next_index,
406-
PyThread_type_lock unicode_ids_mutex,
407-
PyThread_type_lock interpreters_mutex,
408-
PyThread_type_lock xidregistry_mutex,
409-
PyThread_type_lock getargs_mutex)
388+
PyThread_type_lock locks[NUMLOCKS])
410389
{
411390
if (runtime->_initialized) {
412391
Py_FatalError("runtime already initialized");
@@ -424,17 +403,21 @@ init_runtime(_PyRuntimeState *runtime,
424403

425404
PyPreConfig_InitPythonConfig(&runtime->preconfig);
426405

427-
runtime->interpreters.mutex = interpreters_mutex;
428-
429-
runtime->xidregistry.mutex = xidregistry_mutex;
430-
431-
runtime->getargs.mutex = getargs_mutex;
406+
PyThread_type_lock *lockptrs[NUMLOCKS] = {
407+
&runtime->interpreters.mutex,
408+
&runtime->xidregistry.mutex,
409+
&runtime->getargs.mutex,
410+
&runtime->unicode_state.ids.lock,
411+
};
412+
for (int i = 0; i < NUMLOCKS; i++) {
413+
assert(locks[i] != NULL);
414+
*lockptrs[i] = locks[i];
415+
}
432416

433417
// Set it to the ID of the main thread of the main interpreter.
434418
runtime->main_thread = PyThread_get_thread_ident();
435419

436420
runtime->unicode_state.ids.next_index = unicode_next_index;
437-
runtime->unicode_state.ids.lock = unicode_ids_mutex;
438421

439422
runtime->_initialized = 1;
440423
}
@@ -452,8 +435,8 @@ _PyRuntimeState_Init(_PyRuntimeState *runtime)
452435
// is called multiple times.
453436
Py_ssize_t unicode_next_index = runtime->unicode_state.ids.next_index;
454437

455-
PyThread_type_lock lock1, lock2, lock3, lock4;
456-
if (alloc_for_runtime(&lock1, &lock2, &lock3, &lock4) != 0) {
438+
PyThread_type_lock locks[NUMLOCKS];
439+
if (alloc_for_runtime(locks) != 0) {
457440
return _PyStatus_NO_MEMORY();
458441
}
459442

@@ -474,7 +457,7 @@ _PyRuntimeState_Init(_PyRuntimeState *runtime)
474457
}
475458

476459
init_runtime(runtime, open_code_hook, open_code_userdata, audit_hook_head,
477-
unicode_next_index, lock1, lock2, lock3, lock4);
460+
unicode_next_index, locks);
478461

479462
return _PyStatus_OK();
480463
}
@@ -504,10 +487,15 @@ _PyRuntimeState_Fini(_PyRuntimeState *runtime)
504487
LOCK = NULL; \
505488
}
506489

507-
FREE_LOCK(runtime->interpreters.mutex);
508-
FREE_LOCK(runtime->xidregistry.mutex);
509-
FREE_LOCK(runtime->unicode_state.ids.lock);
510-
FREE_LOCK(runtime->getargs.mutex);
490+
PyThread_type_lock *lockptrs[NUMLOCKS] = {
491+
&runtime->interpreters.mutex,
492+
&runtime->xidregistry.mutex,
493+
&runtime->getargs.mutex,
494+
&runtime->unicode_state.ids.lock,
495+
};
496+
for (int i = 0; i < NUMLOCKS; i++) {
497+
FREE_LOCK(*lockptrs[i]);
498+
}
511499

512500
#undef FREE_LOCK
513501
PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
@@ -527,25 +515,25 @@ _PyRuntimeState_ReInitThreads(_PyRuntimeState *runtime)
527515
PyMemAllocatorEx old_alloc;
528516
_PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
529517

530-
int reinit_interp = _PyThread_at_fork_reinit(&runtime->interpreters.mutex);
531-
int reinit_xidregistry = _PyThread_at_fork_reinit(&runtime->xidregistry.mutex);
532-
int reinit_unicode_ids = _PyThread_at_fork_reinit(&runtime->unicode_state.ids.lock);
533-
int reinit_getargs = _PyThread_at_fork_reinit(&runtime->getargs.mutex);
518+
PyThread_type_lock *lockptrs[NUMLOCKS] = {
519+
&runtime->interpreters.mutex,
520+
&runtime->xidregistry.mutex,
521+
&runtime->getargs.mutex,
522+
&runtime->unicode_state.ids.lock,
523+
};
524+
int reinit_err = 0;
525+
for (int i = 0; i < NUMLOCKS; i++) {
526+
reinit_err += _PyThread_at_fork_reinit(lockptrs[i]);
527+
}
534528

535529
PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
536530

537531
/* bpo-42540: id_mutex is freed by _PyInterpreterState_Delete, which does
538532
* not force the default allocator. */
539-
int reinit_main_id = _PyThread_at_fork_reinit(&runtime->interpreters.main->id_mutex);
533+
reinit_err += _PyThread_at_fork_reinit(&runtime->interpreters.main->id_mutex);
540534

541-
if (reinit_interp < 0
542-
|| reinit_main_id < 0
543-
|| reinit_xidregistry < 0
544-
|| reinit_unicode_ids < 0
545-
|| reinit_getargs < 0)
546-
{
535+
if (reinit_err < 0) {
547536
return _PyStatus_ERR("Failed to reinitialize runtime locks");
548-
549537
}
550538

551539
PyStatus status = gilstate_tss_reinit(runtime);

0 commit comments

Comments
 (0)