Skip to content

Commit d501f35

Browse files
committed
Use the interpreter's reference count and native thread countdown as one.
1 parent 40989de commit d501f35

4 files changed

Lines changed: 29 additions & 84 deletions

File tree

Include/internal/pycore_interp_structs.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -955,10 +955,6 @@ struct _is {
955955
# endif
956956
#endif
957957

958-
/* This prevents the interpreter from deleting.
959-
See PEP 788 for the full specification. */
960-
Py_ssize_t refcount;
961-
962958
/* the initial PyInterpreterState.threads.head */
963959
_PyThreadStateImpl _initial_thread;
964960
// _initial_thread should be the last field of PyInterpreterState.

Programs/_testembed.c

Lines changed: 6 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -2350,54 +2350,21 @@ const char *THREAD_CODE = "import time\n"
23502350
" return fib(n - 1) + fib(n - 2)\n"
23512351
"fib(10)";
23522352

2353-
static void
2354-
non_daemon_native(void *arg)
2355-
{
2356-
PyEvent *event = (PyEvent *)arg;
2357-
PyThreadState *tstate = PyThreadState_New(PyInterpreterState_Main());
2358-
PyThreadState_Swap(tstate);
2359-
int res = PyThreadState_SetDaemon(0);
2360-
assert(res == 1);
2361-
_PyEvent_Notify(event);
2362-
res = PyRun_SimpleString(THREAD_CODE);
2363-
assert(res == 0);
2364-
PyThreadState_Clear(tstate);
2365-
PyThreadState_Swap(NULL);
2366-
PyThreadState_Delete(tstate);
2367-
}
2368-
2369-
static int
2370-
test_non_daemon_native_thread(void)
2371-
{
2372-
_testembed_Py_InitializeFromConfig();
2373-
PyThread_handle_t handle;
2374-
PyThread_ident_t ident;
2375-
PyEvent event = {0};
2376-
if (PyThread_start_joinable_thread(non_daemon_native, &event,
2377-
&ident, &handle) < 0) {
2378-
return -1;
2379-
}
2380-
PyEvent_Wait(&event);
2381-
Py_Finalize();
2382-
return 0;
2383-
}
2384-
23852353
typedef struct {
23862354
PyInterpreterState *interp;
2387-
PyEvent *event;
2355+
int done;
23882356
} ThreadData;
23892357

23902358
static void
23912359
do_tstate_ensure(void *arg)
23922360
{
23932361
ThreadData *data = (ThreadData *)arg;
2394-
PyEvent *event = data->event;
23952362
int res = PyThreadState_Ensure(data->interp);
23962363
assert(res == 0);
2397-
_PyEvent_Notify(event);
23982364
res = PyRun_SimpleString(THREAD_CODE);
23992365
assert(res == 0);
24002366
PyThreadState_Release();
2367+
data->done = 1;
24012368
}
24022369

24032370
static int
@@ -2406,14 +2373,14 @@ test_thread_state_ensure(void)
24062373
_testembed_Py_InitializeFromConfig();
24072374
PyThread_handle_t handle;
24082375
PyThread_ident_t ident;
2409-
PyEvent event = {0};
2410-
ThreadData data = { PyInterpreterState_Hold(), &event };
2411-
if (PyThread_start_joinable_thread(non_daemon_native, &data,
2376+
ThreadData data = { PyInterpreterState_Hold() };
2377+
if (PyThread_start_joinable_thread(do_tstate_ensure, &data,
24122378
&ident, &handle) < 0) {
2379+
PyInterpreterState_Release(data.interp);
24132380
return -1;
24142381
}
2415-
PyEvent_Wait(&event);
24162382
Py_Finalize();
2383+
assert(data.done == 1);
24172384
return 0;
24182385
}
24192386

@@ -2506,7 +2473,6 @@ static struct TestCase TestCases[] = {
25062473
{"test_frozenmain", test_frozenmain},
25072474
#endif
25082475
{"test_get_incomplete_frame", test_get_incomplete_frame},
2509-
{"test_non_daemon_native_thread", test_non_daemon_native_thread},
25102476
{"test_thread_state_ensure", test_thread_state_ensure},
25112477

25122478
{NULL, NULL}

Python/pylifecycle.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2293,7 +2293,6 @@ new_interpreter(PyThreadState **tstate_p,
22932293
}
22942294
_PyInterpreterState_SetWhence(interp, whence);
22952295
interp->_ready = 1;
2296-
interp->refcount = 1;
22972296

22982297
// XXX Might new_interpreter() have been called without the GIL held?
22992298
PyThreadState *save_tstate = _PyThreadState_GET();
@@ -3471,15 +3470,14 @@ wait_for_native_shutdown(PyInterpreterState *interp)
34713470
assert(interp != NULL);
34723471
struct _Py_finalizing_threads *finalizing = &interp->threads.finalizing;
34733472
PyMutex_Lock(&finalizing->mutex);
3474-
if (finalizing->countdown == 0) {
3473+
if (_Py_atomic_load_ssize_relaxed(&finalizing->countdown) == 0) {
34753474
// Nothing to do.
34763475
PyMutex_Unlock(&finalizing->mutex);
34773476
return;
34783477
}
34793478
PyMutex_Unlock(&finalizing->mutex);
34803479

34813480
PyEvent_Wait(&finalizing->finished);
3482-
assert(finalizing->countdown == 0);
34833481
}
34843482

34853483
int Py_AtExit(void (*func)(void))

Python/pystate.c

Lines changed: 22 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -600,18 +600,6 @@ free_interpreter(PyInterpreterState *interp)
600600
}
601601
}
602602

603-
static Py_ssize_t
604-
decref_interpreter(PyInterpreterState *interp)
605-
{
606-
assert(interp != NULL);
607-
Py_ssize_t old_refcnt = _Py_atomic_add_ssize(&interp->refcount, -1);
608-
if (old_refcnt == 1) {
609-
free_interpreter(interp);
610-
}
611-
612-
return old_refcnt;
613-
}
614-
615603
#ifndef NDEBUG
616604
static inline int check_interpreter_whence(long);
617605
#endif
@@ -805,7 +793,6 @@ _PyInterpreterState_New(PyThreadState *tstate, PyInterpreterState **pinterp)
805793
HEAD_UNLOCK(runtime);
806794

807795
if (interp != NULL) {
808-
assert(interp->refcount == 1);
809796
free_interpreter(interp);
810797
}
811798
return status;
@@ -1056,7 +1043,7 @@ PyInterpreterState_Delete(PyInterpreterState *interp)
10561043

10571044
_PyObject_FiniState(interp);
10581045

1059-
decref_interpreter(interp);
1046+
free_interpreter(interp);
10601047
}
10611048

