bpo-35724: Explicitly require the main interpreter for signal-handling. (GH-11530)
Ensure that the main interpreter is active (in the main thread) for signal-handling operations. This is increasingly relevant as people use subinterpreters more. https://bugs.python.org/issue35724
This commit is contained in:
parent
06babb2422
commit
64d6cc826d
|
@ -133,6 +133,7 @@ PyAPI_FUNC(PyObject *) _PyErr_TrySetFromCause(
|
||||||
/* In signalmodule.c */
|
/* In signalmodule.c */
|
||||||
|
|
||||||
int PySignal_SetWakeupFd(int fd);
|
int PySignal_SetWakeupFd(int fd);
|
||||||
|
PyAPI_FUNC(int) _PyErr_CheckSignals(void);
|
||||||
|
|
||||||
/* Support for adding program text to SyntaxErrors */
|
/* Support for adding program text to SyntaxErrors */
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Signal-handling is now guaranteed to happen relative to the main
|
||||||
|
interpreter.
|
|
@ -99,6 +99,7 @@ class sigset_t_converter(CConverter):
|
||||||
#include "pythread.h"
|
#include "pythread.h"
|
||||||
static unsigned long main_thread;
|
static unsigned long main_thread;
|
||||||
static pid_t main_pid;
|
static pid_t main_pid;
|
||||||
|
static PyInterpreterState *main_interp;
|
||||||
|
|
||||||
static volatile struct {
|
static volatile struct {
|
||||||
_Py_atomic_int tripped;
|
_Py_atomic_int tripped;
|
||||||
|
@ -185,6 +186,13 @@ itimer_retval(struct itimerval *iv)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static int
|
||||||
|
is_main(void)
|
||||||
|
{
|
||||||
|
return PyThread_get_thread_ident() == main_thread &&
|
||||||
|
_PyInterpreterState_Get() == main_interp;
|
||||||
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
signal_default_int_handler(PyObject *self, PyObject *args)
|
signal_default_int_handler(PyObject *self, PyObject *args)
|
||||||
{
|
{
|
||||||
|
@ -464,7 +472,7 @@ signal_signal_impl(PyObject *module, int signalnum, PyObject *handler)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (PyThread_get_thread_ident() != main_thread) {
|
if (!is_main()) {
|
||||||
PyErr_SetString(PyExc_ValueError,
|
PyErr_SetString(PyExc_ValueError,
|
||||||
"signal only works in main thread");
|
"signal only works in main thread");
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -486,7 +494,7 @@ signal_signal_impl(PyObject *module, int signalnum, PyObject *handler)
|
||||||
else
|
else
|
||||||
func = signal_handler;
|
func = signal_handler;
|
||||||
/* Check for pending signals before changing signal handler */
|
/* Check for pending signals before changing signal handler */
|
||||||
if (PyErr_CheckSignals()) {
|
if (_PyErr_CheckSignals()) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (PyOS_setsig(signalnum, func) == SIG_ERR) {
|
if (PyOS_setsig(signalnum, func) == SIG_ERR) {
|
||||||
|
@ -681,7 +689,7 @@ signal_set_wakeup_fd(PyObject *self, PyObject *args, PyObject *kwds)
|
||||||
return NULL;
|
return NULL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (PyThread_get_thread_ident() != main_thread) {
|
if (!is_main()) {
|
||||||
PyErr_SetString(PyExc_ValueError,
|
PyErr_SetString(PyExc_ValueError,
|
||||||
"set_wakeup_fd only works in main thread");
|
"set_wakeup_fd only works in main thread");
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -1314,6 +1322,7 @@ PyInit__signal(void)
|
||||||
|
|
||||||
main_thread = PyThread_get_thread_ident();
|
main_thread = PyThread_get_thread_ident();
|
||||||
main_pid = getpid();
|
main_pid = getpid();
|
||||||
|
main_interp = _PyInterpreterState_Get();
|
||||||
|
|
||||||
/* Create the module and add the functions */
|
/* Create the module and add the functions */
|
||||||
m = PyModule_Create(&signalmodule);
|
m = PyModule_Create(&signalmodule);
|
||||||
|
@ -1606,6 +1615,18 @@ finisignal(void)
|
||||||
/* Declared in pyerrors.h */
|
/* Declared in pyerrors.h */
|
||||||
int
|
int
|
||||||
PyErr_CheckSignals(void)
|
PyErr_CheckSignals(void)
|
||||||
|
{
|
||||||
|
if (!is_main()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _PyErr_CheckSignals();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Declared in cpython/pyerrors.h */
|
||||||
|
int
|
||||||
|
_PyErr_CheckSignals(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
PyObject *f;
|
PyObject *f;
|
||||||
|
@ -1613,9 +1634,6 @@ PyErr_CheckSignals(void)
|
||||||
if (!_Py_atomic_load(&is_tripped))
|
if (!_Py_atomic_load(&is_tripped))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (PyThread_get_thread_ident() != main_thread)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The is_tripped variable is meant to speed up the calls to
|
* The is_tripped variable is meant to speed up the calls to
|
||||||
* PyErr_CheckSignals (both directly or via pending calls) when no
|
* PyErr_CheckSignals (both directly or via pending calls) when no
|
||||||
|
@ -1687,8 +1705,9 @@ int
|
||||||
PyOS_InterruptOccurred(void)
|
PyOS_InterruptOccurred(void)
|
||||||
{
|
{
|
||||||
if (_Py_atomic_load_relaxed(&Handlers[SIGINT].tripped)) {
|
if (_Py_atomic_load_relaxed(&Handlers[SIGINT].tripped)) {
|
||||||
if (PyThread_get_thread_ident() != main_thread)
|
if (!is_main()) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
_Py_atomic_store_relaxed(&Handlers[SIGINT].tripped, 0);
|
_Py_atomic_store_relaxed(&Handlers[SIGINT].tripped, 0);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -1716,12 +1735,13 @@ _PySignal_AfterFork(void)
|
||||||
_clear_pending_signals();
|
_clear_pending_signals();
|
||||||
main_thread = PyThread_get_thread_ident();
|
main_thread = PyThread_get_thread_ident();
|
||||||
main_pid = getpid();
|
main_pid = getpid();
|
||||||
|
main_interp = _PyInterpreterState_Get();
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
_PyOS_IsMainThread(void)
|
_PyOS_IsMainThread(void)
|
||||||
{
|
{
|
||||||
return PyThread_get_thread_ident() == main_thread;
|
return is_main();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef MS_WINDOWS
|
#ifdef MS_WINDOWS
|
||||||
|
|
|
@ -379,9 +379,16 @@ handle_signals(void)
|
||||||
{
|
{
|
||||||
return 0;
|
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();
|
UNSIGNAL_PENDING_SIGNALS();
|
||||||
if (PyErr_CheckSignals() < 0) {
|
if (_PyErr_CheckSignals() < 0) {
|
||||||
SIGNAL_PENDING_SIGNALS(); /* We're not done yet */
|
SIGNAL_PENDING_SIGNALS(); /* We're not done yet */
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue