summaryrefslogtreecommitdiffstats
path: root/Include
diff options
context:
space:
mode:
authorEric Snow <ericsnowcurrently@gmail.com>2024-04-26 01:05:51 (GMT)
committerGitHub <noreply@github.com>2024-04-26 01:05:51 (GMT)
commit09c29475813ff2a763931fc0b45aaaef57cd2ac7 (patch)
treedc006bd73c8969f5a228a3b778c38349b3cc8bbb /Include
parentd5df25268b037c2f1f4a1184fad5274d0e72f8d6 (diff)
downloadcpython-09c29475813ff2a763931fc0b45aaaef57cd2ac7.zip
cpython-09c29475813ff2a763931fc0b45aaaef57cd2ac7.tar.gz
cpython-09c29475813ff2a763931fc0b45aaaef57cd2ac7.tar.bz2
gh-110693: Pending Calls Machinery Cleanups (gh-118296)
This does some cleanup in preparation for later changes.
Diffstat (limited to 'Include')
-rw-r--r--Include/internal/pycore_ceval.h6
-rw-r--r--Include/internal/pycore_ceval_state.h52
-rw-r--r--Include/internal/pycore_runtime_init.h8
3 files changed, 56 insertions, 10 deletions
diff --git a/Include/internal/pycore_ceval.h b/Include/internal/pycore_ceval.h
index 8d88b5c..cfb88c3 100644
--- a/Include/internal/pycore_ceval.h
+++ b/Include/internal/pycore_ceval.h
@@ -48,8 +48,12 @@ extern void _PyEval_SignalReceived(void);
#define _Py_PENDING_MAINTHREADONLY 1
#define _Py_PENDING_RAWFREE 2
+typedef int _Py_add_pending_call_result;
+#define _Py_ADD_PENDING_SUCCESS 0
+#define _Py_ADD_PENDING_FULL -1
+
// Export for '_testinternalcapi' shared extension
-PyAPI_FUNC(int) _PyEval_AddPendingCall(
+PyAPI_FUNC(_Py_add_pending_call_result) _PyEval_AddPendingCall(
PyInterpreterState *interp,
_Py_pending_call_func func,
void *arg,
diff --git a/Include/internal/pycore_ceval_state.h b/Include/internal/pycore_ceval_state.h
index 1682955..1831f58 100644
--- a/Include/internal/pycore_ceval_state.h
+++ b/Include/internal/pycore_ceval_state.h
@@ -14,28 +14,56 @@ extern "C" {
typedef int (*_Py_pending_call_func)(void *);
+struct _pending_call {
+ _Py_pending_call_func func;
+ void *arg;
+ int flags;
+};
+
+#define PENDINGCALLSARRAYSIZE 32
+
+#define MAXPENDINGCALLS PENDINGCALLSARRAYSIZE
+/* For interpreter-level pending calls, we want to avoid spending too
+ much time on pending calls in any one thread, so we apply a limit. */
+#if MAXPENDINGCALLS > 100
+# define MAXPENDINGCALLSLOOP 100
+#else
+# define MAXPENDINGCALLSLOOP MAXPENDINGCALLS
+#endif
+
+#define MAXPENDINGCALLS_MAIN PENDINGCALLSARRAYSIZE
+/* For the main thread, we want to make sure all pending calls are
+ run at once, for the sake of prompt signal handling. This is
+ unlikely to cause any problems since there should be very few
+ pending calls for the main thread. */
+#define MAXPENDINGCALLSLOOP_MAIN 0
+
struct _pending_calls {
int busy;
PyMutex mutex;
/* Request for running pending calls. */
- int32_t calls_to_do;
-#define NPENDINGCALLS 32
- struct _pending_call {
- _Py_pending_call_func func;
- void *arg;
- int flags;
- } calls[NPENDINGCALLS];
+ int32_t npending;
+ /* The maximum allowed number of pending calls.
+ If the queue fills up to this point then _PyEval_AddPendingCall()
+ will return _Py_ADD_PENDING_FULL. */
+ int32_t max;
+ /* We don't want a flood of pending calls to interrupt any one thread
+ for too long, so we keep a limit on the number handled per pass.
+ A value of 0 means there is no limit (other than the maximum
+ size of the list of pending calls). */
+ int32_t maxloop;
+ struct _pending_call calls[PENDINGCALLSARRAYSIZE];
int first;
- int last;
+ int next;
};
+
typedef enum {
PERF_STATUS_FAILED = -1, // Perf trampoline is in an invalid state
PERF_STATUS_NO_INIT = 0, // Perf trampoline is not initialized
PERF_STATUS_OK = 1, // Perf trampoline is ready to be executed
} perf_status_t;
-
#ifdef PY_HAVE_PERF_TRAMPOLINE
struct code_arena_st;
@@ -48,6 +76,7 @@ struct trampoline_api_st {
};
#endif
+
struct _ceval_runtime_state {
struct {
#ifdef PY_HAVE_PERF_TRAMPOLINE
@@ -62,10 +91,15 @@ struct _ceval_runtime_state {
#endif
} perf;
/* Pending calls to be made only on the main thread. */
+ // The signal machinery falls back on this
+ // so it must be especially stable and efficient.
+ // For example, we use a preallocated array
+ // for the list of pending calls.
struct _pending_calls pending_mainthread;
PyMutex sys_trace_profile_mutex;
};
+
#ifdef PY_HAVE_PERF_TRAMPOLINE
# define _PyEval_RUNTIME_PERF_INIT \
{ \
diff --git a/Include/internal/pycore_runtime_init.h b/Include/internal/pycore_runtime_init.h
index 33c7a9d..41331df 100644
--- a/Include/internal/pycore_runtime_init.h
+++ b/Include/internal/pycore_runtime_init.h
@@ -114,6 +114,10 @@ extern PyTypeObject _PyExc_MemoryError;
.autoTSSkey = Py_tss_NEEDS_INIT, \
.parser = _parser_runtime_state_INIT, \
.ceval = { \
+ .pending_mainthread = { \
+ .max = MAXPENDINGCALLS_MAIN, \
+ .maxloop = MAXPENDINGCALLSLOOP_MAIN, \
+ }, \
.perf = _PyEval_RUNTIME_PERF_INIT, \
}, \
.gilstate = { \
@@ -166,6 +170,10 @@ extern PyTypeObject _PyExc_MemoryError;
.imports = IMPORTS_INIT, \
.ceval = { \
.recursion_limit = Py_DEFAULT_RECURSION_LIMIT, \
+ .pending = { \
+ .max = MAXPENDINGCALLS, \
+ .maxloop = MAXPENDINGCALLSLOOP, \
+ }, \
}, \
.gc = { \
.enabled = 1, \