/* Signal module -- many thanks to Lance Ellinghaus */ /* XXX Signals should be recorded per thread, now we have thread state. */ #include "Python.h" #include "pycore_call.h" // _PyObject_Call() #include "pycore_ceval.h" // _PyEval_SignalReceived() #include "pycore_emscripten_signal.h" // _Py_CHECK_EMSCRIPTEN_SIGNALS #include "pycore_fileutils.h" // _Py_BEGIN_SUPPRESS_IPH #include "pycore_frame.h" // _PyInterpreterFrame #include "pycore_moduleobject.h" // _PyModule_GetState() #include "pycore_pyerrors.h" // _PyErr_SetString() #include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_signal.h" // _Py_RestoreSignals() #include "pycore_time.h" // _PyTime_FromSecondsObject() #ifndef MS_WINDOWS # include "posixmodule.h" // _PyLong_FromUid() #endif #ifdef MS_WINDOWS # include "socketmodule.h" // SOCKET_T #endif #ifdef HAVE_UNISTD_H # include <unistd.h> // alarm() #endif #ifdef MS_WINDOWS # ifdef HAVE_PROCESS_H # include <process.h> # endif #endif #ifdef HAVE_SIGNAL_H # include <signal.h> // sigaction() #endif #ifdef HAVE_SYS_SYSCALL_H # include <sys/syscall.h> // __NR_pidfd_send_signal #endif #ifdef HAVE_SYS_STAT_H # include <sys/stat.h> #endif #ifdef HAVE_SYS_TIME_H # include <sys/time.h> // setitimer() #endif #if defined(HAVE_PTHREAD_SIGMASK) && !defined(HAVE_BROKEN_PTHREAD_SIGMASK) #define PYPTHREAD_SIGMASK #endif #if defined(PYPTHREAD_SIGMASK) && defined(HAVE_PTHREAD_H) # include <pthread.h> #endif #ifndef SIG_ERR #define SIG_ERR … #endif #include "clinic/signalmodule.c.h" /*[clinic input] module signal [clinic start generated code]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=b0301a3bde5fe9d3]*/ #ifdef HAVE_SETSIG_T /*[python input] class sigset_t_converter(CConverter): type = 'sigset_t' converter = '_Py_Sigset_Converter' [python start generated code]*/ /*[python end generated code: output=da39a3ee5e6b4b0d input=b5689d14466b6823]*/ #endif /* NOTES ON THE INTERACTION BETWEEN SIGNALS AND THREADS We want the following semantics: - only the main thread can set a signal handler - only the main thread runs the signal handler - signals can be delivered to any thread - any thread can get a signal handler I.e. we don't support "synchronous signals" like SIGFPE (catching this doesn't make much sense in Python anyway) nor do we support signals as a means of inter-thread communication, since not all thread implementations support that (at least our thread library doesn't). We still have the problem that in some implementations signals generated by the keyboard (e.g. SIGINT) are delivered to all threads (e.g. SGI), while in others (e.g. Solaris) such signals are delivered to one random thread. On Linux, signals are delivered to the main thread (unless the main thread is blocking the signal, for example because it's already handling the same signal). Since we allow signals to be delivered to any thread, this works fine. The only oddity is that the thread executing the Python signal handler may not be the thread that received the signal. */ #define Handlers … #define wakeup … #define is_tripped … // State shared by all Python interpreters signal_state_t; #define signal_global_state … #if defined(HAVE_GETITIMER) || defined(HAVE_SETITIMER) #define PYHAVE_ITIMER_ERROR #endif _signal_module_state; Py_LOCAL_INLINE(PyObject *) get_handler(int i) { … } Py_LOCAL_INLINE(void) set_handler(int i, PyObject* func) { … } static inline _signal_module_state* get_signal_state(PyObject *module) { … } static inline int compare_handler(PyObject *func, PyObject *dfl_ign_handler) { … } #ifdef HAVE_SETITIMER /* auxiliary function for setitimer */ static int timeval_from_double(PyObject *obj, struct timeval *tv) { … } #endif #if defined(HAVE_SETITIMER) || defined(HAVE_GETITIMER) /* auxiliary functions for get/setitimer */ Py_LOCAL_INLINE(double) double_from_timeval(struct timeval *tv) { … } static PyObject * itimer_retval(struct itimerval *iv) { … } #endif /*[clinic input] signal.default_int_handler signalnum: int frame: object / The default handler for SIGINT installed by Python. It raises KeyboardInterrupt. [clinic start generated code]*/ static PyObject * signal_default_int_handler_impl(PyObject *module, int signalnum, PyObject *frame) /*[clinic end generated code: output=bb11c2eb115ace4e input=efcd4a56a207acfd]*/ { … } static int report_wakeup_write_error(void *data) { … } #ifdef MS_WINDOWS static int report_wakeup_send_error(void* data) { int send_errno = (int) (intptr_t) data; PyObject *exc = PyErr_GetRaisedException(); /* PyErr_SetExcFromWindowsErr() invokes FormatMessage() which recognizes the error codes used by both GetLastError() and WSAGetLastError */ PyErr_SetExcFromWindowsErr(PyExc_OSError, send_errno); PyErr_FormatUnraisable("Exception ignored when trying to send to the signal wakeup fd"); PyErr_SetRaisedException(exc); return 0; } #endif /* MS_WINDOWS */ static void trip_signal(int sig_num) { … } static void signal_handler(int sig_num) { … } #ifdef HAVE_ALARM /*[clinic input] signal.alarm -> long seconds: int / Arrange for SIGALRM to arrive after the given number of seconds. [clinic start generated code]*/ static long signal_alarm_impl(PyObject *module, int seconds) /*[clinic end generated code: output=144232290814c298 input=0d5e97e0e6f39e86]*/ { … } #endif #ifdef HAVE_PAUSE /*[clinic input] signal.pause Wait until a signal arrives. [clinic start generated code]*/ static PyObject * signal_pause_impl(PyObject *module) /*[clinic end generated code: output=391656788b3c3929 input=f03de0f875752062]*/ { … } #endif /*[clinic input] signal.raise_signal signalnum: int / Send a signal to the executing process. [clinic start generated code]*/ static PyObject * signal_raise_signal_impl(PyObject *module, int signalnum) /*[clinic end generated code: output=e2b014220aa6111d input=e90c0f9a42358de6]*/ { … } /*[clinic input] signal.signal signalnum: int handler: object / Set the action for the given signal. The action can be SIG_DFL, SIG_IGN, or a callable Python object. The previous action is returned. See getsignal() for possible return values. *** IMPORTANT NOTICE *** A signal handler function is called with two arguments: the first is the signal number, the second is the interrupted stack frame. [clinic start generated code]*/ static PyObject * signal_signal_impl(PyObject *module, int signalnum, PyObject *handler) /*[clinic end generated code: output=b44cfda43780f3a1 input=deee84af5fa0432c]*/ { … } /*[clinic input] signal.getsignal signalnum: int / Return the current action for the given signal. The return value can be: SIG_IGN -- if the signal is being ignored SIG_DFL -- if the default action for the signal is in effect None -- if an unknown handler is in effect anything else -- the callable Python object used as a handler [clinic start generated code]*/ static PyObject * signal_getsignal_impl(PyObject *module, int signalnum) /*[clinic end generated code: output=35b3e0e796fd555e input=ac23a00f19dfa509]*/ { … } /*[clinic input] signal.strsignal signalnum: int / Return the system description of the given signal. Returns the description of signal *signalnum*, such as "Interrupt" for :const:`SIGINT`. Returns :const:`None` if *signalnum* has no description. Raises :exc:`ValueError` if *signalnum* is invalid. [clinic start generated code]*/ static PyObject * signal_strsignal_impl(PyObject *module, int signalnum) /*[clinic end generated code: output=44e12e1e3b666261 input=238b335847778bc0]*/ { … } #ifdef HAVE_SIGINTERRUPT /*[clinic input] signal.siginterrupt signalnum: int flag: int / Change system call restart behaviour. If flag is False, system calls will be restarted when interrupted by signal sig, else system calls will be interrupted. [clinic start generated code]*/ static PyObject * signal_siginterrupt_impl(PyObject *module, int signalnum, int flag) /*[clinic end generated code: output=063816243d85dd19 input=4160acacca3e2099]*/ { … } #endif /*[clinic input] signal.set_wakeup_fd fd as fdobj: object / * warn_on_full_buffer: bool = True Sets the fd to be written to (with the signal number) when a signal comes in. A library can use this to wakeup select or poll. The previous fd or -1 is returned. The fd must be non-blocking. [clinic start generated code]*/ static PyObject * signal_set_wakeup_fd_impl(PyObject *module, PyObject *fdobj, int warn_on_full_buffer) /*[clinic end generated code: output=2280d72dd2a54c4f input=5b545946a28b8339]*/ { … } /* C API for the same, without all the error checking */ int PySignal_SetWakeupFd(int fd) { … } #ifdef HAVE_SETITIMER /*[clinic input] signal.setitimer which: int seconds: object interval: object(c_default="NULL") = 0.0 / Sets given itimer (one of ITIMER_REAL, ITIMER_VIRTUAL or ITIMER_PROF). The timer will fire after value seconds and after that every interval seconds. The itimer can be cleared by setting seconds to zero. Returns old values as a tuple: (delay, interval). [clinic start generated code]*/ static PyObject * signal_setitimer_impl(PyObject *module, int which, PyObject *seconds, PyObject *interval) /*[clinic end generated code: output=65f9dcbddc35527b input=de43daf194e6f66f]*/ { … } #endif // HAVE_SETITIMER #ifdef HAVE_GETITIMER /*[clinic input] signal.getitimer which: int / Returns current value of given itimer. [clinic start generated code]*/ static PyObject * signal_getitimer_impl(PyObject *module, int which) /*[clinic end generated code: output=9e053175d517db40 input=f7d21d38f3490627]*/ { … } #endif // HAVE_GETITIMER #ifdef HAVE_SIGSET_T #if defined(PYPTHREAD_SIGMASK) || defined(HAVE_SIGPENDING) static PyObject* sigset_to_set(sigset_t mask) { … } #endif #ifdef PYPTHREAD_SIGMASK /*[clinic input] signal.pthread_sigmask how: int mask: sigset_t / Fetch and/or change the signal mask of the calling thread. [clinic start generated code]*/ static PyObject * signal_pthread_sigmask_impl(PyObject *module, int how, sigset_t mask) /*[clinic end generated code: output=0562c0fb192981a8 input=85bcebda442fa77f]*/ { … } #endif /* #ifdef PYPTHREAD_SIGMASK */ #ifdef HAVE_SIGPENDING /*[clinic input] signal.sigpending Examine pending signals. Returns a set of signal numbers that are pending for delivery to the calling thread. [clinic start generated code]*/ static PyObject * signal_sigpending_impl(PyObject *module) /*[clinic end generated code: output=53375ffe89325022 input=e0036c016f874e29]*/ { … } #endif /* #ifdef HAVE_SIGPENDING */ #ifdef HAVE_SIGWAIT /*[clinic input] signal.sigwait sigset: sigset_t / Wait for a signal. Suspend execution of the calling thread until the delivery of one of the signals specified in the signal set sigset. The function accepts the signal and returns the signal number. [clinic start generated code]*/ static PyObject * signal_sigwait_impl(PyObject *module, sigset_t sigset) /*[clinic end generated code: output=f43770699d682f96 input=a6fbd47b1086d119]*/ { … } #endif /* #ifdef HAVE_SIGWAIT */ #endif /* #ifdef HAVE_SIGSET_T */ #if (defined(HAVE_SIGFILLSET) && defined(HAVE_SIGSET_T)) || defined(MS_WINDOWS) /*[clinic input] signal.valid_signals Return a set of valid signal numbers on this platform. The signal numbers returned by this function can be safely passed to functions like `pthread_sigmask`. [clinic start generated code]*/ static PyObject * signal_valid_signals_impl(PyObject *module) /*[clinic end generated code: output=1609cffbcfcf1314 input=86a3717ff25288f2]*/ { … } #endif /* #if (defined(HAVE_SIGFILLSET) && defined(HAVE_SIGSET_T)) || defined(MS_WINDOWS) */ #if defined(HAVE_SIGWAITINFO) || defined(HAVE_SIGTIMEDWAIT) static PyStructSequence_Field struct_siginfo_fields[] = …; PyDoc_STRVAR(struct_siginfo__doc__, "struct_siginfo: Result from sigwaitinfo or sigtimedwait.\n\n\ This object may be accessed either as a tuple of\n\ (si_signo, si_code, si_errno, si_pid, si_uid, si_status, si_band),\n\ or via the attributes si_signo, si_code, and so on."); static PyStructSequence_Desc struct_siginfo_desc = …; static PyObject * fill_siginfo(_signal_module_state *state, siginfo_t *si) { … } #endif #ifdef HAVE_SIGSET_T #ifdef HAVE_SIGWAITINFO /*[clinic input] signal.sigwaitinfo sigset: sigset_t / Wait synchronously until one of the signals in *sigset* is delivered. Returns a struct_siginfo containing information about the signal. [clinic start generated code]*/ static PyObject * signal_sigwaitinfo_impl(PyObject *module, sigset_t sigset) /*[clinic end generated code: output=1eb2f1fa236fdbca input=3d1a7e1f27fc664c]*/ { … } #endif /* #ifdef HAVE_SIGWAITINFO */ #ifdef HAVE_SIGTIMEDWAIT /*[clinic input] signal.sigtimedwait sigset: sigset_t timeout as timeout_obj: object / Like sigwaitinfo(), but with a timeout. The timeout is specified in seconds, with floating-point numbers allowed. [clinic start generated code]*/ static PyObject * signal_sigtimedwait_impl(PyObject *module, sigset_t sigset, PyObject *timeout_obj) /*[clinic end generated code: output=59c8971e8ae18a64 input=955773219c1596cd]*/ { … } #endif /* #ifdef HAVE_SIGTIMEDWAIT */ #endif /* #ifdef HAVE_SIGSET_T */ #if defined(HAVE_PTHREAD_KILL) /*[clinic input] signal.pthread_kill thread_id: unsigned_long(bitwise=True) signalnum: int / Send a signal to a thread. [clinic start generated code]*/ static PyObject * signal_pthread_kill_impl(PyObject *module, unsigned long thread_id, int signalnum) /*[clinic end generated code: output=7629919b791bc27f input=1d901f2c7bb544ff]*/ { … } #endif /* #if defined(HAVE_PTHREAD_KILL) */ // This system call always crashes on older Android versions. #if defined(__linux__) && defined(__NR_pidfd_send_signal) && \ !(defined(__ANDROID__) && __ANDROID_API__ < 31) /*[clinic input] signal.pidfd_send_signal pidfd: int signalnum: int siginfo: object = None flags: int = 0 / Send a signal to a process referred to by a pid file descriptor. [clinic start generated code]*/ static PyObject * signal_pidfd_send_signal_impl(PyObject *module, int pidfd, int signalnum, PyObject *siginfo, int flags) /*[clinic end generated code: output=2d59f04a75d9cbdf input=2a6543a1f4ac2000]*/ { … } #endif /* List of functions defined in the module -- some of the methoddefs are defined to nothing if the corresponding C function is not available. */ static PyMethodDef signal_methods[] = …; PyDoc_STRVAR(module_doc, "This module provides mechanisms to use signal handlers in Python.\n\ \n\ Functions:\n\ \n\ alarm() -- cause SIGALRM after a specified time [Unix only]\n\ setitimer() -- cause a signal (described below) after a specified\n\ float time and the timer may restart then [Unix only]\n\ getitimer() -- get current value of timer [Unix only]\n\ signal() -- set the action for a given signal\n\ getsignal() -- get the signal action for a given signal\n\ pause() -- wait until a signal arrives [Unix only]\n\ default_int_handler() -- default SIGINT handler\n\ \n\ signal constants:\n\ SIG_DFL -- used to refer to the system default handler\n\ SIG_IGN -- used to ignore the signal\n\ NSIG -- number of defined signals\n\ SIGINT, SIGTERM, etc. -- signal numbers\n\ \n\ itimer constants:\n\ ITIMER_REAL -- decrements in real time, and delivers SIGALRM upon\n\ expiration\n\ ITIMER_VIRTUAL -- decrements only when the process is executing,\n\ and delivers SIGVTALRM upon expiration\n\ ITIMER_PROF -- decrements both when the process is executing and\n\ when the system is executing on behalf of the process.\n\ Coupled with ITIMER_VIRTUAL, this timer is usually\n\ used to profile the time spent by the application\n\ in user and kernel space. SIGPROF is delivered upon\n\ expiration.\n\ \n\n\ *** IMPORTANT NOTICE ***\n\ A signal handler function is called with two arguments:\n\ the first is the signal number, the second is the interrupted stack frame."); static int signal_add_constants(PyObject *module) { … } static int signal_get_set_handlers(signal_state_t *state, PyObject *mod_dict) { … } static int signal_module_exec(PyObject *m) { … } #ifdef PYHAVE_ITIMER_ERROR static int _signal_module_traverse(PyObject *module, visitproc visit, void *arg) { … } static int _signal_module_clear(PyObject *module) { … } static void _signal_module_free(void *module) { … } #endif // PYHAVE_ITIMER_ERROR static PyModuleDef_Slot signal_slots[] = …; static struct PyModuleDef signal_module = …; PyMODINIT_FUNC PyInit__signal(void) { … } void _PySignal_Fini(void) { … } /* Declared in pyerrors.h */ int PyErr_CheckSignals(void) { … } /* Declared in cpython/pyerrors.h */ int _PyErr_CheckSignalsTstate(PyThreadState *tstate) { … } int _PyErr_CheckSignals(void) { … } /* Simulate the effect of a signal arriving. The next time PyErr_CheckSignals is called, the corresponding Python signal handler will be raised. Missing signal handler for the given signal number is silently ignored. */ int PyErr_SetInterruptEx(int signum) { … } void PyErr_SetInterrupt(void) { … } static int signal_install_handlers(void) { … } /* Restore signals that the interpreter has called SIG_IGN on to SIG_DFL. * * All of the code in this function must only use async-signal-safe functions, * listed at `man 7 signal` or * http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html. * * If this function is updated, update also _posix_spawn() of subprocess.py. */ void _Py_RestoreSignals(void) { … } int _PySignal_Init(int install_signal_handlers) { … } // The caller doesn't have to hold the GIL int _PyOS_InterruptOccurred(PyThreadState *tstate) { … } // The caller must to hold the GIL int PyOS_InterruptOccurred(void) { … } #ifdef HAVE_FORK static void _clear_pending_signals(void) { … } void _PySignal_AfterFork(void) { … } #endif /* HAVE_FORK */ int _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) { signal_state_t *state = &signal_global_state; return state->sigint_event; } #endif