Skip to content

Commit 99ffe4b

Browse files
Release the shutdown lock *after* releasing the GIL.
1 parent 097b783 commit 99ffe4b

File tree

3 files changed

+12
-6
lines changed

3 files changed

+12
-6
lines changed

Include/cpython/pystate.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ struct _ts {
211211
* weakref-to-lock (on_delete_data) argument, and release_sentinel releases
212212
* the indirectly held lock.
213213
*/
214-
void (*on_delete)(void *);
214+
int (*on_delete)(void *);
215215
void *on_delete_data;
216216

217217
int coroutine_origin_tracking_depth;

Modules/_threadmodule.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -1307,7 +1307,7 @@ yet finished.\n\
13071307
This function is meant for internal and specialized purposes only.\n\
13081308
In most applications `threading.enumerate()` should be used instead.");
13091309

1310-
static void
1310+
static int
13111311
release_sentinel(void *wr_raw)
13121312
{
13131313
PyObject *wr = _PyObject_CAST(wr_raw);
@@ -1326,6 +1326,7 @@ release_sentinel(void *wr_raw)
13261326
/* Deallocating a weakref with a NULL callback only calls
13271327
PyObject_GC_Del(), which can't call any Python code. */
13281328
Py_DECREF(wr);
1329+
return 0;
13291330
}
13301331

13311332
static PyObject *

Python/pystate.c

+9-4
Original file line numberDiff line numberDiff line change
@@ -1490,10 +1490,6 @@ PyThreadState_Clear(PyThreadState *tstate)
14901490

14911491
Py_CLEAR(tstate->context);
14921492

1493-
if (tstate->on_delete != NULL) {
1494-
tstate->on_delete(tstate->on_delete_data);
1495-
}
1496-
14971493
tstate->_status.cleared = 1;
14981494

14991495
// XXX Call _PyThreadStateSwap(runtime, NULL) here if "current".
@@ -1565,6 +1561,15 @@ void
15651561
_PyThreadState_DeleteCurrent(PyThreadState *tstate)
15661562
{
15671563
_Py_EnsureTstateNotNULL(tstate);
1564+
/* We ignore the return value. A non-zero value means there were
1565+
too many pending calls already queued up. This case is unlikely,
1566+
and, at worst, we'll leak on_delete_data.
1567+
Also, note that the pending call will be run the next time the
1568+
GIL is taken by one of this interpreter's threads. So it won't
1569+
happen until after the _PyEval_ReleaseLock() call below. */
1570+
(void)_PyEval_AddPendingCall(tstate->interp,
1571+
tstate->on_delete, tstate->on_delete_data);
1572+
15681573
tstate_delete_common(tstate);
15691574
current_fast_clear(tstate->interp->runtime);
15701575
_PyEval_ReleaseLock(tstate);

0 commit comments

Comments
 (0)