Skip to content

Commit 5d8739e

Browse files
pythongh-111924: use atomics for interp id refcounting (python#125321)
1 parent 5a074aa commit 5d8739e

File tree

2 files changed

+8
-52
lines changed

2 files changed

+8
-52
lines changed

Include/internal/pycore_interp.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,8 @@ struct _is {
102102
PyInterpreterState *next;
103103

104104
int64_t id;
105-
int64_t id_refcount;
105+
Py_ssize_t id_refcount;
106106
int requires_idref;
107-
PyThread_type_lock id_mutex;
108107

109108
#define _PyInterpreterState_WHENCE_NOTSET -1
110109
#define _PyInterpreterState_WHENCE_UNKNOWN 0
@@ -318,8 +317,7 @@ _PyInterpreterState_SetFinalizing(PyInterpreterState *interp, PyThreadState *tst
318317
PyAPI_FUNC(int64_t) _PyInterpreterState_ObjectToID(PyObject *);
319318
PyAPI_FUNC(PyInterpreterState *) _PyInterpreterState_LookUpID(int64_t);
320319
PyAPI_FUNC(PyInterpreterState *) _PyInterpreterState_LookUpIDObject(PyObject *);
321-
PyAPI_FUNC(int) _PyInterpreterState_IDInitref(PyInterpreterState *);
322-
PyAPI_FUNC(int) _PyInterpreterState_IDIncref(PyInterpreterState *);
320+
PyAPI_FUNC(void) _PyInterpreterState_IDIncref(PyInterpreterState *);
323321
PyAPI_FUNC(void) _PyInterpreterState_IDDecref(PyInterpreterState *);
324322

325323
PyAPI_FUNC(int) _PyInterpreterState_IsReady(PyInterpreterState *interp);

Python/pystate.c

Lines changed: 6 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -523,12 +523,6 @@ _PyRuntimeState_ReInitThreads(_PyRuntimeState *runtime)
523523

524524
_PyTypes_AfterFork();
525525

526-
/* bpo-42540: id_mutex is freed by _PyInterpreterState_Delete, which does
527-
* not force the default allocator. */
528-
if (_PyThread_at_fork_reinit(&runtime->interpreters.main->id_mutex) < 0) {
529-
return _PyStatus_ERR("Failed to reinitialize runtime locks");
530-
}
531-
532526
PyStatus status = gilstate_tss_reinit(runtime);
533527
if (_PyStatus_EXCEPTION(status)) {
534528
return status;
@@ -629,6 +623,8 @@ init_interpreter(PyInterpreterState *interp,
629623
assert(id > 0 || (id == 0 && interp == runtime->interpreters.main));
630624
interp->id = id;
631625

626+
interp->id_refcount = 0;
627+
632628
assert(runtime->interpreters.head == interp);
633629
assert(next != NULL || (interp == runtime->interpreters.main));
634630
interp->next = next;
@@ -989,10 +985,6 @@ PyInterpreterState_Delete(PyInterpreterState *interp)
989985
}
990986
HEAD_UNLOCK(runtime);
991987

992-
if (interp->id_mutex != NULL) {
993-
PyThread_free_lock(interp->id_mutex);
994-
}
995-
996988
_Py_qsbr_fini(interp);
997989

998990
_PyObject_FiniState(interp);
@@ -1031,9 +1023,6 @@ _PyInterpreterState_DeleteExceptMain(_PyRuntimeState *runtime)
10311023
// the "current" tstate to be set?
10321024
PyInterpreterState_Clear(interp); // XXX must activate?
10331025
zapthreads(interp);
1034-
if (interp->id_mutex != NULL) {
1035-
PyThread_free_lock(interp->id_mutex);
1036-
}
10371026
PyInterpreterState *prev_interp = interp;
10381027
interp = interp->next;
10391028
free_interpreter(prev_interp);
@@ -1247,9 +1236,6 @@ PyInterpreterState_GetID(PyInterpreterState *interp)
12471236
PyObject *
12481237
_PyInterpreterState_GetIDObject(PyInterpreterState *interp)
12491238
{
1250-
if (_PyInterpreterState_IDInitref(interp) != 0) {
1251-
return NULL;
1252-
};
12531239
int64_t interpid = interp->id;
12541240
if (interpid < 0) {
12551241
return NULL;
@@ -1259,50 +1245,22 @@ _PyInterpreterState_GetIDObject(PyInterpreterState *interp)
12591245
}
12601246

12611247

1262-
int
1263-
_PyInterpreterState_IDInitref(PyInterpreterState *interp)
1264-
{
1265-
if (interp->id_mutex != NULL) {
1266-
return 0;
1267-
}
1268-
interp->id_mutex = PyThread_allocate_lock();
1269-
if (interp->id_mutex == NULL) {
1270-
PyErr_SetString(PyExc_RuntimeError,
1271-
"failed to create init interpreter ID mutex");
1272-
return -1;
1273-
}
1274-
interp->id_refcount = 0;
1275-
return 0;
1276-
}
1277-
12781248

1279-
int
1249+
void
12801250
_PyInterpreterState_IDIncref(PyInterpreterState *interp)
12811251
{
1282-
if (_PyInterpreterState_IDInitref(interp) < 0) {
1283-
return -1;
1284-
}
1285-
1286-
PyThread_acquire_lock(interp->id_mutex, WAIT_LOCK);
1287-
interp->id_refcount += 1;
1288-
PyThread_release_lock(interp->id_mutex);
1289-
return 0;
1252+
_Py_atomic_add_ssize(&interp->id_refcount, 1);
12901253
}
12911254

12921255

12931256
void
12941257
_PyInterpreterState_IDDecref(PyInterpreterState *interp)
12951258
{
1296-
assert(interp->id_mutex != NULL);
12971259
_PyRuntimeState *runtime = interp->runtime;
12981260

1299-
PyThread_acquire_lock(interp->id_mutex, WAIT_LOCK);
1300-
assert(interp->id_refcount != 0);
1301-
interp->id_refcount -= 1;
1302-
int64_t refcount = interp->id_refcount;
1303-
PyThread_release_lock(interp->id_mutex);
1261+
Py_ssize_t refcount = _Py_atomic_add_ssize(&interp->id_refcount, -1);
13041262

1305-
if (refcount == 0 && interp->requires_idref) {
1263+
if (refcount == 1 && interp->requires_idref) {
13061264
PyThreadState *tstate =
13071265
_PyThreadState_NewBound(interp, _PyThreadState_WHENCE_FINI);
13081266

0 commit comments

Comments
 (0)