cpython/Modules/signalmodule.c


/* 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