Skip to content

Commit 56bfdeb

Browse files
authored
bpo-39984: Pass tstate to _PyEval_SignalAsyncExc() (GH-19049)
_PyEval_SignalAsyncExc() and _PyEval_FiniThreads() now expect tstate, instead of ceval.
1 parent 611836a commit 56bfdeb

File tree

5 files changed

+30
-26
lines changed

5 files changed

+30
-26
lines changed

Include/internal/pycore_ceval.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,15 @@ struct _frame;
1818
extern void _Py_FinishPendingCalls(PyThreadState *tstate);
1919
extern void _PyEval_InitRuntimeState(struct _ceval_runtime_state *);
2020
extern void _PyEval_InitState(struct _ceval_state *);
21-
extern void _PyEval_FiniThreads(
22-
struct _ceval_runtime_state *ceval);
21+
extern void _PyEval_FiniThreads(PyThreadState *tstate);
2322
PyAPI_FUNC(void) _PyEval_SignalReceived(
2423
struct _ceval_runtime_state *ceval);
2524
PyAPI_FUNC(int) _PyEval_AddPendingCall(
2625
PyThreadState *tstate,
2726
struct _ceval_runtime_state *ceval,
2827
int (*func)(void *),
2928
void *arg);
30-
PyAPI_FUNC(void) _PyEval_SignalAsyncExc(
31-
struct _ceval_runtime_state *ceval);
29+
PyAPI_FUNC(void) _PyEval_SignalAsyncExc(PyThreadState *tstate);
3230
PyAPI_FUNC(void) _PyEval_ReInitThreads(
3331
struct pyruntimestate *runtime);
3432
PyAPI_FUNC(void) _PyEval_SetCoroutineOriginTrackingDepth(

Python/ceval.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -246,8 +246,9 @@ PyEval_InitThreads(void)
246246
}
247247

248248
void
249-
_PyEval_FiniThreads(struct _ceval_runtime_state *ceval)
249+
_PyEval_FiniThreads(PyThreadState *tstate)
250250
{
251+
struct _ceval_runtime_state *ceval = &tstate->interp->runtime->ceval;
251252
struct _gil_runtime_state *gil = &ceval->gil;
252253
if (!gil_created(gil)) {
253254
return;
@@ -356,10 +357,11 @@ void
356357
_PyEval_ReInitThreads(_PyRuntimeState *runtime)
357358
{
358359
struct _ceval_runtime_state *ceval = &runtime->ceval;
359-
if (!gil_created(&ceval->gil)) {
360+
struct _gil_runtime_state *gil = &runtime->ceval.gil;
361+
if (!gil_created(gil)) {
360362
return;
361363
}
362-
recreate_gil(&ceval->gil);
364+
recreate_gil(gil);
363365
PyThreadState *tstate = _PyRuntimeState_GetThreadState(runtime);
364366
ensure_tstate_not_null(__func__, tstate);
365367

@@ -379,8 +381,9 @@ _PyEval_ReInitThreads(_PyRuntimeState *runtime)
379381
raised. */
380382

381383
void
382-
_PyEval_SignalAsyncExc(struct _ceval_runtime_state *ceval)
384+
_PyEval_SignalAsyncExc(PyThreadState *tstate)
383385
{
386+
struct _ceval_runtime_state *ceval = &tstate->interp->runtime->ceval;
384387
SIGNAL_ASYNC_EXC(ceval);
385388
}
386389

Python/ceval_gil.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ take_gil(PyThreadState *tstate)
286286

287287
/* Don't access tstate if the thread must exit */
288288
if (!must_exit && tstate->async_exc != NULL) {
289-
_PyEval_SignalAsyncExc(ceval);
289+
_PyEval_SignalAsyncExc(tstate);
290290
}
291291

292292
MUTEX_UNLOCK(gil->mutex);

Python/pylifecycle.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -548,7 +548,7 @@ pycore_create_interpreter(_PyRuntimeState *runtime,
548548
another running thread (see issue #9901).
549549
Instead we destroy the previously created GIL here, which ensures
550550
that we can call Py_Initialize / Py_FinalizeEx multiple times. */
551-
_PyEval_FiniThreads(&runtime->ceval);
551+
_PyEval_FiniThreads(tstate);
552552

553553
/* Auto-thread-state API */
554554
status = _PyGILState_Init(tstate);

Python/pystate.c

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1034,23 +1034,26 @@ PyThreadState_SetAsyncExc(unsigned long id, PyObject *exc)
10341034
* head_mutex for the duration.
10351035
*/
10361036
HEAD_LOCK(runtime);
1037-
for (PyThreadState *p = interp->tstate_head; p != NULL; p = p->next) {
1038-
if (p->thread_id == id) {
1039-
/* Tricky: we need to decref the current value
1040-
* (if any) in p->async_exc, but that can in turn
1041-
* allow arbitrary Python code to run, including
1042-
* perhaps calls to this function. To prevent
1043-
* deadlock, we need to release head_mutex before
1044-
* the decref.
1045-
*/
1046-
PyObject *old_exc = p->async_exc;
1047-
Py_XINCREF(exc);
1048-
p->async_exc = exc;
1049-
HEAD_UNLOCK(runtime);
1050-
Py_XDECREF(old_exc);
1051-
_PyEval_SignalAsyncExc(&runtime->ceval);
1052-
return 1;
1037+
for (PyThreadState *tstate = interp->tstate_head; tstate != NULL; tstate = tstate->next) {
1038+
if (tstate->thread_id != id) {
1039+
continue;
10531040
}
1041+
1042+
/* Tricky: we need to decref the current value
1043+
* (if any) in tstate->async_exc, but that can in turn
1044+
* allow arbitrary Python code to run, including
1045+
* perhaps calls to this function. To prevent
1046+
* deadlock, we need to release head_mutex before
1047+
* the decref.
1048+
*/
1049+
PyObject *old_exc = tstate->async_exc;
1050+
Py_XINCREF(exc);
1051+
tstate->async_exc = exc;
1052+
HEAD_UNLOCK(runtime);
1053+
1054+
Py_XDECREF(old_exc);
1055+
_PyEval_SignalAsyncExc(tstate);
1056+
return 1;
10541057
}
10551058
HEAD_UNLOCK(runtime);
10561059
return 0;

0 commit comments

Comments
 (0)