#ifndef VLIBC_SIGNAL_H #define VLIBC_SIGNAL_H /* * vlibc — . * * Signal handling (POSIX.1-2008 base) plus the XSI/obsolete conveniences. * The core calls ride the kernel's rt_* signal ABI (SYS_rt_sigaction, * SYS_rt_sigprocmask, SYS_rt_sigpending, SYS_rt_sigsuspend, * SYS_rt_sigtimedwait, SYS_rt_sigqueueinfo) with the x86_64 kernel * sigset size of one 64-bit word. * * Level 1 (onlyposix): signal numbers, SIG_DFL/SIG_IGN/SIG_ERR, the * sigset_t manipulation and query calls, sigaction, * sigprocmask, sigpending, sigsuspend, sigwait, * sigwaitinfo, sigtimedwait, kill, killpg, raise, * pause, alarm, abort, sigqueue, and the signal() * convenience. * Level 2 (muslmimic): sigaltstack (and stack_t / SS_* / SIGSTKSZ), * ualarm, siginterrupt, psignal, psiginfo (XSI / * obsolete — sigaction/sigprocmask/alarm are POSIX * base and stay at level 1). * * The layout facts below are x86_64 kernel-ABI: * * - The kernel sigset_t is 8 bytes (one word); signal N occupies bit * N-1, signals 1..64 are usable (32..64 are the realtime signals). * The same single-word sigset_t is declared by and * under the shared VLIBC_SIGSET_T_DEFINED guard so pselect/ * ppoll and the sig* API agree on the type no matter the include order. * - SIG_DFL/SIG_IGN/SIG_ERR are the magic handler values 0/1/-1 cast to * the handler type; the kernel dispatches on the raw value. * - The PUBLIC struct sigaction is the POSIX layout (handler, mask, * int flags, restorer). The kernel's rt_sigaction ABI layout is * DIFFERENT (handler, flags, restorer, mask — flags is a full word); * src/signal/sigaction.c converts between the two. * - SA_RESTORER (0x04000000) is the kernel-private bit that makes the * kernel jump to the user-supplied sa_restorer trampoline when the * handler returns; every real (non-DFL/IGN) handler install sets it * (see sigaction.c). It is masked out of the flags reported back. * * siginfo_t is the minimal 128-byte layout shared with * under the VLIBC_INTERNAL_SIGINFO_DEFINED guard (see the block below); * either header may be included first. No SIGEV_* / SI_* constants are * defined: the signal-handling details behind them are owned by a later * todo and nothing here needs the names. */ #include #include #include #ifdef __cplusplus extern "C" { #endif /* * struct timespec is defined by ; a forward declaration is enough * for sigtimedwait()'s pointer parameter, and the two headers may be * included in either order. */ struct timespec; /* Signal numbers (x86_64 asm-generic values; kernel-ABI facts). */ #define SIGHUP 1 /* hangup detected on controlling terminal */ #define SIGINT 2 /* interactive attention (^C) */ #define SIGQUIT 3 /* interactive quit (^\) */ #define SIGILL 4 /* illegal instruction */ #define SIGTRAP 5 /* trace/breakpoint trap */ #define SIGABRT 6 /* abnormal termination (abort()) */ #define SIGBUS 7 /* bus error */ #define SIGFPE 8 /* floating-point exception */ #define SIGKILL 9 /* kill (cannot be caught or ignored) */ #define SIGUSR1 10 /* user-defined signal 1 */ #define SIGSEGV 11 /* invalid memory reference */ #define SIGUSR2 12 /* user-defined signal 2 */ #define SIGPIPE 13 /* write on a pipe with no reader */ #define SIGALRM 14 /* real-time timer expired (alarm/ualarm/setitimer) */ #define SIGTERM 15 /* termination request */ #define SIGSTKFLT 16 /* stack fault (unused) */ #define SIGCHLD 17 /* child stopped or terminated */ #define SIGCONT 18 /* continue if stopped */ #define SIGSTOP 19 /* stop (cannot be caught or ignored) */ #define SIGTSTP 20 /* interactive stop (^Z) */ #define SIGTTIN 21 /* background process read from terminal */ #define SIGTTOU 22 /* background process write to terminal */ #define SIGURG 23 /* urgent condition on a socket */ #define SIGXCPU 24 /* CPU time limit exceeded */ #define SIGXFSZ 25 /* file size limit exceeded */ #define SIGVTALRM 26 /* virtual timer expired */ #define SIGPROF 27 /* profiling timer expired */ #define SIGWINCH 28 /* window size change */ #define SIGIO 29 /* I/O now possible */ #define SIGPWR 30 /* power failure */ #define SIGSYS 31 /* bad system call */ /* Realtime signals: the 32..64 range, usable for user-defined purposes. */ #define SIGRTMIN 32 #define SIGRTMAX 64 /* One more than the highest signal number; signals 1..64 are usable. */ #define NSIG 65 /* The magic handler values. The kernel dispatches on the raw value. */ #define SIG_DFL ((void (*)(int))0) /* default action */ #define SIG_IGN ((void (*)(int))1) /* ignore the signal */ #define SIG_ERR ((void (*)(int)) - 1) /* signal() error return */ /* * Integer type that can be accessed as an atomic entity even when an * asynchronous signal interrupts the access (volatile sig_atomic_t is the * conventional spelling). int is atomic on x86_64. */ typedef int sig_atomic_t; /* sigprocmask()/pthread_sigmask() how values (kernel-identical). */ #define SIG_BLOCK 0 /* add the given set to the blocked mask */ #define SIG_UNBLOCK 1 /* remove the given set from the blocked mask */ #define SIG_SETMASK 2 /* replace the blocked mask with the given set */ #ifndef VLIBC_SIGSET_T_DEFINED #define VLIBC_SIGSET_T_DEFINED /* * Signal mask type: a single 64-bit word — the x86_64 Linux sigset_t, * where signal N is bit N-1 (see setjmp.h, whose sigsetjmp stores this * same word). The typedef is shared with and * under this guard, so pselect()/ppoll() and the sig* API agree on the * type regardless of include order. */ typedef unsigned long sigset_t; #endif /* * Value carried with a queued (realtime) signal. sival_int and sival_ptr * are alternative views of the same 64-bit payload. */ union sigval { int sival_int; /* integer payload */ void *sival_ptr; /* pointer payload */ }; /* POSIX spelling of the payload type. */ typedef union sigval sigval_t; /* * Description of a delivered signal: number, errno, code and one of the * per-code unions. This is the minimal x86_64 kernel layout (128 bytes) * shared with , which fills si_pid/si_uid/si_status/si_utime/ * si_stime for waitid(); the two headers define this exact block under the * common VLIBC_INTERNAL_SIGINFO_DEFINED guard, so whichever is included * first wins and the other skips — the type is identical either way. The * kernel copies the full 128 bytes on signal delivery (sigaction with * SA_SIGINFO, sigwaitinfo, sigtimedwait), so the size must stay 128 and * the pad member guarantees it; the fields behind each si_code value * (si_addr, si_value, timers, ...) are owned by a later todo. */ #ifndef VLIBC_INTERNAL_SIGINFO_DEFINED #define VLIBC_INTERNAL_SIGINFO_DEFINED typedef struct { int si_signo; int si_errno; int si_code; union { struct { pid_t si_pid; /* 16 */ uid_t si_uid; /* 20 */ int si_status; /* 24 */ long si_utime; /* 32 — 8-byte clock_t, matches the kernel/glibc ABI */ long si_stime; /* 40 */ }; int vlibc_siginfo_pad[28]; /* union sized 112 so the struct stays 128 */ }; } siginfo_t; _Static_assert(sizeof(siginfo_t) == 128, "siginfo_t must match the kernel size"); _Static_assert(offsetof(siginfo_t, si_pid) == 16, "si_pid must sit at offset 16"); #endif /* * Action taken when signal sig is delivered. sa_handler and sa_sigaction * are two views of the same slot (POSIX: sa_sigaction is used when * SA_SIGINFO is set and receives (sig, siginfo_t *, void *) instead of * just sig). The layout — handler, mask, flags, restorer — is the PUBLIC * POSIX order; the kernel ABI uses a different order (see the file-top * note) that sigaction() translates. */ struct sigaction { union { void (*sa_handler)(int); /* SIG_DFL/SIG_IGN/a handler */ void (*sa_sigaction)(int, siginfo_t *, void *); /* SA_SIGINFO form */ }; sigset_t sa_mask; /* signals additionally blocked in the handler */ int sa_flags; /* SA_* bits below */ void (*sa_restorer)(void); /* kernel-private; do not set (see top) */ }; _Static_assert(sizeof(struct sigaction) == 32, "struct sigaction must be 32 bytes"); _Static_assert(offsetof(struct sigaction, sa_mask) == 8, "sa_mask must sit at offset 8"); _Static_assert(offsetof(struct sigaction, sa_flags) == 16, "sa_flags must sit at offset 16"); _Static_assert(offsetof(struct sigaction, sa_restorer) == 24, "sa_restorer must sit at offset 24"); /* sa_flags bits (x86_64 kernel values; SA_RESTORER is kernel-private). */ #define SA_NOCLDSTOP 1 /* do not generate SIGCHLD when children stop */ #define SA_NOCLDWAIT 2 /* do not leave zombies on child exit */ #define SA_SIGINFO 4 /* call the handler with the siginfo form */ #define SA_RESTORER 0x04000000 /* handler returns via sa_restorer (kernel) */ #define SA_ONSTACK 0x08000000 /* run the handler on the alternate stack */ #define SA_RESTART 0x10000000 /* restart interrupted syscalls after the handler */ #define SA_NODEFER 0x40000000 /* do not block the delivered signal in its handler */ #define SA_RESETHAND 0x80000000 /* reset the disposition to SIG_DFL on entry */ /* * Install the action act for signal sig (NULL leaves it unchanged) and * store the previous action through oact (NULL skips the store). Return * 0, or -1 with errno set. sig must be in 1..64 and (for a catching * action) not SIGKILL/SIGSTOP; the kernel rejects invalid values with * EINVAL. Real handler pointers are installed with SA_RESTORER and the * internal return trampoline so the handler may return normally. */ int sigaction(int sig, const struct sigaction *restrict act, struct sigaction *restrict oact); /* * Inspect or change the calling thread's blocked-signal mask. how is * SIG_BLOCK/SIG_UNBLOCK/SIG_SETMASK; set is the mask operand (NULL * queries without changing: how is then ignored) and the previous mask is * stored through oldset (NULL skips the store). Return 0, or -1 with * errno set. */ int sigprocmask(int how, const sigset_t *restrict set, sigset_t *restrict oldset); /* Store the set of blocked-and-pending signals through set. 0 or -1. */ int sigpending(sigset_t *set); /* * Atomically install mask as the blocked mask and wait until a signal * whose delivery is not blocked by mask is caught; when its handler * returns, the previous mask is restored and sigsuspend returns -1 with * errno EINTR. */ int sigsuspend(const sigset_t *mask); /* Empty set: no signal blocked, and no member set. Always 0. */ int sigemptyset(sigset_t *set); /* Set every signal 1..64 blocked/member. Always 0. */ int sigfillset(sigset_t *set); /* * Add/remove signal sig to/from set. Return 0, or -1 with errno EINVAL * when sig is outside 1..64. */ int sigaddset(sigset_t *set, int sig); int sigdelset(sigset_t *set, int sig); /* * Nonzero when sig is a member of set, 0 otherwise, or -1 with errno * EINVAL when sig is outside 1..64. */ int sigismember(const sigset_t *set, int sig); /* * Synchronously wait for one of the signals in set (which should be * blocked in the calling thread) and store the delivered signal number * through sig. Return 0 on success, or the error number (EINTR is * retried internally). The signal is consumed and never delivered to a * handler. */ int sigwait(const sigset_t *restrict set, int *restrict sig); /* * Like sigwait, but return the delivered signal number directly (or -1 * with errno set) and, when info is not NULL, store the full 128-byte * kernel siginfo through it. */ int sigwaitinfo(const sigset_t *restrict set, siginfo_t *restrict info); /* * sigwaitinfo bounded by timeout (relative; NULL waits indefinitely). * Returns the signal number, 0 is never returned for a successful wait, * or -1 with errno set (EAGAIN on timeout, EINTR if a handler ran). */ int sigtimedwait(const sigset_t *restrict set, siginfo_t *restrict info, const struct timespec *restrict timeout); /* * Send signal sig to the process pid (negative pid targets a process * group; 0 targets the caller's process group; see killpg). Return 0, or * -1 with errno set. Permission, existence and signal validity are * checked by the kernel. */ int kill(pid_t pid, int sig); /* * Send signal sig to every process in the process group pgrp (0 selects * the caller's process group). Return 0, or -1 with errno set. */ int killpg(pid_t pgrp, int sig); /* * Send signal sig to the calling thread (thread-directed, so it is * delivered even when another thread of the process has it blocked). * Return 0, or -1 with errno set. */ int raise(int sig); /* * Wait until a signal is caught, then return -1 with errno EINTR. If the * process is terminated by the signal instead, pause never returns. */ int pause(void); /* * Schedule delivery of SIGALRM to the calling process after seconds * seconds (0 cancels any pending alarm). Return the number of seconds * remaining on any previously scheduled alarm, or 0. */ unsigned alarm(unsigned seconds); /* * Abnormally terminate the calling process: raise SIGABRT with default * disposition — if SIGABRT is blocked it is unblocked first, and if it * is caught or ignored the disposition is reset to SIG_DFL and the raise * repeated. If that still returns, terminate with exit status 134 as a * last resort. abort never returns. */ __attribute__((noreturn)) void abort(void); /* * Send signal sig with payload value to process pid, as if by a kernel * queue operation (the kernel sees a negative si_code, SI_QUEUE). Return * 0, or -1 with errno set. */ int sigqueue(pid_t pid, int sig, const union sigval value); /* * Install handler as the action for sig with SA_RESTART (BSD semantics: * syscalls interrupted by the signal are restarted). Return the previous * handler, or SIG_ERR with errno set. */ void (*signal(int sig, void (*handler)(int)))(int); #if VLIBC_LEVEL_GE(2) /* Level 2 (muslmimic): XSI and obsolete conveniences. */ /* * Alternate signal stack descriptor. ss_sp/ss_size name a region the * kernel switches to when delivering a handler installed with SA_ONSTACK * (see sigaltstack below). stack_t is the POSIX spelling. */ typedef struct sigaltstack { void *ss_sp; /* stack base or current stack base */ int ss_flags; /* SS_ONSTACK/SS_DISABLE */ size_t ss_size; /* stack bytes */ } stack_t; /* ss_flags values. */ #define SS_ONSTACK 1 /* the process is currently executing on this stack */ #define SS_DISABLE 2 /* the alternate stack is currently disabled */ /* Minimum / default alternate stack sizes (x86_64 values). */ #define MINSIGSTKSZ 2048 #define SIGSTKSZ 8192 /* * Install ss as the alternate signal stack (NULL leaves it unchanged) * and store the previous descriptor through oss (NULL skips the store). * Return 0, or -1 with errno set. */ int sigaltstack(const stack_t *restrict ss, stack_t *restrict oss); /* * Schedule SIGALRM after usecs microseconds, repeating every interval * microseconds (0 fires once). Return the number of microseconds * remaining on any previously scheduled alarm, or -1 on error. */ useconds_t ualarm(useconds_t usecs, useconds_t interval); /* * Toggle the SA_RESTART bit of sig's disposition: flag nonzero removes * it (interrupted syscalls return EINTR, System V semantics), flag zero * restores it. Return 0, or -1 with errno set. */ int siginterrupt(int sig, int flag); /* * Write s (when non-NULL and nonempty), ": " and strsignal(sig) to * stderr. The output is a diagnostic only. */ void psignal(int sig, const char *s); /* * Like psignal, but the signal number and details are taken from the * siginfo si (si_signo names the signal). si may be NULL, in which case * only the message prefix is written. */ void psiginfo(const siginfo_t *si, const char *s); #endif /* VLIBC_LEVEL_GE(2) */ #ifdef __cplusplus } #endif #endif /* VLIBC_SIGNAL_H */