From 0ae323b87f1bed64a7fa70f5a41a5800aca032cc Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 17 Nov 2020 18:15:20 +0100 Subject: [PATCH] bpo-41686: Always create the SIGINT event on Windows (GH-23344) bpo-41686, bpo-41713: On Windows, the SIGINT event, _PyOS_SigintEvent(), is now created even if Python is configured to not install signal handlers (PyConfig.install_signal_handlers=0 or Py_InitializeEx(0)). Changes: * Move global variables initialization from signal_exec() to _PySignal_Init() to clarify that they are global variables cleared by _PySignal_Fini(). * _PySignal_Fini() now closes sigint_event. * IntHandler is no longer a global variable. --- .../2020-11-17-16-25-50.bpo-41686.hX77kL.rst | 4 + Modules/signalmodule.c | 140 +++++++++++------- 2 files changed, 91 insertions(+), 53 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-11-17-16-25-50.bpo-41686.hX77kL.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-11-17-16-25-50.bpo-41686.hX77kL.rst b/Misc/NEWS.d/next/Core and Builtins/2020-11-17-16-25-50.bpo-41686.hX77kL.rst new file mode 100644 index 00000000000..0265d48660a --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2020-11-17-16-25-50.bpo-41686.hX77kL.rst @@ -0,0 +1,4 @@ +On Windows, the ``SIGINT`` event, ``_PyOS_SigintEvent()``, is now created +even if Python is configured to not install signal handlers (if +:c:member:`PyConfig.install_signal_handlers` equals to 0, or +``Py_InitializeEx(0)``). diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c index c0b211749aa..7cd6666ede8 100644 --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -130,15 +130,16 @@ static _Py_atomic_int is_tripped; static PyObject *DefaultHandler; static PyObject *IgnoreHandler; -static PyObject *IntHandler; #ifdef MS_WINDOWS static HANDLE sigint_event = NULL; #endif -#ifdef HAVE_GETITIMER +#if defined(HAVE_GETITIMER) || defined(HAVE_SETITIMER) static PyObject *ItimerError; +#endif +#ifdef HAVE_GETITIMER /* auxiliary functions for setitimer */ static int timeval_from_double(PyObject *obj, struct timeval *tv) @@ -1074,7 +1075,6 @@ signal_valid_signals_impl(PyObject *module) #if defined(HAVE_SIGWAITINFO) || defined(HAVE_SIGTIMEDWAIT) -static int initialized; static PyStructSequence_Field struct_siginfo_fields[] = { {"si_signo", "signal number"}, {"si_code", "signal code"}, @@ -1384,30 +1384,19 @@ signal_exec(PyObject *m) { /* add the functions */ #if defined(HAVE_SIGWAITINFO) || defined(HAVE_SIGTIMEDWAIT) - if (!initialized) { - if (PyStructSequence_InitType2(&SiginfoType, &struct_siginfo_desc) < 0) { - return -1; - } - } - if (PyModule_AddType(m, &SiginfoType) < 0) { return -1; } - initialized = 1; #endif /* Add some symbolic constants to the module */ PyObject *d = PyModule_GetDict(m); - DefaultHandler = PyLong_FromVoidPtr((void *)SIG_DFL); - if (!DefaultHandler || - PyDict_SetItemString(d, "SIG_DFL", DefaultHandler) < 0) { + if (PyDict_SetItemString(d, "SIG_DFL", DefaultHandler) < 0) { return -1; } - IgnoreHandler = PyLong_FromVoidPtr((void *)SIG_IGN); - if (!IgnoreHandler || - PyDict_SetItemString(d, "SIG_IGN", IgnoreHandler) < 0) { + if (PyDict_SetItemString(d, "SIG_IGN", IgnoreHandler) < 0) { return -1; } @@ -1427,15 +1416,9 @@ signal_exec(PyObject *m) return -1; #endif - IntHandler = PyMapping_GetItemString(d, "default_int_handler"); - if (!IntHandler) - return -1; - - _Py_atomic_store_relaxed(&Handlers[0].tripped, 0); for (int i = 1; i < NSIG; i++) { void (*t)(int); t = PyOS_getsig(i); - _Py_atomic_store_relaxed(&Handlers[i].tripped, 0); if (t == SIG_DFL) Handlers[i].func = DefaultHandler; else if (t == SIG_IGN) @@ -1445,9 +1428,13 @@ signal_exec(PyObject *m) Py_INCREF(Handlers[i].func); } if (Handlers[SIGINT].func == DefaultHandler) { + PyObject *int_handler = PyMapping_GetItemString(d, "default_int_handler"); + if (!int_handler) { + return -1; + } + /* Install default int handler */ - Py_INCREF(IntHandler); - Py_SETREF(Handlers[SIGINT].func, IntHandler); + Py_SETREF(Handlers[SIGINT].func, int_handler); PyOS_setsig(SIGINT, signal_handler); } @@ -1617,11 +1604,8 @@ signal_exec(PyObject *m) return -1; #endif -#if defined (HAVE_SETITIMER) || defined (HAVE_GETITIMER) - ItimerError = PyErr_NewException("signal.ItimerError", - PyExc_OSError, NULL); - if (!ItimerError || - PyDict_SetItemString(d, "ItimerError", ItimerError) < 0) { +#if defined(HAVE_GETITIMER) || defined(HAVE_SETITIMER) + if (PyDict_SetItemString(d, "ItimerError", ItimerError) < 0) { return -1; } #endif @@ -1636,11 +1620,6 @@ signal_exec(PyObject *m) return -1; #endif -#ifdef MS_WINDOWS - /* Create manual-reset event, initially unset */ - sigint_event = CreateEvent(NULL, TRUE, FALSE, FALSE); -#endif - if (PyErr_Occurred()) { return -1; } @@ -1677,23 +1656,31 @@ PyInit__signal(void) void _PySignal_Fini(void) { - int i; - PyObject *func; - - for (i = 1; i < NSIG; i++) { - func = Handlers[i].func; - _Py_atomic_store_relaxed(&Handlers[i].tripped, 0); - Handlers[i].func = NULL; - if (func != NULL && func != Py_None && - func != DefaultHandler && func != IgnoreHandler) - PyOS_setsig(i, SIG_DFL); + // Restore default signals and clear handlers + for (int signum = 1; signum < NSIG; signum++) { + PyObject *func = Handlers[signum].func; + _Py_atomic_store_relaxed(&Handlers[signum].tripped, 0); + Handlers[signum].func = NULL; + if (func != NULL + && func != Py_None + && func != DefaultHandler + && func != IgnoreHandler) + { + PyOS_setsig(signum, SIG_DFL); + } Py_XDECREF(func); } - Py_CLEAR(IntHandler); +#ifdef MS_WINDOWS + if (sigint_event != NULL) { + CloseHandle(sigint_event); + sigint_event = NULL; + } +#endif + Py_CLEAR(DefaultHandler); Py_CLEAR(IgnoreHandler); -#ifdef HAVE_GETITIMER +#if defined(HAVE_GETITIMER) || defined(HAVE_SETITIMER) Py_CLEAR(ItimerError); #endif } @@ -1792,14 +1779,9 @@ PyErr_SetInterrupt(void) } } -int -_PySignal_Init(int install_signal_handlers) +static int +signal_install_handlers(void) { - if (!install_signal_handlers) { - // Nothing to do - return 0; - } - #ifdef SIGPIPE PyOS_setsig(SIGPIPE, SIG_IGN); #endif @@ -1821,6 +1803,58 @@ _PySignal_Init(int install_signal_handlers) } +int +_PySignal_Init(int install_signal_handlers) +{ + DefaultHandler = PyLong_FromVoidPtr((void *)SIG_DFL); + if (!DefaultHandler) { + return -1; + } + + IgnoreHandler = PyLong_FromVoidPtr((void *)SIG_IGN); + if (!IgnoreHandler) { + 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) { + PyErr_SetFromWindowsErr(0); + return -1; + } +#endif + +#if defined(HAVE_SIGWAITINFO) || defined(HAVE_SIGTIMEDWAIT) + if (SiginfoType.tp_name == NULL) { + if (PyStructSequence_InitType2(&SiginfoType, &struct_siginfo_desc) < 0) { + return -1; + } + } +#endif + + for (int signum = 1; signum < NSIG; signum++) { + _Py_atomic_store_relaxed(&Handlers[signum].tripped, 0); + } + + if (install_signal_handlers) { + if (signal_install_handlers() < 0) { + return -1; + } + } + + return 0; +} + + // The caller doesn't have to hold the GIL int _PyOS_InterruptOccurred(PyThreadState *tstate)