gh-111924: use atomics for interp id refcounting (#125321)

This commit is contained in:
Kumar Aditya 2024-10-12 12:40:34 +05:30 committed by GitHub
parent 5a074aab84
commit 5d8739e956
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 8 additions and 52 deletions

View File

@ -102,9 +102,8 @@ struct _is {
PyInterpreterState *next; PyInterpreterState *next;
int64_t id; int64_t id;
int64_t id_refcount; Py_ssize_t id_refcount;
int requires_idref; int requires_idref;
PyThread_type_lock id_mutex;
#define _PyInterpreterState_WHENCE_NOTSET -1 #define _PyInterpreterState_WHENCE_NOTSET -1
#define _PyInterpreterState_WHENCE_UNKNOWN 0 #define _PyInterpreterState_WHENCE_UNKNOWN 0
@ -318,8 +317,7 @@ _PyInterpreterState_SetFinalizing(PyInterpreterState *interp, PyThreadState *tst
PyAPI_FUNC(int64_t) _PyInterpreterState_ObjectToID(PyObject *); PyAPI_FUNC(int64_t) _PyInterpreterState_ObjectToID(PyObject *);
PyAPI_FUNC(PyInterpreterState *) _PyInterpreterState_LookUpID(int64_t); PyAPI_FUNC(PyInterpreterState *) _PyInterpreterState_LookUpID(int64_t);
PyAPI_FUNC(PyInterpreterState *) _PyInterpreterState_LookUpIDObject(PyObject *); PyAPI_FUNC(PyInterpreterState *) _PyInterpreterState_LookUpIDObject(PyObject *);
PyAPI_FUNC(int) _PyInterpreterState_IDInitref(PyInterpreterState *); PyAPI_FUNC(void) _PyInterpreterState_IDIncref(PyInterpreterState *);
PyAPI_FUNC(int) _PyInterpreterState_IDIncref(PyInterpreterState *);
PyAPI_FUNC(void) _PyInterpreterState_IDDecref(PyInterpreterState *); PyAPI_FUNC(void) _PyInterpreterState_IDDecref(PyInterpreterState *);
PyAPI_FUNC(int) _PyInterpreterState_IsReady(PyInterpreterState *interp); PyAPI_FUNC(int) _PyInterpreterState_IsReady(PyInterpreterState *interp);

View File

@ -523,12 +523,6 @@ _PyRuntimeState_ReInitThreads(_PyRuntimeState *runtime)
_PyTypes_AfterFork(); _PyTypes_AfterFork();
/* bpo-42540: id_mutex is freed by _PyInterpreterState_Delete, which does
* not force the default allocator. */
if (_PyThread_at_fork_reinit(&runtime->interpreters.main->id_mutex) < 0) {
return _PyStatus_ERR("Failed to reinitialize runtime locks");
}
PyStatus status = gilstate_tss_reinit(runtime); PyStatus status = gilstate_tss_reinit(runtime);
if (_PyStatus_EXCEPTION(status)) { if (_PyStatus_EXCEPTION(status)) {
return status; return status;
@ -629,6 +623,8 @@ init_interpreter(PyInterpreterState *interp,
assert(id > 0 || (id == 0 && interp == runtime->interpreters.main)); assert(id > 0 || (id == 0 && interp == runtime->interpreters.main));
interp->id = id; interp->id = id;
interp->id_refcount = 0;
assert(runtime->interpreters.head == interp); assert(runtime->interpreters.head == interp);
assert(next != NULL || (interp == runtime->interpreters.main)); assert(next != NULL || (interp == runtime->interpreters.main));
interp->next = next; interp->next = next;
@ -989,10 +985,6 @@ PyInterpreterState_Delete(PyInterpreterState *interp)
} }
HEAD_UNLOCK(runtime); HEAD_UNLOCK(runtime);
if (interp->id_mutex != NULL) {
PyThread_free_lock(interp->id_mutex);
}
_Py_qsbr_fini(interp); _Py_qsbr_fini(interp);
_PyObject_FiniState(interp); _PyObject_FiniState(interp);
@ -1031,9 +1023,6 @@ _PyInterpreterState_DeleteExceptMain(_PyRuntimeState *runtime)
// the "current" tstate to be set? // the "current" tstate to be set?
PyInterpreterState_Clear(interp); // XXX must activate? PyInterpreterState_Clear(interp); // XXX must activate?
zapthreads(interp); zapthreads(interp);
if (interp->id_mutex != NULL) {
PyThread_free_lock(interp->id_mutex);
}
PyInterpreterState *prev_interp = interp; PyInterpreterState *prev_interp = interp;
interp = interp->next; interp = interp->next;
free_interpreter(prev_interp); free_interpreter(prev_interp);
@ -1247,9 +1236,6 @@ PyInterpreterState_GetID(PyInterpreterState *interp)
PyObject * PyObject *
_PyInterpreterState_GetIDObject(PyInterpreterState *interp) _PyInterpreterState_GetIDObject(PyInterpreterState *interp)
{ {
if (_PyInterpreterState_IDInitref(interp) != 0) {
return NULL;
};
int64_t interpid = interp->id; int64_t interpid = interp->id;
if (interpid < 0) { if (interpid < 0) {
return NULL; return NULL;
@ -1259,50 +1245,22 @@ _PyInterpreterState_GetIDObject(PyInterpreterState *interp)
} }
int
_PyInterpreterState_IDInitref(PyInterpreterState *interp)
{
if (interp->id_mutex != NULL) {
return 0;
}
interp->id_mutex = PyThread_allocate_lock();
if (interp->id_mutex == NULL) {
PyErr_SetString(PyExc_RuntimeError,
"failed to create init interpreter ID mutex");
return -1;
}
interp->id_refcount = 0;
return 0;
}
void
int
_PyInterpreterState_IDIncref(PyInterpreterState *interp) _PyInterpreterState_IDIncref(PyInterpreterState *interp)
{ {
if (_PyInterpreterState_IDInitref(interp) < 0) { _Py_atomic_add_ssize(&interp->id_refcount, 1);
return -1;
}
PyThread_acquire_lock(interp->id_mutex, WAIT_LOCK);
interp->id_refcount += 1;
PyThread_release_lock(interp->id_mutex);
return 0;
} }
void void
_PyInterpreterState_IDDecref(PyInterpreterState *interp) _PyInterpreterState_IDDecref(PyInterpreterState *interp)
{ {
assert(interp->id_mutex != NULL);
_PyRuntimeState *runtime = interp->runtime; _PyRuntimeState *runtime = interp->runtime;
PyThread_acquire_lock(interp->id_mutex, WAIT_LOCK); Py_ssize_t refcount = _Py_atomic_add_ssize(&interp->id_refcount, -1);
assert(interp->id_refcount != 0);
interp->id_refcount -= 1;
int64_t refcount = interp->id_refcount;
PyThread_release_lock(interp->id_mutex);
if (refcount == 0 && interp->requires_idref) { if (refcount == 1 && interp->requires_idref) {
PyThreadState *tstate = PyThreadState *tstate =
_PyThreadState_NewBound(interp, _PyThreadState_WHENCE_FINI); _PyThreadState_NewBound(interp, _PyThreadState_WHENCE_FINI);