Skip to content

Commit ff65d1e

Browse files
[3.13] gh-118297: Make Sure All Pending Calls Run in _Py_FinishPendingCalls() (gh-121806)
(cherry picked from commit 985dd8e, AKA gh-118298) Co-authored-by: Eric Snow <ericsnowcurrently@gmail.com>
1 parent 308857b commit ff65d1e

File tree

1 file changed

+28
-6
lines changed

1 file changed

+28
-6
lines changed

Python/ceval_gil.c

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -991,12 +991,34 @@ _Py_FinishPendingCalls(PyThreadState *tstate)
991991
assert(PyGILState_Check());
992992
assert(_PyThreadState_CheckConsistency(tstate));
993993

994-
if (make_pending_calls(tstate) < 0) {
995-
PyObject *exc = _PyErr_GetRaisedException(tstate);
996-
PyErr_BadInternalCall();
997-
_PyErr_ChainExceptions1(exc);
998-
_PyErr_Print(tstate);
999-
}
994+
struct _pending_calls *pending = &tstate->interp->ceval.pending;
995+
struct _pending_calls *pending_main =
996+
_Py_IsMainThread() && _Py_IsMainInterpreter(tstate->interp)
997+
? &_PyRuntime.ceval.pending_mainthread
998+
: NULL;
999+
/* make_pending_calls() may return early without making all pending
1000+
calls, so we keep trying until we're actually done. */
1001+
int32_t npending;
1002+
#ifndef NDEBUG
1003+
int32_t npending_prev = INT32_MAX;
1004+
#endif
1005+
do {
1006+
if (make_pending_calls(tstate) < 0) {
1007+
PyObject *exc = _PyErr_GetRaisedException(tstate);
1008+
PyErr_BadInternalCall();
1009+
_PyErr_ChainExceptions1(exc);
1010+
_PyErr_Print(tstate);
1011+
}
1012+
1013+
npending = _Py_atomic_load_int32_relaxed(&pending->npending);
1014+
if (pending_main != NULL) {
1015+
npending += _Py_atomic_load_int32_relaxed(&pending_main->npending);
1016+
}
1017+
#ifndef NDEBUG
1018+
assert(npending_prev > npending);
1019+
npending_prev = npending;
1020+
#endif
1021+
} while (npending > 0);
10001022
}
10011023

10021024
int

0 commit comments

Comments
 (0)