mirror of https://github.com/python/cpython
bpo-43963: Add _signal module state (GH-25676)
* Add signal_state_t structure and signal_global_state variable. * Add a module state to the _signal module. * Move and rename variables: * DefaultHandler becomes state->default_handler * IgnoreHandler becomes state->ignore_handler * sigint_event becomes state->sigint_event * ItimerError becomes modstate->itimer_error * Rename SetHandler() to set_handler() to be consistent with get_handler().
This commit is contained in:
parent
5c84bb506a
commit
a5e64444e6
|
@ -4,38 +4,39 @@
|
|||
/* XXX Signals should be recorded per thread, now we have thread state. */
|
||||
|
||||
#include "Python.h"
|
||||
#include "pycore_atomic.h"
|
||||
#include "pycore_call.h"
|
||||
#include "pycore_ceval.h"
|
||||
#include "pycore_pyerrors.h"
|
||||
#include "pycore_pylifecycle.h"
|
||||
#include "pycore_pystate.h" // _PyThreadState_GET()
|
||||
#include "pycore_atomic.h" // _Py_atomic_int
|
||||
#include "pycore_call.h" // _PyObject_Call()
|
||||
#include "pycore_ceval.h" // _PyEval_SignalReceived()
|
||||
#include "pycore_moduleobject.h" // _PyModule_GetState()
|
||||
#include "pycore_pyerrors.h" // _PyErr_SetString()
|
||||
#include "pycore_pylifecycle.h" // NSIG
|
||||
#include "pycore_pystate.h" // _PyThreadState_GET()
|
||||
|
||||
#ifndef MS_WINDOWS
|
||||
#include "posixmodule.h"
|
||||
# include "posixmodule.h"
|
||||
#endif
|
||||
#ifdef MS_WINDOWS
|
||||
#include "socketmodule.h" /* needed for SOCKET_T */
|
||||
# include "socketmodule.h" /* needed for SOCKET_T */
|
||||
#endif
|
||||
|
||||
#ifdef MS_WINDOWS
|
||||
#include <windows.h>
|
||||
#ifdef HAVE_PROCESS_H
|
||||
#include <process.h>
|
||||
#endif
|
||||
# include <windows.h>
|
||||
# ifdef HAVE_PROCESS_H
|
||||
# include <process.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SIGNAL_H
|
||||
#include <signal.h>
|
||||
# include <signal.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SYSCALL_H
|
||||
#include <sys/syscall.h>
|
||||
# include <sys/syscall.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
# include <sys/stat.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
# include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_PTHREAD_SIGMASK) && !defined(HAVE_BROKEN_PTHREAD_SIGMASK)
|
||||
|
@ -47,7 +48,7 @@
|
|||
#endif
|
||||
|
||||
#ifndef SIG_ERR
|
||||
#define SIG_ERR ((PyOS_sighandler_t)(-1))
|
||||
# define SIG_ERR ((PyOS_sighandler_t)(-1))
|
||||
#endif
|
||||
|
||||
#include "clinic/signalmodule.c.h"
|
||||
|
@ -124,27 +125,52 @@ static volatile struct {
|
|||
/* Speed up sigcheck() when none tripped */
|
||||
static _Py_atomic_int is_tripped;
|
||||
|
||||
static PyObject *DefaultHandler;
|
||||
static PyObject *IgnoreHandler;
|
||||
|
||||
typedef struct {
|
||||
PyObject *default_handler;
|
||||
PyObject *ignore_handler;
|
||||
#ifdef MS_WINDOWS
|
||||
static HANDLE sigint_event = NULL;
|
||||
HANDLE sigint_event;
|
||||
#endif
|
||||
} signal_state_t;
|
||||
|
||||
// State shared by all Python interpreters
|
||||
static signal_state_t signal_global_state = {0};
|
||||
|
||||
#if defined(HAVE_GETITIMER) || defined(HAVE_SETITIMER)
|
||||
static PyObject *ItimerError;
|
||||
# define PYHAVE_ITIMER_ERROR
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
PyObject *default_handler; // borrowed ref (signal_global_state)
|
||||
PyObject *ignore_handler; // borrowed ref (signal_global_state)
|
||||
#ifdef PYHAVE_ITIMER_ERROR
|
||||
PyObject *itimer_error;
|
||||
#endif
|
||||
} _signal_module_state;
|
||||
|
||||
|
||||
Py_LOCAL_INLINE(PyObject *)
|
||||
get_handler(int i) {
|
||||
get_handler(int i)
|
||||
{
|
||||
return (PyObject *)_Py_atomic_load(&Handlers[i].func);
|
||||
}
|
||||
|
||||
Py_LOCAL_INLINE(void)
|
||||
SetHandler(int i, PyObject* func) {
|
||||
set_handler(int i, PyObject* func)
|
||||
{
|
||||
_Py_atomic_store(&Handlers[i].func, (uintptr_t)func);
|
||||
}
|
||||
|
||||
|
||||
static inline _signal_module_state*
|
||||
get_signal_state(PyObject *module)
|
||||
{
|
||||
void *state = _PyModule_GetState(module);
|
||||
assert(state != NULL);
|
||||
return (_signal_module_state *)state;
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAVE_GETITIMER
|
||||
/* auxiliary functions for setitimer */
|
||||
static int
|
||||
|
@ -359,8 +385,10 @@ signal_handler(int sig_num)
|
|||
errno = save_errno;
|
||||
|
||||
#ifdef MS_WINDOWS
|
||||
if (sig_num == SIGINT)
|
||||
SetEvent(sigint_event);
|
||||
if (sig_num == SIGINT) {
|
||||
signal_state_t *state = &signal_global_state;
|
||||
SetEvent(state->sigint_event);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -459,6 +487,7 @@ static PyObject *
|
|||
signal_signal_impl(PyObject *module, int signalnum, PyObject *handler)
|
||||
/*[clinic end generated code: output=b44cfda43780f3a1 input=deee84af5fa0432c]*/
|
||||
{
|
||||
_signal_module_state *modstate = get_signal_state(module);
|
||||
PyObject *old_handler;
|
||||
void (*func)(int);
|
||||
#ifdef MS_WINDOWS
|
||||
|
@ -493,10 +522,10 @@ signal_signal_impl(PyObject *module, int signalnum, PyObject *handler)
|
|||
"signal number out of range");
|
||||
return NULL;
|
||||
}
|
||||
if (handler == IgnoreHandler) {
|
||||
if (handler == modstate->ignore_handler) {
|
||||
func = SIG_IGN;
|
||||
}
|
||||
else if (handler == DefaultHandler) {
|
||||
else if (handler == modstate->default_handler) {
|
||||
func = SIG_DFL;
|
||||
}
|
||||
else if (!PyCallable_Check(handler)) {
|
||||
|
@ -519,7 +548,7 @@ signal_signal_impl(PyObject *module, int signalnum, PyObject *handler)
|
|||
}
|
||||
|
||||
old_handler = get_handler(signalnum);
|
||||
SetHandler(signalnum, Py_NewRef(handler));
|
||||
set_handler(signalnum, Py_NewRef(handler));
|
||||
|
||||
if (old_handler != NULL) {
|
||||
return old_handler;
|
||||
|
@ -831,7 +860,6 @@ PySignal_SetWakeupFd(int fd)
|
|||
|
||||
|
||||
#ifdef HAVE_SETITIMER
|
||||
|
||||
/*[clinic input]
|
||||
signal.setitimer
|
||||
|
||||
|
@ -853,8 +881,9 @@ signal_setitimer_impl(PyObject *module, int which, PyObject *seconds,
|
|||
PyObject *interval)
|
||||
/*[clinic end generated code: output=65f9dcbddc35527b input=de43daf194e6f66f]*/
|
||||
{
|
||||
struct itimerval new;
|
||||
_signal_module_state *modstate = get_signal_state(module);
|
||||
|
||||
struct itimerval new;
|
||||
if (timeval_from_double(seconds, &new.it_value) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
@ -865,18 +894,16 @@ signal_setitimer_impl(PyObject *module, int which, PyObject *seconds,
|
|||
/* Let OS check "which" value */
|
||||
struct itimerval old;
|
||||
if (setitimer(which, &new, &old) != 0) {
|
||||
PyErr_SetFromErrno(ItimerError);
|
||||
PyErr_SetFromErrno(modstate->itimer_error);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return itimer_retval(&old);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // HAVE_SETITIMER
|
||||
|
||||
|
||||
#ifdef HAVE_GETITIMER
|
||||
|
||||
/*[clinic input]
|
||||
signal.getitimer
|
||||
|
||||
|
@ -890,17 +917,18 @@ static PyObject *
|
|||
signal_getitimer_impl(PyObject *module, int which)
|
||||
/*[clinic end generated code: output=9e053175d517db40 input=f7d21d38f3490627]*/
|
||||
{
|
||||
struct itimerval old;
|
||||
_signal_module_state *modstate = get_signal_state(module);
|
||||
|
||||
struct itimerval old;
|
||||
if (getitimer(which, &old) != 0) {
|
||||
PyErr_SetFromErrno(ItimerError);
|
||||
PyErr_SetFromErrno(modstate->itimer_error);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return itimer_retval(&old);
|
||||
}
|
||||
#endif // HAVE_GETITIMER
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(PYPTHREAD_SIGMASK) || defined(HAVE_SIGPENDING)
|
||||
static PyObject*
|
||||
|
@ -1544,17 +1572,17 @@ signal_add_constants(PyObject *module)
|
|||
|
||||
|
||||
static int
|
||||
signal_get_set_handlers(PyObject *mod_dict)
|
||||
signal_get_set_handlers(signal_state_t *state, PyObject *mod_dict)
|
||||
{
|
||||
// Get signal handlers
|
||||
for (int signum = 1; signum < NSIG; signum++) {
|
||||
void (*c_handler)(int) = PyOS_getsig(signum);
|
||||
PyObject *func;
|
||||
if (c_handler == SIG_DFL) {
|
||||
func = DefaultHandler;
|
||||
func = state->default_handler;
|
||||
}
|
||||
else if (c_handler == SIG_IGN) {
|
||||
func = IgnoreHandler;
|
||||
func = state->ignore_handler;
|
||||
}
|
||||
else {
|
||||
func = Py_None; // None of our business
|
||||
|
@ -1562,20 +1590,20 @@ signal_get_set_handlers(PyObject *mod_dict)
|
|||
// If signal_module_exec() is called more than one, we must
|
||||
// clear the strong reference to the previous function.
|
||||
PyObject* old_func = get_handler(signum);
|
||||
SetHandler(signum, Py_NewRef(func));
|
||||
set_handler(signum, Py_NewRef(func));
|
||||
Py_XDECREF(old_func);
|
||||
}
|
||||
|
||||
// Instal Python SIGINT handler which raises KeyboardInterrupt
|
||||
PyObject* sigint_func = get_handler(SIGINT);
|
||||
if (sigint_func == DefaultHandler) {
|
||||
if (sigint_func == state->default_handler) {
|
||||
PyObject *int_handler = PyMapping_GetItemString(mod_dict,
|
||||
"default_int_handler");
|
||||
if (!int_handler) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
SetHandler(SIGINT, int_handler);
|
||||
set_handler(SIGINT, int_handler);
|
||||
Py_DECREF(sigint_func);
|
||||
PyOS_setsig(SIGINT, signal_handler);
|
||||
}
|
||||
|
@ -1588,20 +1616,34 @@ signal_module_exec(PyObject *m)
|
|||
{
|
||||
assert(!PyErr_Occurred());
|
||||
|
||||
signal_state_t *state = &signal_global_state;
|
||||
_signal_module_state *modstate = get_signal_state(m);
|
||||
|
||||
modstate->default_handler = state->default_handler; // borrowed ref
|
||||
modstate->ignore_handler = state->ignore_handler; // borrowed ref
|
||||
|
||||
#ifdef PYHAVE_ITIMER_ERROR
|
||||
modstate->itimer_error = PyErr_NewException("signal.itimer_error",
|
||||
PyExc_OSError, NULL);
|
||||
if (modstate->itimer_error == NULL) {
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (signal_add_constants(m) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Add some symbolic constants to the module */
|
||||
PyObject *d = PyModule_GetDict(m);
|
||||
if (PyDict_SetItemString(d, "SIG_DFL", DefaultHandler) < 0) {
|
||||
if (PyDict_SetItemString(d, "SIG_DFL", state->default_handler) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (PyDict_SetItemString(d, "SIG_IGN", IgnoreHandler) < 0) {
|
||||
if (PyDict_SetItemString(d, "SIG_IGN", state->ignore_handler) < 0) {
|
||||
return -1;
|
||||
}
|
||||
#if defined(HAVE_GETITIMER) || defined(HAVE_SETITIMER)
|
||||
if (PyDict_SetItemString(d, "ItimerError", ItimerError) < 0) {
|
||||
#ifdef PYHAVE_ITIMER_ERROR
|
||||
if (PyDict_SetItemString(d, "ItimerError", modstate->itimer_error) < 0) {
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
@ -1613,7 +1655,7 @@ signal_module_exec(PyObject *m)
|
|||
|
||||
PyThreadState *tstate = _PyThreadState_GET();
|
||||
if (_Py_IsMainInterpreter(tstate->interp)) {
|
||||
if (signal_get_set_handlers(d) < 0) {
|
||||
if (signal_get_set_handlers(state, d) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
@ -1623,6 +1665,31 @@ signal_module_exec(PyObject *m)
|
|||
}
|
||||
|
||||
|
||||
#ifdef PYHAVE_ITIMER_ERROR
|
||||
static int
|
||||
_signal_module_traverse(PyObject *module, visitproc visit, void *arg)
|
||||
{
|
||||
_signal_module_state *modstate = get_signal_state(module);
|
||||
Py_VISIT(modstate->itimer_error);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
_signal_module_clear(PyObject *module)
|
||||
{
|
||||
_signal_module_state *modstate = get_signal_state(module);
|
||||
Py_CLEAR(modstate->itimer_error);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_signal_module_free(void *module)
|
||||
{
|
||||
_signal_module_clear((PyObject *)module);
|
||||
}
|
||||
#endif // PYHAVE_ITIMER_ERROR
|
||||
|
||||
|
||||
static PyModuleDef_Slot signal_slots[] = {
|
||||
{Py_mod_exec, signal_module_exec},
|
||||
{0, NULL}
|
||||
|
@ -1632,9 +1699,14 @@ static struct PyModuleDef signal_module = {
|
|||
PyModuleDef_HEAD_INIT,
|
||||
"_signal",
|
||||
.m_doc = module_doc,
|
||||
.m_size = 0,
|
||||
.m_size = sizeof(_signal_module_state),
|
||||
.m_methods = signal_methods,
|
||||
.m_slots = signal_slots,
|
||||
#ifdef PYHAVE_ITIMER_ERROR
|
||||
.m_traverse = _signal_module_traverse,
|
||||
.m_clear = _signal_module_clear,
|
||||
.m_free = _signal_module_free,
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
@ -1648,15 +1720,17 @@ PyInit__signal(void)
|
|||
void
|
||||
_PySignal_Fini(void)
|
||||
{
|
||||
signal_state_t *state = &signal_global_state;
|
||||
|
||||
// Restore default signals and clear handlers
|
||||
for (int signum = 1; signum < NSIG; signum++) {
|
||||
PyObject *func = get_handler(signum);
|
||||
_Py_atomic_store_relaxed(&Handlers[signum].tripped, 0);
|
||||
SetHandler(signum, NULL);
|
||||
set_handler(signum, NULL);
|
||||
if (func != NULL
|
||||
&& func != Py_None
|
||||
&& func != DefaultHandler
|
||||
&& func != IgnoreHandler)
|
||||
&& func != state->default_handler
|
||||
&& func != state->ignore_handler)
|
||||
{
|
||||
PyOS_setsig(signum, SIG_DFL);
|
||||
}
|
||||
|
@ -1664,17 +1738,14 @@ _PySignal_Fini(void)
|
|||
}
|
||||
|
||||
#ifdef MS_WINDOWS
|
||||
if (sigint_event != NULL) {
|
||||
CloseHandle(sigint_event);
|
||||
sigint_event = NULL;
|
||||
if (state->sigint_event != NULL) {
|
||||
CloseHandle(state->sigint_event);
|
||||
state->sigint_event = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
Py_CLEAR(DefaultHandler);
|
||||
Py_CLEAR(IgnoreHandler);
|
||||
#if defined(HAVE_GETITIMER) || defined(HAVE_SETITIMER)
|
||||
Py_CLEAR(ItimerError);
|
||||
#endif
|
||||
Py_CLEAR(state->default_handler);
|
||||
Py_CLEAR(state->ignore_handler);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1720,6 +1791,7 @@ _PyErr_CheckSignalsTstate(PyThreadState *tstate)
|
|||
frame = Py_None;
|
||||
}
|
||||
|
||||
signal_state_t *state = &signal_global_state;
|
||||
for (int i = 1; i < NSIG; i++) {
|
||||
if (!_Py_atomic_load_relaxed(&Handlers[i].tripped)) {
|
||||
continue;
|
||||
|
@ -1733,8 +1805,8 @@ _PyErr_CheckSignalsTstate(PyThreadState *tstate)
|
|||
* (see bpo-43406).
|
||||
*/
|
||||
PyObject *func = get_handler(i);
|
||||
if (func == NULL || func == Py_None || func == IgnoreHandler ||
|
||||
func == DefaultHandler) {
|
||||
if (func == NULL || func == Py_None || func == state->ignore_handler ||
|
||||
func == state->default_handler) {
|
||||
/* No Python signal handler due to aforementioned race condition.
|
||||
* We can't call raise() as it would break the assumption
|
||||
* that PyErr_SetInterrupt() only *simulates* an incoming
|
||||
|
@ -1791,8 +1863,10 @@ PyErr_SetInterruptEx(int signum)
|
|||
if (signum < 1 || signum >= NSIG) {
|
||||
return -1;
|
||||
}
|
||||
PyObject* func = get_handler(signum);
|
||||
if (func != IgnoreHandler && func != DefaultHandler) {
|
||||
|
||||
signal_state_t *state = &signal_global_state;
|
||||
PyObject *func = get_handler(signum);
|
||||
if (func != state->ignore_handler && func != state->default_handler) {
|
||||
trip_signal(signum);
|
||||
}
|
||||
return 0;
|
||||
|
@ -1854,28 +1928,22 @@ _Py_RestoreSignals(void)
|
|||
int
|
||||
_PySignal_Init(int install_signal_handlers)
|
||||
{
|
||||
DefaultHandler = PyLong_FromVoidPtr((void *)SIG_DFL);
|
||||
if (!DefaultHandler) {
|
||||
signal_state_t *state = &signal_global_state;
|
||||
|
||||
state->default_handler = PyLong_FromVoidPtr((void *)SIG_DFL);
|
||||
if (state->default_handler == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
IgnoreHandler = PyLong_FromVoidPtr((void *)SIG_IGN);
|
||||
if (!IgnoreHandler) {
|
||||
state->ignore_handler = PyLong_FromVoidPtr((void *)SIG_IGN);
|
||||
if (state->ignore_handler == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if defined(HAVE_GETITIMER) || defined(HAVE_SETITIMER)
|
||||
ItimerError = PyErr_NewException("signal.ItimerError",
|
||||
PyExc_OSError, NULL);
|
||||
if (!ItimerError) {
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MS_WINDOWS
|
||||
/* Create manual-reset event, initially unset */
|
||||
sigint_event = CreateEvent(NULL, TRUE, FALSE, FALSE);
|
||||
if (sigint_event == NULL) {
|
||||
state->sigint_event = CreateEvent(NULL, TRUE, FALSE, FALSE);
|
||||
if (state->sigint_event == NULL) {
|
||||
PyErr_SetFromWindowsErr(0);
|
||||
return -1;
|
||||
}
|
||||
|
@ -1963,13 +2031,14 @@ _PyOS_IsMainThread(void)
|
|||
}
|
||||
|
||||
#ifdef MS_WINDOWS
|
||||
/* Returns a manual-reset event which gets tripped whenever
|
||||
SIGINT is received.
|
||||
|
||||
Python.h does not include windows.h so we do cannot use HANDLE
|
||||
as the return type of this function. We use void* instead. */
|
||||
void *_PyOS_SigintEvent(void)
|
||||
{
|
||||
/* Returns a manual-reset event which gets tripped whenever
|
||||
SIGINT is received.
|
||||
|
||||
Python.h does not include windows.h so we do cannot use HANDLE
|
||||
as the return type of this function. We use void* instead. */
|
||||
return sigint_event;
|
||||
signal_state_t *state = &signal_global_state;
|
||||
return state->sigint_event;
|
||||
}
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue