Skip to content

Commit d661578

Browse files
committed
Updates for the new proposal.
1 parent 71e1aec commit d661578

File tree

4 files changed

+98
-31
lines changed

4 files changed

+98
-31
lines changed

Include/cpython/pystate.h

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -270,32 +270,39 @@ PyAPI_FUNC(void) _PyInterpreterState_SetEvalFrameFunc(
270270

271271
typedef uintptr_t PyInterpreterRef;
272272

273-
PyAPI_FUNC(PyInterpreterRef) PyInterpreterRef_Get(void);
273+
PyAPI_FUNC(int) PyInterpreterRef_Get(PyInterpreterRef *ptr);
274274
PyAPI_FUNC(PyInterpreterRef) PyInterpreterRef_Dup(PyInterpreterRef ref);
275-
PyAPI_FUNC(int) PyInterpreterState_AsStrong(PyInterpreterState *interp, PyInterpreterRef *strong_ptr);
275+
PyAPI_FUNC(int) PyInterpreterRef_Main(PyInterpreterRef *strong_ptr);
276276
PyAPI_FUNC(void) PyInterpreterRef_Close(PyInterpreterRef ref);
277277
PyAPI_FUNC(PyInterpreterState *) PyInterpreterRef_AsInterpreter(PyInterpreterRef ref);
278278

279279
#define PyInterpreterRef_Close(ref) do { \
280280
PyInterpreterRef_Close(ref); \
281281
ref = 0; \
282-
} while (0); \
282+
} while (0);
283283

284284
/* Weak interpreter references */
285285

286286
typedef struct _interpreter_weakref {
287287
int64_t id;
288288
Py_ssize_t refcount;
289-
} PyInterpreterWeakRef;
289+
} _PyInterpreterWeakRef;
290290

291-
PyAPI_FUNC(PyInterpreterWeakRef) PyInterpreterWeakRef_Get(void);
291+
typedef _PyInterpreterWeakRef *PyInterpreterWeakRef;
292+
293+
PyAPI_FUNC(int) PyInterpreterWeakRef_Get(PyInterpreterWeakRef *ptr);
292294
PyAPI_FUNC(PyInterpreterWeakRef) PyInterpreterWeakRef_Dup(PyInterpreterWeakRef wref);
293295
PyAPI_FUNC(int) PyInterpreterWeakRef_AsStrong(PyInterpreterWeakRef wref, PyInterpreterRef *strong_ptr);
294296
PyAPI_FUNC(void) PyInterpreterWeakRef_Close(PyInterpreterWeakRef wref);
295297

298+
#define PyInterpreterWeakRef_Close(ref) do { \
299+
PyInterpreterWeakRef_Close(ref); \
300+
ref = 0; \
301+
} while (0);
302+
296303
// Exports for '_testcapi' shared extension
297304
PyAPI_FUNC(Py_ssize_t) _PyInterpreterState_Refcount(PyInterpreterState *interp);
298-
PyAPI_FUNC(void) _PyInterpreterState_Incref(PyInterpreterState *interp);
305+
PyAPI_FUNC(int) _PyInterpreterState_Incref(PyInterpreterState *interp);
299306

300307
PyAPI_FUNC(int) PyThreadState_Ensure(PyInterpreterRef interp_ref);
301308

Modules/_testcapimodule.c

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2546,6 +2546,16 @@ toggle_reftrace_printer(PyObject *ob, PyObject *arg)
25462546
Py_RETURN_NONE;
25472547
}
25482548

