Skip to content

Commit 0b1e330

Browse files
authored
bpo-40513: Per-interpreter gil_drop_request (GH-19927)
Move gil_drop_request member from _PyRuntimeState.ceval to PyInterpreterState.ceval.
1 parent 4e01946 commit 0b1e330

File tree

4 files changed

+45
-47
lines changed

4 files changed

+45
-47
lines changed

Include/internal/pycore_interp.h

+2
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ struct _ceval_state {
4242
/* This single variable consolidates all requests to break out of
4343
the fast path in the eval loop. */
4444
_Py_atomic_int eval_breaker;
45+
/* Request for dropping the GIL */
46+
_Py_atomic_int gil_drop_request;
4547
struct _pending_calls pending;
4648
/* Request for checking signals. */
4749
_Py_atomic_int signals_pending;

Include/internal/pycore_runtime.h

-2
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@ extern "C" {
1515

1616
struct _ceval_runtime_state {
1717
int recursion_limit;
18-
/* Request for dropping the GIL */
19-
_Py_atomic_int gil_drop_request;
2018
struct _gil_runtime_state gil;
2119
};
2220

Python/ceval.c

+36-39
Original file line numberDiff line numberDiff line change
@@ -143,77 +143,70 @@ is_tstate_valid(PyThreadState *tstate)
143143
the GIL eventually anyway. */
144144
static inline void
145145
COMPUTE_EVAL_BREAKER(PyInterpreterState *interp,
146-
struct _ceval_runtime_state *ceval,
147-
struct _ceval_state *ceval2)
146+
struct _ceval_state *ceval)
148147
{
149-
_Py_atomic_store_relaxed(&ceval2->eval_breaker,
148+
_Py_atomic_store_relaxed(&ceval->eval_breaker,
150149
_Py_atomic_load_relaxed(&ceval->gil_drop_request)
151-
| (_Py_atomic_load_relaxed(&ceval2->signals_pending)
150+
| (_Py_atomic_load_relaxed(&ceval->signals_pending)
152151
&& _Py_ThreadCanHandleSignals(interp))
153-
| (_Py_atomic_load_relaxed(&ceval2->pending.calls_to_do)
152+
| (_Py_atomic_load_relaxed(&ceval->pending.calls_to_do)
154153
&& _Py_ThreadCanHandlePendingCalls())
155-
| ceval2->pending.async_exc);
154+
| ceval->pending.async_exc);
156155
}
157156

158157

159158
static inline void
160159
SET_GIL_DROP_REQUEST(PyInterpreterState *interp)
161160
{
162-
struct _ceval_runtime_state *ceval = &interp->runtime->ceval;
163-
struct _ceval_state *ceval2 = &interp->ceval;
161+
struct _ceval_state *ceval = &interp->ceval;
164162
_Py_atomic_store_relaxed(&ceval->gil_drop_request, 1);
165-
_Py_atomic_store_relaxed(&ceval2->eval_breaker, 1);
163+
_Py_atomic_store_relaxed(&ceval->eval_breaker, 1);
166164
}
167165

168166

169167
static inline void
170168
RESET_GIL_DROP_REQUEST(PyInterpreterState *interp)
171169
{
172-
struct _ceval_runtime_state *ceval = &interp->runtime->ceval;
173-
struct _ceval_state *ceval2 = &interp->ceval;
170+
struct _ceval_state *ceval = &interp->ceval;
174171
_Py_atomic_store_relaxed(&ceval->gil_drop_request, 0);
175-
COMPUTE_EVAL_BREAKER(interp, ceval, ceval2);
172+
COMPUTE_EVAL_BREAKER(interp, ceval);
176173
}
177174

178175

179176
static inline void
180177
SIGNAL_PENDING_CALLS(PyInterpreterState *interp)
181178
{
182-
struct _ceval_runtime_state *ceval = &interp->runtime->ceval;
183-
struct _ceval_state *ceval2 = &interp->ceval;
184-
_Py_atomic_store_relaxed(&ceval2->pending.calls_to_do, 1);
185-
COMPUTE_EVAL_BREAKER(interp, ceval, ceval2);
179+
struct _ceval_state *ceval = &interp->ceval;
180+
_Py_atomic_store_relaxed(&ceval->pending.calls_to_do, 1);
181+
COMPUTE_EVAL_BREAKER(interp, ceval);
186182
}
187183

188184

189185
static inline void
190186
UNSIGNAL_PENDING_CALLS(PyInterpreterState *interp)
191187
{
192-
struct _ceval_runtime_state *ceval = &interp->runtime->ceval;
193-
struct _ceval_state *ceval2 = &interp->ceval;
194-
_Py_atomic_store_relaxed(&ceval2->pending.calls_to_do, 0);
195-
COMPUTE_EVAL_BREAKER(interp, ceval, ceval2);
188+
struct _ceval_state *ceval = &interp->ceval;
189+
_Py_atomic_store_relaxed(&ceval->pending.calls_to_do, 0);
190+
COMPUTE_EVAL_BREAKER(interp, ceval);
196191
}
197192

198193

199194
static inline void
200195
SIGNAL_PENDING_SIGNALS(PyInterpreterState *interp)
201196
{
202-
struct _ceval_runtime_state *ceval = &interp->runtime->ceval;
203-
struct _ceval_state *ceval2 = &interp->ceval;
204-
_Py_atomic_store_relaxed(&ceval2->signals_pending, 1);
197+
struct _ceval_state *ceval = &interp->ceval;
198+
_Py_atomic_store_relaxed(&ceval->signals_pending, 1);
205199
/* eval_breaker is not set to 1 if thread_can_handle_signals() is false */
206-
COMPUTE_EVAL_BREAKER(interp, ceval, ceval2);
200+
COMPUTE_EVAL_BREAKER(interp, ceval);
207201
}
208202

209203

210204
static inline void
211205
UNSIGNAL_PENDING_SIGNALS(PyInterpreterState *interp)
212206
{
213-
struct _ceval_runtime_state *ceval = &interp->runtime->ceval;
214-
struct _ceval_state *ceval2 = &interp->ceval;
215-
_Py_atomic_store_relaxed(&ceval2->signals_pending, 0);
216-
COMPUTE_EVAL_BREAKER(interp, ceval, ceval2);
207+
struct _ceval_state *ceval = &interp->ceval;
208+
_Py_atomic_store_relaxed(&ceval->signals_pending, 0);
209+
COMPUTE_EVAL_BREAKER(interp, ceval);
217210
}
218211

219212

@@ -229,10 +222,9 @@ SIGNAL_ASYNC_EXC(PyInterpreterState *interp)
229222
static inline void
230223
UNSIGNAL_ASYNC_EXC(PyInterpreterState *interp)
231224
{
232-
struct _ceval_runtime_state *ceval = &interp->runtime->ceval;
233-
struct _ceval_state *ceval2 = &interp->ceval;
234-
ceval2->pending.async_exc = 0;
235-
COMPUTE_EVAL_BREAKER(interp, ceval, ceval2);
225+
struct _ceval_state *ceval = &interp->ceval;
226+
ceval->pending.async_exc = 0;
227+
COMPUTE_EVAL_BREAKER(interp, ceval);
236228
}
237229

238230

@@ -357,17 +349,19 @@ PyEval_ReleaseLock(void)
357349
{
358350
_PyRuntimeState *runtime = &_PyRuntime;
359351
PyThreadState *tstate = _PyRuntimeState_GetThreadState(runtime);
352+
struct _ceval_state *ceval2 = &tstate->interp->ceval;
360353
/* This function must succeed when the current thread state is NULL.
361354
We therefore avoid PyThreadState_Get() which dumps a fatal error
362355
in debug mode. */
363-
drop_gil(&runtime->ceval, tstate);
356+
drop_gil(&runtime->ceval, ceval2, tstate);
364357
}
365358

366359
void
367360
_PyEval_ReleaseLock(PyThreadState *tstate)
368361
{
369362
struct _ceval_runtime_state *ceval = &tstate->interp->runtime->ceval;
370-
drop_gil(ceval, tstate);
363+
struct _ceval_state *ceval2 = &tstate->interp->ceval;
364+
drop_gil(ceval, ceval2, tstate);
371365
}
372366

373367
void
@@ -393,7 +387,9 @@ PyEval_ReleaseThread(PyThreadState *tstate)
393387
if (new_tstate != tstate) {
394388
Py_FatalError("wrong thread state");
395389
}
396-
drop_gil(&runtime->ceval, tstate);
390+
struct _ceval_runtime_state *ceval = &runtime->ceval;
391+
struct _ceval_state *ceval2 = &tstate->interp->ceval;
392+
drop_gil(ceval, ceval2, tstate);
397393
}
398394

399395
#ifdef HAVE_FORK
@@ -439,13 +435,14 @@ PyThreadState *
439435
PyEval_SaveThread(void)
440436
{
441437
_PyRuntimeState *runtime = &_PyRuntime;
442-
struct _ceval_runtime_state *ceval = &runtime->ceval;
443438

444439
PyThreadState *tstate = _PyThreadState_Swap(&runtime->gilstate, NULL);
445440
ensure_tstate_not_null(__func__, tstate);
446441

442+
struct _ceval_runtime_state *ceval = &runtime->ceval;
443+
struct _ceval_state *ceval2 = &tstate->interp->ceval;
447444
assert(gil_created(&ceval->gil));
448-
drop_gil(ceval, tstate);
445+
drop_gil(ceval, ceval2, tstate);
449446
return tstate;
450447
}
451448

@@ -847,12 +844,12 @@ eval_frame_handle_pending(PyThreadState *tstate)
847844
}
848845

849846
/* GIL drop request */
850-
if (_Py_atomic_load_relaxed(&ceval->gil_drop_request)) {
847+
if (_Py_atomic_load_relaxed(&ceval2->gil_drop_request)) {
851848
/* Give another thread a chance */
852849
if (_PyThreadState_Swap(&runtime->gilstate, NULL) != tstate) {
853850
Py_FatalError("tstate mix-up");
854851
}
855-
drop_gil(ceval, tstate);
852+
drop_gil(ceval, ceval2, tstate);
856853

857854
/* Other threads may run now */
858855

Python/ceval_gil.h

+7-6
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,8 @@ static void recreate_gil(struct _gil_runtime_state *gil)
141141
}
142142

143143
static void
144-
drop_gil(struct _ceval_runtime_state *ceval, PyThreadState *tstate)
144+
drop_gil(struct _ceval_runtime_state *ceval, struct _ceval_state *ceval2,
145+
PyThreadState *tstate)
145146
{
146147
struct _gil_runtime_state *gil = &ceval->gil;
147148
if (!_Py_atomic_load_relaxed(&gil->locked)) {
@@ -163,7 +164,7 @@ drop_gil(struct _ceval_runtime_state *ceval, PyThreadState *tstate)
163164
MUTEX_UNLOCK(gil->mutex);
164165

165166
#ifdef FORCE_SWITCHING
166-
if (_Py_atomic_load_relaxed(&ceval->gil_drop_request) && tstate != NULL) {
167+
if (_Py_atomic_load_relaxed(&ceval2->gil_drop_request) && tstate != NULL) {
167168
MUTEX_LOCK(gil->switch_mutex);
168169
/* Not switched yet => wait */
169170
if (((PyThreadState*)_Py_atomic_load_relaxed(&gil->last_holder)) == tstate)
@@ -226,6 +227,7 @@ take_gil(PyThreadState *tstate)
226227
assert(is_tstate_valid(tstate));
227228
PyInterpreterState *interp = tstate->interp;
228229
struct _ceval_runtime_state *ceval = &interp->runtime->ceval;
230+
struct _ceval_state *ceval2 = &interp->ceval;
229231
struct _gil_runtime_state *gil = &ceval->gil;
230232

231233
/* Check that _PyEval_InitThreads() was called to create the lock */
@@ -289,12 +291,12 @@ take_gil(PyThreadState *tstate)
289291
in take_gil() while the main thread called
290292
wait_for_thread_shutdown() from Py_Finalize(). */
291293
MUTEX_UNLOCK(gil->mutex);
292-
drop_gil(ceval, tstate);
294+
drop_gil(ceval, ceval2, tstate);
293295
PyThread_exit_thread();
294296
}
295297
assert(is_tstate_valid(tstate));
296298

297-
if (_Py_atomic_load_relaxed(&ceval->gil_drop_request)) {
299+
if (_Py_atomic_load_relaxed(&ceval2->gil_drop_request)) {
298300
RESET_GIL_DROP_REQUEST(interp);
299301
}
300302
else {
@@ -303,8 +305,7 @@ take_gil(PyThreadState *tstate)
303305
handle signals.
304306
305307
Note: RESET_GIL_DROP_REQUEST() calls COMPUTE_EVAL_BREAKER(). */
306-
struct _ceval_state *ceval2 = &interp->ceval;
307-
COMPUTE_EVAL_BREAKER(interp, ceval, ceval2);
308+
COMPUTE_EVAL_BREAKER(interp, ceval2);
308309
}
309310

310311
/* Don't access tstate if the thread must exit */

0 commit comments

Comments
 (0)