summaryrefslogtreecommitdiffstats
path: root/Modules
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@python.org>2021-04-28 01:02:55 (GMT)
committerGitHub <noreply@github.com>2021-04-28 01:02:55 (GMT)
commita5e64444e6df7d1d498576bab26deaddc288a7bd (patch)
tree46ce042c4fd4f6341457e0ca77a216ab72bb3456 /Modules
parent5c84bb506aaca01f5f750116d8f7a41d41f8124d (diff)
downloadcpython-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.c237
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