• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #ifndef Py_INTERNAL_CEVAL_STATE_H
2 #define Py_INTERNAL_CEVAL_STATE_H
3 #ifdef __cplusplus
4 extern "C" {
5 #endif
6 
7 #ifndef Py_BUILD_CORE
8 #  error "this header requires Py_BUILD_CORE define"
9 #endif
10 
11 #include "pycore_lock.h"            // PyMutex
12 #include "pycore_gil.h"             // struct _gil_runtime_state
13 
14 
15 typedef int (*_Py_pending_call_func)(void *);
16 
17 struct _pending_call {
18     _Py_pending_call_func func;
19     void *arg;
20     int flags;
21 };
22 
23 #define PENDINGCALLSARRAYSIZE 300
24 
25 #define MAXPENDINGCALLS PENDINGCALLSARRAYSIZE
26 /* For interpreter-level pending calls, we want to avoid spending too
27    much time on pending calls in any one thread, so we apply a limit. */
28 #if MAXPENDINGCALLS > 100
29 #  define MAXPENDINGCALLSLOOP 100
30 #else
31 #  define MAXPENDINGCALLSLOOP MAXPENDINGCALLS
32 #endif
33 
34 /* We keep the number small to preserve as much compatibility
35    as possible with earlier versions. */
36 #define MAXPENDINGCALLS_MAIN 32
37 /* For the main thread, we want to make sure all pending calls are
38    run at once, for the sake of prompt signal handling.  This is
39    unlikely to cause any problems since there should be very few
40    pending calls for the main thread. */
41 #define MAXPENDINGCALLSLOOP_MAIN 0
42 
43 struct _pending_calls {
44     PyThreadState *handling_thread;
45     PyMutex mutex;
46     /* Request for running pending calls. */
47     int32_t npending;
48     /* The maximum allowed number of pending calls.
49        If the queue fills up to this point then _PyEval_AddPendingCall()
50        will return _Py_ADD_PENDING_FULL. */
51     int32_t max;
52     /* We don't want a flood of pending calls to interrupt any one thread
53        for too long, so we keep a limit on the number handled per pass.
54        A value of 0 means there is no limit (other than the maximum
55        size of the list of pending calls). */
56     int32_t maxloop;
57     struct _pending_call calls[PENDINGCALLSARRAYSIZE];
58     int first;
59     int next;
60 };
61 
62 
63 typedef enum {
64     PERF_STATUS_FAILED = -1,  // Perf trampoline is in an invalid state
65     PERF_STATUS_NO_INIT = 0,  // Perf trampoline is not initialized
66     PERF_STATUS_OK = 1,       // Perf trampoline is ready to be executed
67 } perf_status_t;
68 
69 #ifdef PY_HAVE_PERF_TRAMPOLINE
70 struct code_arena_st;
71 
72 struct trampoline_api_st {
73     void* (*init_state)(void);
74     void (*write_state)(void* state, const void *code_addr,
75                         unsigned int code_size, PyCodeObject* code);
76     int (*free_state)(void* state);
77     void *state;
78     Py_ssize_t code_padding;
79 };
80 #endif
81 
82 
83 struct _ceval_runtime_state {
84     struct {
85 #ifdef PY_HAVE_PERF_TRAMPOLINE
86         perf_status_t status;
87         int perf_trampoline_type;
88         Py_ssize_t extra_code_index;
89         struct code_arena_st *code_arena;
90         struct trampoline_api_st trampoline_api;
91         FILE *map_file;
92         Py_ssize_t persist_after_fork;
93 #else
94         int _not_used;
95 #endif
96     } perf;
97     /* Pending calls to be made only on the main thread. */
98     // The signal machinery falls back on this
99     // so it must be especially stable and efficient.
100     // For example, we use a preallocated array
101     // for the list of pending calls.
102     struct _pending_calls pending_mainthread;
103     PyMutex sys_trace_profile_mutex;
104 };
105 
106 
107 #ifdef PY_HAVE_PERF_TRAMPOLINE
108 # define _PyEval_RUNTIME_PERF_INIT \
109     { \
110         .status = PERF_STATUS_NO_INIT, \
111         .extra_code_index = -1, \
112         .persist_after_fork = 0, \
113     }
114 #else
115 # define _PyEval_RUNTIME_PERF_INIT {0}
116 #endif
117 
118 
119 struct _ceval_state {
120     /* This variable holds the global instrumentation version. When a thread is
121        running, this value is overlaid onto PyThreadState.eval_breaker so that
122        changes in the instrumentation version will trigger the eval breaker. */
123     uintptr_t instrumentation_version;
124     int recursion_limit;
125     struct _gil_runtime_state *gil;
126     int own_gil;
127     struct _pending_calls pending;
128 };
129 
130 
131 #ifdef __cplusplus
132 }
133 #endif
134 #endif /* !Py_INTERNAL_CEVAL_STATE_H */
135