Lib/signal.py
cpython 3.14 @ ab2d84fe1023/Lib/signal.py
Lib/signal.py is a thin pure-Python layer over Modules/signalmodule.c.
The C module exposes signal, getsignal, raise_signal, strsignal,
valid_signals, SIG_DFL, SIG_IGN, and the POSIX extensions
(alarm, setitimer, getitimer, pause, pthread_kill,
pthread_sigmask, sigwait, sigwaitinfo, sigtimedwait). The Python
module wraps these with two IntEnum subclasses, Signals and
Handlers, that give all signal numbers and the two special handler
values symbolic names.
The central function is signal(signum, handler), which installs
handler as the callback to invoke when the process receives signum.
CPython's signal delivery model calls the handler from the main thread
only: signals are received by the C-level signal(2) handler, which
sets a flag in _PyRuntime.ceval.signals_pending, and the eval loop
checks that flag at safe points (between bytecode instructions) and calls
the registered Python handler from the main thread's frame.
Map
| Lines | Symbol | Role | gopy |
|---|---|---|---|
| 1-40 | Module header, re-exports from _signal | Import the C extension names into the module namespace; define __all__. | (stdlib pending) |
| 41-100 | Signals enum, signal constants | Signals(IntEnum) enumerates SIGABRT, SIGFPE, SIGILL, SIGINT, SIGSEGV, SIGTERM on all platforms, plus POSIX-only names; re-registers each constant at module level. | (stdlib pending) |
| 101-150 | Handlers enum, SIG_DFL, SIG_IGN | Handlers(IntEnum) with members SIG_DFL (0) and SIG_IGN (1); getsignal normalises its return value to a Handlers member when possible. | (stdlib pending) |
| 151-200 | signal, getsignal, raise_signal, strsignal, valid_signals | Wrappers that accept both integer signal numbers and Signals enum members; signal also accepts Handlers members for SIG_DFL/SIG_IGN. | (stdlib pending) |
| 201-250 | alarm, pause, setitimer, getitimer | POSIX-only; setitimer takes ITIMER_REAL, ITIMER_VIRTUAL, or ITIMER_PROF and delivers SIGALRM, SIGVTALRM, or SIGPROF respectively; only available if hasattr(signal, 'setitimer'). | (stdlib pending) |
| 251-300 | pthread_kill, pthread_sigmask, sigwait, sigwaitinfo, sigtimedwait | POSIX thread signal functions; pthread_sigmask accepts and returns frozenset of Signals members; only defined when the C extension supplies them. | (stdlib pending) |
| 301-350 | set_wakeup_fd, NSIG, SIGRTMIN, SIGRTMAX | set_wakeup_fd writes a byte to a file descriptor or socket when a signal arrives, enabling integration with event loops; real-time signal range constants on Linux. | (stdlib pending) |
Reading
signal() handler registration (lines 151 to 200)
cpython 3.14 @ ab2d84fe1023/Lib/signal.py#L151-200
def signal(signalnum, handler):
handler = _enum_to_int(handler)
signalnum = Signals(signalnum)
return _signal.signal(signalnum, handler)
def getsignal(signalnum):
signalnum = Signals(signalnum)
handler = _signal.getsignal(signalnum)
try:
return Handlers(handler)
except ValueError:
# handler is a Python callable, not SIG_DFL/SIG_IGN
return handler
signal() accepts any integer-compatible signal specifier and normalises
it to a Signals member before delegating to _signal.signal. The C
function stores the callable in a per-signal slot in _PyRuntime and
installs a C-level sigaction handler that sets the pending-signal flag.
getsignal() returns the currently registered handler. When the return
value is SIG_DFL (0) or SIG_IGN (1), it is converted to the
corresponding Handlers enum member. Otherwise it is returned as-is (the
Python callable, or SIG_DFL/SIG_IGN as raw ints if the signal was set
by a non-Python sigaction call).
A ValueError is raised if signalnum is not a valid signal on the
current platform. A TypeError is raised if handler is not callable,
SIG_DFL, or SIG_IGN. Only the main thread may call signal(); calling
from a non-main thread raises ValueError.
setitimer and SIGALRM (lines 201 to 250)
cpython 3.14 @ ab2d84fe1023/Lib/signal.py#L201-250
# These are only available on POSIX.
if hasattr(_signal, 'setitimer'):
setitimer = _signal.setitimer
getitimer = _signal.getitimer
ITIMER_REAL = _signal.ITIMER_REAL
ITIMER_VIRTUAL = _signal.ITIMER_VIRTUAL
ITIMER_PROF = _signal.ITIMER_PROF
class ItimerError(OSError):
pass
setitimer(which, seconds, interval=0.0) arms an interval timer.
which selects the timer type:
ITIMER_REAL: decrements in real time; deliversSIGALRMon expiry.ITIMER_VIRTUAL: decrements only while the process is executing in user mode; deliversSIGVTALRM.ITIMER_PROF: decrements while executing in user or kernel mode; used with profilers; deliversSIGPROF.
seconds is the initial delay; interval is the reload value for
repeating timers (0 for one-shot). getitimer(which) returns a
(value, interval) tuple for the current timer state.
The ItimerError exception is raised when the underlying setitimer(2)
call fails, for example if seconds overflows the platform's timer
resolution.
pthread_sigmask (lines 251 to 300)
cpython 3.14 @ ab2d84fe1023/Lib/signal.py#L251-300
if hasattr(_signal, 'pthread_sigmask'):
def pthread_sigmask(how, mask):
sigs = set(mask)
return _signal.pthread_sigmask(how, sigs)
pthread_sigmask(how, mask) manipulates the calling thread's signal mask.
how is one of SIG_BLOCK, SIG_UNBLOCK, or SIG_SETMASK (constants
from _signal). mask is an iterable of signal numbers or Signals
members. The return value is a frozenset of the previous mask as
Signals members.
sigwait(sigset) suspends the calling thread until one of the signals in
sigset is pending, then removes it from the pending set and returns its
number as a Signals member. Unlike pause(), it does not invoke the
registered Python handler; the signal is consumed silently.
pthread_kill(thread_id, signum) sends a signal to a specific POSIX
thread. thread_id is obtained from threading.get_native_id() or
threading.Thread.native_id. The signal is delivered to the target thread
rather than to the process, which is useful for interrupting a blocked
read() or select() in another thread.
Signals and Handlers enums (lines 41 to 150)
cpython 3.14 @ ab2d84fe1023/Lib/signal.py#L41-150
class Signals(IntEnum):
SIGABRT = _signal.SIGABRT
SIGFPE = _signal.SIGFPE
SIGILL = _signal.SIGILL
SIGINT = _signal.SIGINT
SIGSEGV = _signal.SIGSEGV
SIGTERM = _signal.SIGTERM
# Platform-conditional members added below via globals()
...
class Handlers(IntEnum):
SIG_DFL = _signal.SIG_DFL
SIG_IGN = _signal.SIG_IGN
SIG_DFL = Handlers.SIG_DFL
SIG_IGN = Handlers.SIG_IGN
Both enums subclass IntEnum so that their members are usable anywhere
a plain integer is expected. The Signals class is populated with only
the constants that exist in _signal; optional members such as
SIGHUP, SIGCHLD, SIGUSR1, SIGUSR2, and real-time signals
(SIGRTMIN through SIGRTMAX) are added conditionally by iterating
dir(_signal) and inserting entries whose names match SIG[A-Z].
After the class is built, each member is also assigned at module level
(SIGINT = Signals.SIGINT), preserving backward compatibility with code
that imports signal names directly from the module.
gopy mirror
Lib/signal.py is pure Python and can be bundled verbatim once the
_signal C extension is available. The critical requirement is the
eval-loop integration: the pending-signal check (_PyRuntime.ceval.signals_pending)
must fire between instructions and dispatch to the registered Python
handlers from the main goroutine. set_wakeup_fd requires a writable
file descriptor or socket, which maps naturally to a Go channel or pipe in
the event-loop integration layer.