gh-104812: Run Pending Calls in any Thread (gh-104813) · python/cpython@757b402 · GitHub
Skip to content

Commit 757b402

Browse files
gh-104812: Run Pending Calls in any Thread (gh-104813)
For a while now, pending calls only run in the main thread (in the main interpreter). This PR changes things to allow any thread run a pending call, unless the pending call was explicitly added for the main thread to run.
1 parent 4e80082 commit 757b402

16 files changed

Lines changed: 761 additions & 118 deletions

File tree

Include/cpython/ceval.h

Lines changed: 2 additions & 0 deletions

Include/internal/pycore_ceval.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ PyAPI_FUNC(void) _PyEval_SignalReceived(PyInterpreterState *interp);
2727
PyAPI_FUNC(int) _PyEval_AddPendingCall(
2828
PyInterpreterState *interp,
2929
int (*func)(void *),
30-
void *arg);
30+
void *arg,
31+
int mainthreadonly);
3132
PyAPI_FUNC(void) _PyEval_SignalAsyncExc(PyInterpreterState *interp);
3233
#ifdef HAVE_FORK
3334
extern PyStatus _PyEval_ReInitThreads(PyThreadState *tstate);

Include/internal/pycore_ceval_state.h

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,24 @@ extern "C" {
1313
#include "pycore_gil.h" // struct _gil_runtime_state
1414

1515

16+
struct _pending_calls {
17+
int busy;
18+
PyThread_type_lock lock;
19+
/* Request for running pending calls. */
20+
_Py_atomic_int calls_to_do;
21+
/* Request for looking at the `async_exc` field of the current
22+
thread state.
23+
Guarded by the GIL. */
24+
int async_exc;
25+
#define NPENDINGCALLS 32
26+
struct _pending_call {
27+
int (*func)(void *);
28+
void *arg;
29+
} calls[NPENDINGCALLS];
30+
int first;
31+
int last;
32+
};
33+
1634
typedef enum {
1735
PERF_STATUS_FAILED = -1, // Perf trampoline is in an invalid state
1836
PERF_STATUS_NO_INIT = 0, // Perf trampoline is not initialized
@@ -49,6 +67,8 @@ struct _ceval_runtime_state {
4967
the main thread of the main interpreter can handle signals: see
5068
_Py_ThreadCanHandleSignals(). */
5169
_Py_atomic_int signals_pending;
70+
/* Pending calls to be made only on the main thread. */
71+
struct _pending_calls pending_mainthread;
5272
};
5373

5474
#ifdef PY_HAVE_PERF_TRAMPOLINE
@@ -62,24 +82,6 @@ struct _ceval_runtime_state {
6282
#endif
6383

6484

65-
struct _pending_calls {
66-
int busy;
67-
PyThread_type_lock lock;
68-
/* Request for running pending calls. */
69-
_Py_atomic_int calls_to_do;
70-
/* Request for looking at the `async_exc` field of the current
71-
thread state.
72-
Guarded by the GIL. */
73-
int async_exc;
74-
#define NPENDINGCALLS 32
75-
struct {
76-
int (*func)(void *);
77-
void *arg;
78-
} calls[NPENDINGCALLS];
79-
int first;
80-
int last;
81-
};
82-
8385
struct _ceval_state {
8486
/* This single variable consolidates all requests to break out of
8587
the fast path in the eval loop. */

Include/internal/pycore_pystate.h

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -60,14 +60,6 @@ _Py_ThreadCanHandleSignals(PyInterpreterState *interp)
6060
}
6161

6262

63-
/* Only execute pending calls on the main thread. */
64-
static inline int
65-
_Py_ThreadCanHandlePendingCalls(void)
66-
{
67-
return _Py_IsMainThread();
68-
}
69-
70-
7163
/* Variable and static inline functions for in-line access to current thread
7264
and interpreter state */
7365

Lib/test/support/threading_helper.py

Lines changed: 7 additions & 2 deletions

0 commit comments

Comments
 (0)