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

Skip to content

bpo-33608: Factor out a private, per-interpreter _Py_AddPendingCall(). #11617

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

Merged
merged 15 commits into from
Feb 24, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
Optionally lock a pending call to a specific thread.
  • Loading branch information
ericsnowcurrently committed Feb 23, 2019
commit 4f447cd161b5760cb74128630ceaace0fa6a9930
3 changes: 2 additions & 1 deletion Include/internal/pycore_ceval.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ extern "C" {

struct _is; // See PyInterpreterState in cpython/pystate.h.

PyAPI_FUNC(int) _Py_AddPendingCall(struct _is*, int (*)(void *), void *);
PyAPI_FUNC(int) _Py_AddPendingCall(struct _is*, unsigned long, int (*)(void *), void *);
PyAPI_FUNC(int) _Py_MakePendingCalls(struct _is*);

struct _pending_calls {
Expand All @@ -26,6 +26,7 @@ struct _pending_calls {
int async_exc;
#define NPENDINGCALLS 32
struct {
unsigned long thread_id;
int (*func)(void *);
void *arg;
} calls[NPENDINGCALLS];
Expand Down
2 changes: 2 additions & 0 deletions Modules/signalmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,7 @@ trip_signal(int sig_num)
/* Py_AddPendingCall() isn't signal-safe, but we
still use it for this exceptional case. */
_Py_AddPendingCall(_PyRuntime.interpreters.main,
main_thread,
report_wakeup_send_error,
(void *)(intptr_t) last_error);
}
Expand All @@ -308,6 +309,7 @@ trip_signal(int sig_num)
/* Py_AddPendingCall() isn't signal-safe, but we
still use it for this exceptional case. */
_Py_AddPendingCall(_PyRuntime.interpreters.main,
main_thread,
report_wakeup_write_error,
(void *)(intptr_t)errno);
}
Expand Down
19 changes: 14 additions & 5 deletions Python/ceval.c
Original file line number Diff line number Diff line change
Expand Up @@ -322,23 +322,24 @@ _PyEval_SignalReceived(void)
}

static int
_add_pending_call(PyInterpreterState *interp, int (*func)(void *), void *arg)
_add_pending_call(PyInterpreterState *interp, unsigned long thread_id, int (*func)(void *), void *arg)
{
int i = interp->ceval.pending.last;
int j = (i + 1) % NPENDINGCALLS;
if (j == interp->ceval.pending.first) {
return -1; /* Queue full */
}
interp->ceval.pending.calls[i].thread_id = thread_id;
interp->ceval.pending.calls[i].func = func;
interp->ceval.pending.calls[i].arg = arg;
interp->ceval.pending.last = j;
return 0;
}

/* pop one item off the queue while holding the lock */
static void
_pop_pending_call(PyInterpreterState *interp, int (**func)(void *), void **arg)
{
/* pop one item off the queue while holding the lock */
int i = interp->ceval.pending.first;
if (i == interp->ceval.pending.last) {
return; /* Queue empty */
Expand All @@ -347,13 +348,21 @@ _pop_pending_call(PyInterpreterState *interp, int (**func)(void *), void **arg)
*func = interp->ceval.pending.calls[i].func;
*arg = interp->ceval.pending.calls[i].arg;
interp->ceval.pending.first = (i + 1) % NPENDINGCALLS;

unsigned long thread_id = interp->ceval.pending.calls[i].thread_id;
if (thread_id && PyThread_get_thread_ident() != thread_id) {
// Thread mismatch, so move it to the end of the list
// and start over.
_Py_AddPendingCall(interp, thread_id, *func, *arg);
return;
}
}

int
Py_AddPendingCall(int (*func)(void *), void *arg)
{
PyInterpreterState *interp = _PyRuntime.interpreters.main;
return _Py_AddPendingCall(interp, func, arg);
return _Py_AddPendingCall(interp, _PyRuntime.main_thread, func, arg);
}

/* This implementation is thread-safe. It allows
Expand All @@ -362,7 +371,7 @@ Py_AddPendingCall(int (*func)(void *), void *arg)
*/

int
_Py_AddPendingCall(PyInterpreterState *interp, int (*func)(void *), void *arg)
_Py_AddPendingCall(PyInterpreterState *interp, unsigned long thread_id, int (*func)(void *), void *arg)
{
/* try a few times for the lock. Since this mechanism is used
* for signal handling (on the main thread), there is a (slim)
Expand Down Expand Up @@ -396,7 +405,7 @@ _Py_AddPendingCall(PyInterpreterState *interp, int (*func)(void *), void *arg)
goto done;
}

result = _add_pending_call(interp, func, arg);
result = _add_pending_call(interp, thread_id, func, arg);
/* signal main loop */
SIGNAL_PENDING_CALLS(interp);

Expand Down
0