2549+
static PyInterpreterRef
2550+
get_strong_ref(void)
2551+
{
2552+
PyInterpreterRef ref;
2553+
if (PyInterpreterRef_Get(&ref) < 0) {
2554+
Py_FatalError("strong reference should not have failed");
2555+
}
2556+
return ref;
2557+
}
2558+
25492559
static PyObject *
25502560
test_interp_refcount(PyObject *self, PyObject *unused)
25512561
{
@@ -2555,16 +2565,16 @@ test_interp_refcount(PyObject *self, PyObject *unused)
25552565

25562566
// Reference counts are technically 0 by default
25572567
assert(_PyInterpreterState_Refcount(interp) == 0);
2558-
ref1 = PyInterpreterRef_Get();
2568+
ref1 = get_strong_ref();
25592569
assert(_PyInterpreterState_Refcount(interp) == 1);
2560-
ref2 = PyInterpreterRef_Get();
2570+
ref2 = get_strong_ref();
25612571
assert(_PyInterpreterState_Refcount(interp) == 2);
25622572
PyInterpreterRef_Close(ref1);
25632573
assert(_PyInterpreterState_Refcount(interp) == 1);
25642574
PyInterpreterRef_Close(ref2);
25652575
assert(_PyInterpreterState_Refcount(interp) == 0);
25662576

2567-
ref1 = PyInterpreterRef_Get();
2577+
ref1 = get_strong_ref();
25682578
ref2 = PyInterpreterRef_Dup(ref1);
25692579
assert(_PyInterpreterState_Refcount(interp) == 2);
25702580
assert(PyInterpreterRef_AsInterpreter(ref1) == interp);
@@ -2580,7 +2590,10 @@ static PyObject *
25802590
test_interp_weak_ref(PyObject *self, PyObject *unused)
25812591
{
25822592
PyInterpreterState *interp = PyInterpreterState_Get();
2583-
PyInterpreterWeakRef wref = PyInterpreterWeakRef_Get();
2593+
PyInterpreterWeakRef wref;
2594+
if (PyInterpreterWeakRef_Get(&wref) < 0) {
2595+
return NULL;
2596+
}
25842597
assert(_PyInterpreterState_Refcount(interp) == 0);
25852598

25862599
PyInterpreterRef ref;
@@ -2598,10 +2611,10 @@ static PyObject *
25982611
test_interp_ensure(PyObject *self, PyObject *unused)
25992612
{
26002613
PyInterpreterState *interp = PyInterpreterState_Get();
2601-
PyInterpreterRef ref = PyInterpreterRef_Get();
2614+
PyInterpreterRef ref = get_strong_ref();
26022615
PyThreadState *save_tstate = PyThreadState_Swap(NULL);
26032616
PyThreadState *tstate = Py_NewInterpreter();
2604-
PyInterpreterRef sub_ref = PyInterpreterRef_Get();
2617+
PyInterpreterRef sub_ref = get_strong_ref();
26052618
PyInterpreterState *subinterp = PyThreadState_GetInterpreter(tstate);
26062619

26072620
for (int i = 0; i < 10; ++i) {

Programs/_testembed.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2354,7 +2354,10 @@ test_thread_state_ensure(void)
23542354
_testembed_initialize();
23552355
PyThread_handle_t handle;
23562356
PyThread_ident_t ident;
2357-
PyInterpreterRef ref = PyInterpreterRef_Get();
2357+
PyInterpreterRef ref;
2358+
if (PyInterpreterRef_Get(&ref) < 0) {
2359+
return -1;
2360+
};
23582361
ThreadData data = { ref };
23592362
if (PyThread_start_joinable_thread(do_tstate_ensure, &data,
23602363
&ident, &handle) < 0) {

Python/pystate.c

Lines changed: 62 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3145,12 +3145,22 @@ _PyInterpreterState_Refcount(PyInterpreterState *interp)
31453145
return refcount;
31463146
}
31473147

3148-
void
3148+
int
31493149
_PyInterpreterState_Incref(PyInterpreterState *interp)
31503150
{
31513151
assert(interp != NULL);
3152-
assert(_Py_atomic_load_ssize_relaxed(&interp->threads.finalizing.countdown) >= 0);
3152+
struct _Py_finalizing_threads *finalizing = &interp->threads.finalizing;
3153+
assert(_Py_atomic_load_ssize_relaxed(&finalizing->countdown) >= 0);
3154+
PyMutex *mutex = &finalizing->mutex;
3155+
PyMutex_Lock(mutex);
3156+
if (_PyEvent_IsSet(&finalizing->finished)) {
3157+
PyMutex_Unlock(mutex);
3158+
return -1;
3159+
}
3160+
31533161
_Py_atomic_add_ssize(&interp->threads.finalizing.countdown, 1);
3162+
PyMutex_Unlock(mutex);
3163+
return 0;
31543164
}
31553165

31563166
static PyInterpreterState *
@@ -3164,19 +3174,29 @@ ref_as_interp(PyInterpreterRef ref)
31643174
return interp;
31653175
}
31663176

3167-
PyInterpreterRef
3168-
PyInterpreterRef_Get(void)
3177+
int
3178+
PyInterpreterRef_Get(PyInterpreterRef *ref_ptr)
31693179
{
3180+
assert(ref_ptr != NULL);
31703181
PyInterpreterState *interp = PyInterpreterState_Get();
3171-
_PyInterpreterState_Incref(interp);
3172-
return (PyInterpreterRef)interp;
3182+
if (_PyInterpreterState_Incref(interp) < 0) {
3183+
PyErr_SetString(PyExc_PythonFinalizationError,
3184+
"Cannot acquire strong interpreter references anymore");
3185+
return -1;
3186+
}
3187+
*ref_ptr = (PyInterpreterRef)interp;
3188+
return 0;
31733189
}
31743190

31753191
PyInterpreterRef
31763192
PyInterpreterRef_Dup(PyInterpreterRef ref)
31773193
{
31783194
PyInterpreterState *interp = ref_as_interp(ref);
3179-
_PyInterpreterState_Incref(interp);
3195+
int res = _PyInterpreterState_Incref(interp);
3196+
(void)res;
3197+
// We already hold a strong reference, so it shouldn't be possible
3198+
// for the interpreter to be at a point where references don't work anymore
3199+
assert(res == 0);
31803200
return (PyInterpreterRef)interp;
31813201
}
31823202

@@ -3195,24 +3215,48 @@ PyInterpreterRef_AsInterpreter(PyInterpreterRef ref)
31953215
return interp;
31963216
}
31973217

3198-
PyInterpreterWeakRef
3199-
PyInterpreterWeakRef_Get(void)
3218+
int
3219+
PyInterpreterWeakRef_Get(PyInterpreterWeakRef *wref_ptr)
32003220
{
32013221
PyInterpreterState *interp = PyInterpreterState_Get();
3202-
PyInterpreterWeakRef wref = { interp->id };
3222+
_PyInterpreterWeakRef *wref = PyMem_RawMalloc(sizeof(_PyInterpreterWeakRef));
3223+
if (wref == NULL) {
3224+
PyErr_NoMemory();
3225+
return -1;
3226+
}
3227+
wref->refcount = 1;
3228+
wref->id = interp->id;
3229+
*wref_ptr = (PyInterpreterWeakRef)wref;
3230+
return 0;
3231+
}
3232+
3233+
static _PyInterpreterWeakRef *
3234+
wref_handle_as_ptr(PyInterpreterWeakRef wref_handle)
3235+
{
3236+
_PyInterpreterWeakRef *wref = (_PyInterpreterWeakRef *)wref_handle;
3237+
if (wref == NULL) {
3238+
Py_FatalError("Got a null weak interpreter reference, likely due to use after close.");
3239+
}
3240+
32033241
return wref;
32043242
}
32053243

32063244
PyInterpreterWeakRef
3207-
PyInterpreterWeakRef_Dup(PyInterpreterWeakRef wref)
3245+
PyInterpreterWeakRef_Dup(PyInterpreterWeakRef wref_handle)
32083246
{
3247+
_PyInterpreterWeakRef *wref = wref_handle_as_ptr(wref_handle);
3248+
++wref->refcount;
32093249
return wref;
32103250
}
32113251

3252+
#undef PyInterpreterWeakRef_Close
32123253
void
3213-
PyInterpreterWeakRef_Close(PyInterpreterWeakRef wref)
3254+
PyInterpreterWeakRef_Close(PyInterpreterWeakRef wref_handle)
32143255
{
3215-
return;
3256+
_PyInterpreterWeakRef *wref = wref_handle_as_ptr(wref_handle);
3257+
if (--wref->refcount == 0) {
3258+
PyMem_RawFree(wref);
3259+
}
32163260
}
32173261

32183262
static int
@@ -3234,10 +3278,11 @@ try_acquire_strong_ref(PyInterpreterState *interp, PyInterpreterRef *strong_ptr)
32343278
}
32353279

32363280
int
3237-
PyInterpreterWeakRef_AsStrong(PyInterpreterWeakRef wref, PyInterpreterRef *strong_ptr)
3281+
PyInterpreterWeakRef_AsStrong(PyInterpreterWeakRef wref_handle, PyInterpreterRef *strong_ptr)
32383282
{
32393283
assert(strong_ptr != NULL);
3240-
int64_t interp_id = wref.id;
3284+
_PyInterpreterWeakRef *wref = wref_handle_as_ptr(wref_handle);
3285+
int64_t interp_id = wref->id;
32413286
/* Interpreters cannot be deleted while we hold the runtime lock. */
32423287
_PyRuntimeState *runtime = &_PyRuntime;
32433288
HEAD_LOCK(runtime);
@@ -3254,13 +3299,12 @@ PyInterpreterWeakRef_AsStrong(PyInterpreterWeakRef wref, PyInterpreterRef *stron
32543299
}
32553300

32563301
int
3257-
PyInterpreterState_AsStrong(PyInterpreterState *interp, PyInterpreterRef *strong_ptr)
3302+
PyInterpreterRef_Main(PyInterpreterRef *strong_ptr)
32583303
{
3259-
assert(interp != NULL);
32603304
assert(strong_ptr != NULL);
32613305
_PyRuntimeState *runtime = &_PyRuntime;
32623306
HEAD_LOCK(runtime);
3263-
int res = try_acquire_strong_ref(interp, strong_ptr);
3307+
int res = try_acquire_strong_ref(&runtime->_main_interpreter, strong_ptr);
32643308
HEAD_UNLOCK(runtime);
32653309

32663310
return res;

0 commit comments

Comments
 (0)