Skip to content

Commit

Permalink
pythonGH-118095: Make sure that progress is made if there are pending…
Browse files Browse the repository at this point in the history
… calls being handled. (pythonGH-118484)
  • Loading branch information
markshannon authored May 1, 2024
1 parent 8a50544 commit 39981fd
Show file tree
Hide file tree
Showing 2 changed files with 11 additions and 12 deletions.
2 changes: 1 addition & 1 deletion Include/internal/pycore_ceval_state.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ struct _pending_call {
#define MAXPENDINGCALLSLOOP_MAIN 0

struct _pending_calls {
int busy;
PyThreadState *handling_thread;
PyMutex mutex;
/* Request for running pending calls. */
int32_t npending;
Expand Down
21 changes: 10 additions & 11 deletions Python/ceval_gil.c
Original file line number Diff line number Diff line change
Expand Up @@ -877,21 +877,20 @@ make_pending_calls(PyThreadState *tstate)
/* Only one thread (per interpreter) may run the pending calls
at once. In the same way, we don't do recursive pending calls. */
PyMutex_Lock(&pending->mutex);
if (pending->busy) {
if (pending->handling_thread != NULL) {
/* A pending call was added after another thread was already
handling the pending calls (and had already "unsignaled").
Once that thread is done, it may have taken care of all the
pending calls, or there might be some still waiting.
Regardless, this interpreter's pending calls will stay
"signaled" until that first thread has finished. At that
point the next thread to trip the eval breaker will take
care of any remaining pending calls. Until then, though,
all the interpreter's threads will be tripping the eval
breaker every time it's checked. */
To avoid all threads constantly stopping on the eval breaker,
we clear the bit for this thread and make sure it is set
for the thread currently handling the pending call. */
_Py_set_eval_breaker_bit(pending->handling_thread, _PY_CALLS_TO_DO_BIT);
_Py_unset_eval_breaker_bit(tstate, _PY_CALLS_TO_DO_BIT);
PyMutex_Unlock(&pending->mutex);
return 0;
}
pending->busy = 1;
pending->handling_thread = tstate;
PyMutex_Unlock(&pending->mutex);

/* unsignal before starting to call callbacks, so that any callback
Expand All @@ -900,7 +899,7 @@ make_pending_calls(PyThreadState *tstate)

int32_t npending;
if (_make_pending_calls(pending, &npending) != 0) {
pending->busy = 0;
pending->handling_thread = NULL;
/* There might not be more calls to make, but we play it safe. */
signal_pending_calls(tstate, interp);
return -1;
Expand All @@ -912,7 +911,7 @@ make_pending_calls(PyThreadState *tstate)

if (_Py_IsMainThread() && _Py_IsMainInterpreter(interp)) {
if (_make_pending_calls(pending_main, &npending) != 0) {
pending->busy = 0;
pending->handling_thread = NULL;
/* There might not be more calls to make, but we play it safe. */
signal_pending_calls(tstate, interp);
return -1;
Expand All @@ -923,7 +922,7 @@ make_pending_calls(PyThreadState *tstate)
}
}

pending->busy = 0;
pending->handling_thread = NULL;
return 0;
}

Expand Down

0 comments on commit 39981fd

Please sign in to comment.