10621049

@@ -1092,7 +1079,7 @@ _PyInterpreterState_DeleteExceptMain(_PyRuntimeState *runtime)
10921079
zapthreads(interp);
10931080
PyInterpreterState *prev_interp = interp;
10941081
interp = interp->next;
1095-
decref_interpreter(prev_interp);
1082+
free_interpreter(prev_interp);
10961083
}
10971084
HEAD_UNLOCK(runtime);
10981085

@@ -1825,7 +1812,7 @@ decrement_daemon_count(PyInterpreterState *interp)
18251812
{
18261813
assert(interp != NULL);
18271814
struct _Py_finalizing_threads *finalizing = &interp->threads.finalizing;
1828-
if (--finalizing->countdown == 0) {
1815+
if (_Py_atomic_load_ssize_relaxed(&finalizing->countdown) == 1) {
18291816
_PyEvent_Notify(&finalizing->finished);
18301817
}
18311818
}
@@ -3221,25 +3208,24 @@ Py_ssize_t
32213208
_PyInterpreterState_Refcount(PyInterpreterState *interp)
32223209
{
32233210
assert(interp != NULL);
3224-
Py_ssize_t refcount = _Py_atomic_load_ssize_relaxed(&interp->refcount);
3225-
assert(refcount > 0);
3211+
Py_ssize_t refcount = _Py_atomic_load_ssize_relaxed(&interp->threads.finalizing.countdown);
32263212
return refcount;
32273213
}
32283214

32293215
PyInterpreterState *
32303216
PyInterpreterState_Hold(void)
32313217
{
32323218
PyInterpreterState *interp = PyInterpreterState_Get();
3233-
assert(_Py_atomic_load_ssize_relaxed(&interp->refcount) > 0);
3234-
_Py_atomic_add_ssize(&interp->refcount, 1);
3219+
assert(_Py_atomic_load_ssize_relaxed(&interp->threads.finalizing.countdown) >= 0);
3220+
_Py_atomic_add_ssize(&interp->threads.finalizing.countdown, 1);
32353221
return interp;
32363222
}
32373223

32383224
void
32393225
PyInterpreterState_Release(PyInterpreterState *interp)
32403226
{
32413227
assert(interp != NULL);
3242-
decref_interpreter(interp);
3228+
decrement_daemon_count(interp);
32433229
}
32443230

32453231
static int
@@ -3251,12 +3237,16 @@ tstate_set_daemon(PyThreadState *tstate, PyInterpreterState *interp, int daemon)
32513237
assert(daemon == 1 || daemon == 0);
32523238
struct _Py_finalizing_threads *finalizing = &interp->threads.finalizing;
32533239
PyMutex_Lock(&finalizing->mutex);
3240+
if (_Py_atomic_load_ssize_relaxed(&finalizing->countdown) == 0) {
3241+
PyMutex_Unlock(&finalizing->mutex);
3242+
return -1;
3243+
}
32543244
if (_PyEvent_IsSet(&finalizing->finished)) {
32553245
/* Native threads have already finalized */
32563246
PyMutex_Unlock(&finalizing->mutex);
32573247
return -1;
32583248
}
3259-
++finalizing->countdown;
3249+
_Py_atomic_add_ssize(&finalizing->countdown, 1);
32603250
PyMutex_Unlock(&finalizing->mutex);
32613251
tstate->daemon = daemon;
32623252
return 1;
@@ -3271,7 +3261,7 @@ PyThreadState_SetDaemon(int daemon)
32713261
}
32723262
PyInterpreterState *interp = tstate->interp;
32733263
assert(interp != NULL);
3274-
if (tstate == &interp->_initial_thread) {
3264+
if (tstate == (PyThreadState *)&interp->_initial_thread) {
32753265
Py_FatalError("thread cannot be the main thread");
32763266
}
32773267
if (tstate->daemon == daemon) {
@@ -3287,39 +3277,31 @@ PyThreadState_Ensure(PyInterpreterState *interp)
32873277
assert(interp != NULL);
32883278
_Py_ensured_tstate *entry = PyMem_RawMalloc(sizeof(_Py_ensured_tstate));
32893279
if (entry == NULL) {
3290-
decref_interpreter(interp);
3280+
decrement_daemon_count(interp);
32913281
return -1;
32923282
}
32933283
PyThreadState *save = _PyThreadState_GET();
32943284
if (save != NULL && save->interp == interp) {
3295-
/* We already have a thread state that matches the
3296-
interpreter. */
3297-
Py_ssize_t refcnt = decref_interpreter(interp);
32983285
entry->was_daemon = save->daemon;
32993286
entry->next = save->ensured;
33003287
entry->prior_tstate = NULL;
3301-
if (tstate_set_daemon(save, interp, 0) < 0) {
3302-
PyMem_RawFree(entry);
3303-
return -1;
3304-
}
33053288
save->ensured = entry;
3289+
// Setting 'daemon' to 0 passes off the interpreter's reference
3290+
save->daemon = 0;
33063291
return 0;
33073292
}
33083293

33093294
PyThreadState *tstate = PyThreadState_New(interp);
3310-
decref_interpreter(interp);
33113295
if (tstate == NULL) {
33123296
PyMem_RawFree(entry);
33133297
return -1;
33143298
}
3315-
if (tstate_set_daemon(tstate, interp, 0) < 0) {
3316-
PyMem_RawFree(entry);
3317-
return -1;
3318-
}
3299+
tstate->daemon = 0;
33193300
entry->was_daemon = 0;
33203301
entry->prior_tstate = save;
33213302
entry->next = NULL;
33223303
tstate->ensured = entry;
3304+
PyThreadState_Swap(tstate);
33233305

33243306
return 0;
33253307
}
@@ -3342,8 +3324,11 @@ PyThreadState_Release(void)
33423324
return;
33433325
}
33443326

3345-
decrement_daemon_count(tstate->interp);
33463327
tstate->ensured = ensured->next;
33473328
tstate->daemon = ensured->was_daemon;
33483329
PyMem_RawFree(ensured);
3330+
PyThreadState_Clear(tstate);
3331+
PyThreadState_Swap(NULL);
3332+
PyInterpreterState *interp = tstate->interp;
3333+
PyThreadState_Delete(tstate);
33493334
}

0 commit comments

Comments
 (0)