Skip to content

Commit 878803e

Browse files
committed
Add PyThreadState_EnsureFromView().
1 parent b9d3bc8 commit 878803e

2 files changed

Lines changed: 58 additions & 13 deletions

File tree

Include/cpython/pystate.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,7 @@ struct _ts {
239239
// structure and all share the same per-interpreter structure).
240240
PyStats *pystats;
241241
#endif
242+
242243
struct {
243244
/* Number of nested PyThreadState_Ensure() calls on this thread state */
244245
Py_ssize_t counter;
@@ -248,6 +249,9 @@ struct _ts {
248249
249250
This is only true for thread states created by PyThreadState_Ensure() */
250251
int delete_on_release;
252+
253+
/* The interpreter guard owned by PyThreadState_EnsureFromView(), if any. */
254+
PyInterpreterGuard *owned_guard;
251255
} ensure;
252256
};
253257

Python/pystate.c

Lines changed: 54 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3348,11 +3348,13 @@ try_acquire_interp_guard(PyInterpreterState *interp)
33483348
{
33493349
assert(interp != NULL);
33503350
_PyRWMutex_RLock(&interp->finalization_guards.lock);
3351+
33513352
if (_PyInterpreterState_GetFinalizing(interp) != NULL) {
33523353
_PyRWMutex_RUnlock(&interp->finalization_guards.lock);
33533354
assert(_Py_atomic_load_ssize_relaxed(&interp->finalization_guards.countdown) == 0);
33543355
return NULL;
33553356
}
3357+
33563358
_Py_atomic_add_ssize(&interp->finalization_guards.countdown, 1);
33573359
_PyRWMutex_RUnlock(&interp->finalization_guards.lock);
33583360
return (PyInterpreterGuard *)interp;
@@ -3363,12 +3365,14 @@ PyInterpreterGuard_FromCurrent(void)
33633365
{
33643366
PyInterpreterState *interp = _PyInterpreterState_GET();
33653367
assert(interp != NULL);
3368+
33663369
PyInterpreterGuard *guard = try_acquire_interp_guard(interp);
33673370
if (guard == NULL) {
33683371
PyErr_SetString(PyExc_PythonFinalizationError,
33693372
"cannot acquire finalization guard anymore");
33703373
return NULL;
33713374
}
3375+
33723376
return guard;
33733377
}
33743378

@@ -3377,9 +3381,11 @@ PyInterpreterGuard_Close(PyInterpreterGuard *guard)
33773381
{
33783382
PyInterpreterState *interp = guard->interp;
33793383
assert(interp != NULL);
3384+
33803385
_PyRWMutex_RLock(&interp->finalization_guards.lock);
33813386
Py_ssize_t old = _Py_atomic_add_ssize(&interp->finalization_guards.countdown, -1);
33823387
_PyRWMutex_RUnlock(&interp->finalization_guards.lock);
3388+
33833389
assert(old > 0);
33843390
if (old <= 0) {
33853391
Py_FatalError("interpreter has negative guard count, likely due"
@@ -3392,13 +3398,15 @@ PyInterpreterView_FromCurrent(void)
33923398
{
33933399
PyInterpreterState *interp = _PyInterpreterState_GET();
33943400
assert(interp != NULL);
3395-
/* PyInterpreterView_Close() can be called without an attached thread
3396-
state, so we have to use the raw allocator. */
3401+
3402+
// PyInterpreterView_Close() can be called without an attached thread
3403+
// state, so we have to use the raw allocator.
33973404
PyInterpreterView *view = PyMem_RawMalloc(sizeof(PyInterpreterView));
33983405
if (view == NULL) {
33993406
PyErr_NoMemory();
34003407
return NULL;
34013408
}
3409+
34023410
view->refcount = 1;
34033411
view->id = interp->id;
34043412
return view;
@@ -3420,7 +3428,8 @@ PyInterpreterGuard_FromView(PyInterpreterView *view)
34203428
assert(view != NULL);
34213429
int64_t interp_id = view->id;
34223430
assert(interp_id >= 0);
3423-
/* Interpreters cannot be deleted while we hold the runtime lock. */
3431+
3432+
// Interpreters cannot be deleted while we hold the runtime lock.
34243433
_PyRuntimeState *runtime = &_PyRuntime;
34253434
HEAD_LOCK(runtime);
34263435
PyInterpreterState *interp = interp_look_up_id(runtime, interp_id);
@@ -3497,6 +3506,31 @@ PyThreadState_Ensure(PyInterpreterGuard *guard)
34973506
return (PyThreadState *)&NO_TSTATE_SENTINEL;
34983507
}
34993508

3509+
PyThreadState *
3510+
PyThreadState_EnsureFromView(PyInterpreterView *view)
3511+
{
3512+
assert(view != NULL);
3513+
PyInterpreterGuard *guard = PyInterpreterGuard_FromView(view);
3514+
if (guard == NULL) {
3515+
return NULL;
3516+
}
3517+
3518+
PyThreadState *tstate = PyThreadState_Ensure(guard);
3519+
if (tstate == NULL) {
3520+
PyInterpreterGuard_Close(guard);
3521+
return NULL;
3522+
}
3523+
3524+
if (tstate->ensure.owned_guard != NULL) {
3525+
assert(tstate->ensure.owned_guard->interp == guard->interp);
3526+
PyInterpreterGuard_Close(guard);
3527+
} else {
3528+
tstate->ensure.owned_guard = guard;
3529+
}
3530+
3531+
return tstate;
3532+
}
3533+
35003534
void
35013535
PyThreadState_Release(PyThreadState *old_tstate)
35023536
{
@@ -3506,23 +3540,30 @@ PyThreadState_Release(PyThreadState *old_tstate)
35063540
if (remaining < 0) {
35073541
Py_FatalError("PyThreadState_Release() called more times than PyThreadState_Ensure()");
35083542
}
3509-
// The thread view might be NULL
3543+
3544+
if (remaining != 0) {
3545+
return;
3546+
}
3547+
35103548
PyThreadState *to_restore;
35113549
if (old_tstate == (PyThreadState *)&NO_TSTATE_SENTINEL) {
35123550
to_restore = NULL;
35133551
}
35143552
else {
35153553
to_restore = old_tstate;
35163554
}
3517-
if (remaining == 0) {
3518-
if (tstate->ensure.delete_on_release) {
3519-
PyThreadState_Clear(tstate);
3520-
PyThreadState_Swap(to_restore);
3521-
PyThreadState_Delete(tstate);
3522-
} else {
3523-
PyThreadState_Swap(to_restore);
3524-
}
3555+
3556+
assert(tstate->ensure.delete_on_release == 1 || tstate->ensure.delete_on_release == 0);
3557+
if (tstate->ensure.delete_on_release) {
3558+
PyThreadState_Clear(tstate);
3559+
PyThreadState_Swap(to_restore);
3560+
PyThreadState_Delete(tstate);
3561+
} else {
3562+
PyThreadState_Swap(to_restore);
35253563
}
35263564

3527-
return;
3565+
if (tstate->ensure.owned_guard != NULL) {
3566+
PyInterpreterGuard_Close(tstate->ensure.owned_guard);
3567+
tstate->ensure.owned_guard = NULL;
3568+
}
35283569
}

0 commit comments

Comments
 (0)