Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
1 change: 1 addition & 0 deletions Include/cpython/pyerrors.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ PyAPI_FUNC(PyObject *) _PyErr_TrySetFromCause(
/* In signalmodule.c */

int PySignal_SetWakeupFd(int fd);
PyAPI_FUNC(int) _PyErr_CheckSignals(void);

/* Support for adding program text to SyntaxErrors */

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Signal-handling is now guaranteed to happen relative to the main
interpreter.
36 changes: 28 additions & 8 deletions Modules/signalmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ class sigset_t_converter(CConverter):
#include "pythread.h"
static unsigned long main_thread;
static pid_t main_pid;
static PyInterpreterState *main_interp;

static volatile struct {
_Py_atomic_int tripped;
Expand Down Expand Up @@ -185,6 +186,13 @@ itimer_retval(struct itimerval *iv)
}
#endif

static int
is_main(void)
Comment thread
ericsnowcurrently marked this conversation as resolved.
Outdated
{
return PyThread_get_thread_ident() == main_thread &&
_PyInterpreterState_Get() == main_interp;
}

static PyObject *
signal_default_int_handler(PyObject *self, PyObject *args)
{
Expand Down Expand Up @@ -464,7 +472,7 @@ signal_signal_impl(PyObject *module, int signalnum, PyObject *handler)
return NULL;
}
#endif
if (PyThread_get_thread_ident() != main_thread) {
if (!is_main()) {
PyErr_SetString(PyExc_ValueError,
"signal only works in main thread");
return NULL;
Expand All @@ -486,7 +494,7 @@ signal_signal_impl(PyObject *module, int signalnum, PyObject *handler)
else
func = signal_handler;
/* Check for pending signals before changing signal handler */
if (PyErr_CheckSignals()) {
if (_PyErr_CheckSignals()) {
return NULL;
}
if (PyOS_setsig(signalnum, func) == SIG_ERR) {
Expand Down Expand Up @@ -681,7 +689,7 @@ signal_set_wakeup_fd(PyObject *self, PyObject *args, PyObject *kwds)
return NULL;
#endif

if (PyThread_get_thread_ident() != main_thread) {
if (!is_main()) {
PyErr_SetString(PyExc_ValueError,
"set_wakeup_fd only works in main thread");
return NULL;
Expand Down Expand Up @@ -1314,6 +1322,7 @@ PyInit__signal(void)

main_thread = PyThread_get_thread_ident();
main_pid = getpid();
main_interp = _PyInterpreterState_Get();

/* Create the module and add the functions */
m = PyModule_Create(&signalmodule);
Expand Down Expand Up @@ -1606,16 +1615,25 @@ finisignal(void)
/* Declared in pyerrors.h */
int
PyErr_CheckSignals(void)
{
if (!is_main()) {
return 0;
}

return _PyErr_CheckSignals();
}


/* Declared in cpython/pyerrors.h */
int
_PyErr_CheckSignals(void)
{
int i;
PyObject *f;

if (!_Py_atomic_load(&is_tripped))
return 0;

if (PyThread_get_thread_ident() != main_thread)
return 0;

/*
* The is_tripped variable is meant to speed up the calls to
* PyErr_CheckSignals (both directly or via pending calls) when no
Expand Down Expand Up @@ -1687,8 +1705,9 @@ int
PyOS_InterruptOccurred(void)
{
if (_Py_atomic_load_relaxed(&Handlers[SIGINT].tripped)) {
if (PyThread_get_thread_ident() != main_thread)
if (!is_main()) {
return 0;
}
_Py_atomic_store_relaxed(&Handlers[SIGINT].tripped, 0);
return 1;
}
Expand Down Expand Up @@ -1716,12 +1735,13 @@ _PySignal_AfterFork(void)
_clear_pending_signals();
main_thread = PyThread_get_thread_ident();
main_pid = getpid();
main_interp = _PyInterpreterState_Get();
}

int
_PyOS_IsMainThread(void)
{
return PyThread_get_thread_ident() == main_thread;
return is_main();
}

#ifdef MS_WINDOWS
Expand Down
9 changes: 8 additions & 1 deletion Python/ceval.c
Original file line number Diff line number Diff line change
Expand Up @@ -379,9 +379,16 @@ handle_signals(void)
{
return 0;
}
/*
* Ensure that the thread isn't currently running some other
* interpreter.
*/
if (_PyInterpreterState_GET_UNSAFE() != _PyRuntime.interpreters.main) {
return 0;
}

UNSIGNAL_PENDING_SIGNALS();
if (PyErr_CheckSignals() < 0) {
if (_PyErr_CheckSignals() < 0) {
SIGNAL_PENDING_SIGNALS(); /* We're not done yet */
return -1;
}
Expand Down