diff options
author | Victor Stinner <vstinner@python.org> | 2021-04-28 01:02:55 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-04-28 01:02:55 (GMT) |
commit | a5e64444e6df7d1d498576bab26deaddc288a7bd (patch) | |
tree | 46ce042c4fd4f6341457e0ca77a216ab72bb3456 /Modules | |
parent | 5c84bb506aaca01f5f750116d8f7a41d41f8124d (diff) | |
download | cpython-a5e64444e6df7d1d498576bab26deaddc288a7bd.zip cpython-a5e64444e6df7d1d498576bab26deaddc288a7bd.tar.gz cpython-a5e64444e6df7d1d498576bab26deaddc288a7bd.tar.bz2 |
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().
Diffstat (limited to 'Modules')
-rw-r--r-- | Modules/signalmodule.c | 237 |
1 files changed, 153 insertions, 84 deletions
diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c index 8618713..a4eeec9 100644 --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -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) { - return -1; - } + signal_state_t *state = &signal_global_state; - IgnoreHandler = PyLong_FromVoidPtr((void *)SIG_IGN); - if (!IgnoreHandler) { + state->default_handler = PyLong_FromVoidPtr((void *)SIG_DFL); + if (state->default_handler == NULL) { return -1; } -#if defined(HAVE_GETITIMER) || defined(HAVE_SETITIMER) - ItimerError = PyErr_NewException("signal.ItimerError", - PyExc_OSError, NULL); - if (!ItimerError) { + state->ignore_handler = PyLong_FromVoidPtr((void *)SIG_IGN); + if (state->ignore_handler == NULL) { 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 |