8000 [WIP] bpo-33608: Factor out a private, per-interpreter _Py_AddPendingCall(). by ericsnowcurrently · Pull Request #9334 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

[WIP] bpo-33608: Factor out a private, per-interpreter _Py_AddPendingCall(). #9334

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Explicitly pass the interpreter to the stateful ceval macros.
  • Loading branch information
ericsnowcurrently committed Sep 14, 2018
commit 9ebc65b7815802e2476a8ed22ad4b5c67df6a6b5
2 changes: 1 addition & 1 deletion Include/ceval.h
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ PyAPI_FUNC(Py_ssize_t) _PyEval_RequestCodeExtraIndex(freefunc);
#ifndef Py_LIMITED_API
PyAPI_FUNC(int) _PyEval_SliceIndex(PyObject *, Py_ssize_t *);
PyAPI_FUNC(int) _PyEval_SliceIndexNotNone(PyObject *, Py_ssize_t *);
PyAPI_FUNC(void) _PyEval_SignalAsyncExc(void);
PyAPI_FUNC(void) _PyEval_SignalAsyncExc(PyInterpreterState *);
#endif

/* Masks and values used by FORMAT_VALUE opcode. */
Expand Down
56 changes: 29 additions & 27 deletions Python/ceval.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,48 +94,48 @@ static long dxp[256];
/* This can set eval_breaker to 0 even though gil_drop_request became
1. We believe this is all right because the eval loop will release
the GIL eventually anyway. */
#define COMPUTE_EVAL_BREAKER() \
#define COMPUTE_EVAL_BREAKER(interp) \
_Py_atomic_store_relaxed( \
&PyThreadState_Get()->interp->ceval.eval_breaker, \
&interp->ceval.eval_breaker, \
GIL_REQUEST | \
_Py_atomic_load_relaxed(&PyThreadState_Get()->interp->ceval.pending.calls_to_do) | \
PyThreadState_Get()->interp->ceval.pending.async_exc)
_Py_atomic_load_relaxed(&interp->ceval.pending.calls_to_do) | \
interp->ceval.pending.async_exc)

#define SET_GIL_DROP_REQUEST() \
#define SET_GIL_DROP_REQUEST(interp) \
do { \
_Py_atomic_store_relaxed(&_PyRuntime.ceval.gil_drop_request, 1); \
_Py_atomic_store_relaxed(&PyThreadState_Get()->interp->ceval.eval_breaker, 1); \
_Py_atomic_store_relaxed(&interp->ceval.eval_breaker, 1); \
} while (0)

#define RESET_GIL_DROP_REQUEST() \
#define RESET_GIL_DROP_REQUEST(interp) \
do { \
_Py_atomic_store_relaxed(&_PyRuntime.ceval.gil_drop_request, 0); \
COMPUTE_EVAL_BREAKER(); \
COMPUTE_EVAL_BREAKER(interp); \
} while (0)

/* Pending calls are only modified under pending_lock */
#define SIGNAL_PENDING_CALLS() \
#define SIGNAL_PENDING_CALLS(interp) \
do { \
_Py_atomic_store_relaxed(&PyThreadState_Get()->interp->ceval.pending.calls_to_do, 1); \
_Py_atomic_store_relaxed(&PyThreadState_Get()->interp->ceval.eval_breaker, 1); \
_Py_atomic_store_relaxed(&interp->ceval.pending.calls_to_do, 1); \
_Py_atomic_store_relaxed(&interp->ceval.eval_breaker, 1); \
} while (0)

#define UNSIGNAL_PENDING_CALLS() \
#define UNSIGNAL_PENDING_CALLS(interp) \
do { \
_Py_atomic_store_relaxed(&PyThreadState_Get()->interp->ceval.pending.calls_to_do, 0); \
COMPUTE_EVAL_BREAKER(); \
_Py_atomic_store_relaxed(&interp->ceval.pending.calls_to_do, 0); \
COMPUTE_EVAL_BREAKER(interp); \
} while (0)

#define SIGNAL_ASYNC_EXC() \
#define SIGNAL_ASYNC_EXC(interp) \
do { \
PyThreadState_Get()->interp->ceval.pending.async_exc = 1; \
_Py_atomic_store_relaxed(&PyThreadState_Get()->interp->ceval.eval_breaker, 1); \
interp->ceval.pending.async_exc = 1; \
_Py_atomic_store_relaxed(&interp->ceval.eval_breaker, 1); \
} while (0)

#define UNSIGNAL_ASYNC_EXC() \
#define UNSIGNAL_ASYNC_EXC(interp) \
do { \
PyThreadState_Get()->interp->ceval.pending.async_exc = 0; \
COMPUTE_EVAL_BREAKER(); \
interp->ceval.pending.async_exc = 0; \
COMPUTE_EVAL_BREAKER(interp); \
} while (0)


Expand Down Expand Up @@ -239,9 +239,9 @@ PyEval_ReInitThreads(void)
raised, therefore it is also useful in non-threaded builds. */

void
_PyEval_SignalAsyncExc(void)
_PyEval_SignalAsyncExc(PyInterpreterState *interp)
{
SIGNAL_ASYNC_EXC();
SIGNAL_ASYNC_EXC(interp);
}

/* Functions save_thread and restore_thread are always defined so
Expand Down Expand Up @@ -308,7 +308,9 @@ _PyEval_SignalReceived(void)
/* bpo-30703: Function called when the C signal handler of Python gets a
signal. We cannot queue a callback using Py_AddPendingCall() since
that function is not async-signal-safe. */
SIGNAL_PENDING_CALLS();
/* Note that we explicitly use the main interpreter. Signals
are always handled by the main interpreter. */
SIGNAL_PENDING_CALLS(_PyRuntime.interpreters.main);
}

int
Expand Down Expand Up @@ -359,7 +361,7 @@ _Py_AddPendingCall(PyInterpreterState *interp, int (*func)(void *), void *arg)
interp->ceval.pending.last = j;
}
/* signal main loop */
SIGNAL_PENDING_CALLS();
SIGNAL_PENDING_CALLS(interp);
if (lock != NULL)
PyThread_release_lock(lock);
return result;
Expand Down Expand Up @@ -400,7 +402,7 @@ _Py_MakePendingCalls(PyInterpreterState *interp)
busy = 1;
/* unsignal before starting to call callbacks, so that any callback
added in-between re-signals */
UNSIGNAL_PENDING_CALLS();
UNSIGNAL_PENDING_CALLS(interp);

/* Python signal handler doesn't really queue a callback: it only signals
that a signal was received, see _PyEval_SignalReceived(). */
Expand Down Expand Up @@ -439,7 +441,7 @@ _Py_MakePendingCalls(PyInterpreterState *interp)

error:
busy = 0;
SIGNAL_PENDING_CALLS(); /* We're not done yet */
SIGNAL_PENDING_CALLS(interp); /* We're not done yet */
return -1;
}

Expand Down Expand Up @@ -1007,7 +1009,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
if (tstate->async_exc != NULL) {
PyObject *exc = tstate->async_exc;
tstate->async_exc = NULL;
UNSIGNAL_ASYNC_EXC();
UNSIGNAL_ASYNC_EXC(tstate->interp);
PyErr_SetNone(exc);
Py_DECREF(exc);
goto error;
Expand Down
8 changes: 4 additions & 4 deletions Python/ceval_gil.h
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ static void drop_gil(PyThreadState *tstate)
&_PyRuntime.ceval.gil.last_holder)
) == tstate)
{
RESET_GIL_DROP_REQUEST();
RESET_GIL_DROP_REQUEST(tstate->interp);
/* NOTE: if COND_WAIT does not atomically start waiting when
releasing the mutex, another thread can run through, take
the GIL and drop it again, and reset the condition
Expand Down Expand Up @@ -212,7 +212,7 @@ static void take_gil(PyThreadState *tstate)
if (timed_out &&
_Py_atomic_load_relaxed(&_PyRuntime.ceval.gil.locked) &&
_PyRuntime.ceval.gil.switch_number == saved_switchnum) {
SET_GIL_DROP_REQUEST();
SET_GIL_DROP_REQUEST(tstate->interp);
}
}
_ready:
Expand All @@ -238,10 +238,10 @@ static void take_gil(PyThreadState *tstate)
MUTEX_UNLOCK(_PyRuntime.ceval.gil.switch_mutex);
#endif
if (_Py_atomic_load_relaxed(&_PyRuntime.ceval.gil_drop_request)) {
RESET_GIL_DROP_REQUEST();
RESET_GIL_DROP_REQUEST(tstate->interp);
}
if (tstate->async_exc != NULL) {
_PyEval_SignalAsyncExc();
_PyEval_SignalAsyncExc(tstate->interp);
}

MUTEX_UNLOCK(_PyRuntime.ceval.gil.mutex);
Expand Down
2 changes: 1 addition & 1 deletion Python/pystate.c
Original file line number Diff line number Diff line change
Expand Up @@ -847,7 +847,7 @@ PyThreadState_SetAsyncExc(unsigned long id, PyObject *exc)
p->async_exc = exc;
HEAD_UNLOCK();
Py_XDECREF(old_exc);
_PyEval_SignalAsyncExc();
_PyEval_SignalAsyncExc(interp);
return 1;
}
}
Expand Down
0