feat: add SigInfo
This commit is contained in:
1 parent
2b2252dac5
commit
8d2b1df100
1 file changed
+158
@@ -0,0 +1,158 @@
|
||||
#ifndef FROSTBYTE_SIGNALNUM_H
|
||||
#define FROSTBYTE_SIGNALNUM_H
|
||||
|
||||
/*
|
||||
* Plain numeric constants shared verbatim between the kernel (signal.h/
|
||||
* signal.c) and userspace (user/ulib.h/ulib.c) -- exactly like syscall.h
|
||||
* already is for syscall numbers. Split out from signal.h specifically so
|
||||
* user code never has to include signal.h itself, which pulls in sched.h's
|
||||
* Thread struct and isr.h's Registers -- kernel-only types a freestanding
|
||||
* user program has no business seeing, let alone compiling against.
|
||||
*/
|
||||
|
||||
/* Signal numbers. A small, real (not exhaustive) POSIX-shaped subset --
|
||||
enough to exercise catchable delivery, ignore, default-terminate and the
|
||||
one uncatchable case meaningfully, without pretending to implement every
|
||||
job-control signal a real kernel would. Numbering matches Linux/x86-64
|
||||
for anything actually used here, so an unused gap (5, 7, 16) does too. */
|
||||
#define sigHup 1
|
||||
#define sigInt 2
|
||||
#define sigQuit 3
|
||||
#define sigIll 4
|
||||
#define sigAbrt 6
|
||||
#define sigFpe 8
|
||||
#define sigKill 9
|
||||
#define sigUsr1 10
|
||||
#define sigSegv 11
|
||||
#define sigUsr2 12
|
||||
#define sigPipe 13
|
||||
#define sigAlrm 14
|
||||
#define sigTerm 15
|
||||
#define sigChld 17
|
||||
#define sigCont 18
|
||||
#define sigStop 19
|
||||
#define sigTstp 20
|
||||
|
||||
/* Handler-slot sentinels (Thread.sigHandlers[signum] kernel-side,
|
||||
userSigAction's `handler` argument userspace-side), distinct from any
|
||||
real user code address since every user ELF slot starts at
|
||||
userSpaceMin == 0x40000000 (syscall.c), far above 1. */
|
||||
#define sigHandlerDefault 0ull
|
||||
#define sigHandlerIgnore 1ull
|
||||
|
||||
/* sigSetHandler's/userSigAction's failure return -- mirrors real
|
||||
signal(2)'s SIG_ERR, distinguishable from any real sentinel/handler
|
||||
address a caller could have gotten back as the *previous* disposition.
|
||||
Written without a uint64 cast (unlike the kernel-only constants in
|
||||
signal.h) so this header stays includable from userspace, which never
|
||||
sees types.h -- see fs.h's FbStat for the same convention. */
|
||||
#define sigSetFailed (~0ull)
|
||||
|
||||
/* sigProcMask/userSigProcMask "how" values (mirrors POSIX SIG_BLOCK/
|
||||
SIG_UNBLOCK/SIG_SETMASK by shape, not by number). */
|
||||
#define sigMaskBlock 0
|
||||
#define sigMaskUnblock 1
|
||||
#define sigMaskSetMask 2
|
||||
|
||||
/* sigSetHandler's/userSigAction's `flags` argument (mirrors POSIX
|
||||
sigaction's sa_flags by shape, not by bit position -- there is only one
|
||||
flag here). Default (0, what every handler got before this bit existed)
|
||||
is real POSIX's own default: a signal delivered while a thread sits
|
||||
blocked inside a slow syscall (read/write/wait -- see signal.c's
|
||||
sigInRetryableSyscall) does NOT transparently resume that syscall once
|
||||
the handler returns, it makes the syscall return errInterrupted instead,
|
||||
exactly like an EINTR on real Unix. Passing sigFlagRestart opts back into
|
||||
the OTHER behavior (real SIG_RESTART/BSD's original signal(3) semantics):
|
||||
the interrupted syscall is retried, invisibly to the caller, once the
|
||||
handler returns. Only meaningful for a signal that actually interrupts a
|
||||
genuinely retryable syscall; for anything else (plain running code, a
|
||||
sleep, a signal that does not even install a handler) it is silently
|
||||
irrelevant, same as real SA_RESTART. */
|
||||
#define sigFlagRestart (1ull << 0)
|
||||
|
||||
/* Mirrors POSIX sigaction's SA_NODEFER: by default (this bit clear), a
|
||||
signal's own number is added to sigBlocked for as long as ITS handler is
|
||||
running (signal.h's sigConsumePending, "self-blocked like real Unix's
|
||||
implicit default") -- so the same signal raised again while its handler
|
||||
is still active stays merely pending, delivered only once that handler
|
||||
returns, never nested into itself. Passing sigFlagNoDefer for a signal
|
||||
disables exactly that one self-block (nothing else -- sa_mask/other
|
||||
signals' self-blocks are untouched): a second raise of that same signal
|
||||
while its own handler is active is then genuinely deliverable, entering
|
||||
a NESTED instance of its own handler, the same mechanism a completely
|
||||
different unmasked signal already uses to nest (see signal.h's
|
||||
sa_mask paragraph) -- SA_NODEFER only widens which signal numbers that
|
||||
mechanism applies to, it does not introduce a new one. Irrelevant for a
|
||||
signal that never raises itself from inside its own handler. */
|
||||
#define sigFlagNoDefer (1ull << 1)
|
||||
|
||||
/* Mirrors POSIX sigaction's SA_SIGINFO: by default (this bit clear) a
|
||||
handler is called with exactly one argument, the signal number (this
|
||||
kernel's ONLY shape until now, `regs->rdi = signum` in signal.c's
|
||||
sigConsumePending). Passing sigFlagSigInfo for a signal tells
|
||||
sigConsumePending to ALSO populate a real SigInfo (below) describing this
|
||||
specific delivery -- who/what raised it, real Unix's siginfo_t.si_pid/
|
||||
si_code/si_status -- and hand the handler a pointer to it as a SECOND
|
||||
argument (rsi), plus a third (rdx, always 0/NULL here: this kernel has no
|
||||
ucontext_t of its own to expose, unlike a real kernel's SA_SIGINFO third
|
||||
argument). A handler registered with this flag must actually be declared
|
||||
to take (int, SigInfo*, void*) -- see ulib.h's SigInfoHandler/
|
||||
userSigActionInfo -- exactly like real sigaction()'s sa_sigaction union
|
||||
member only being valid to read when SA_SIGINFO was actually passed. */
|
||||
#define sigFlagSigInfo (1ull << 2)
|
||||
|
||||
/* si_code values SigInfo.siCode below can hold -- a small, real (not
|
||||
exhaustive) subset of POSIX's SI_USER/SI_KERNEL/CLD_EXITED/CLD_KILLED/
|
||||
CLD_STOPPED/CLD_CONTINUED, numbered independently of them (this kernel's
|
||||
own small namespace, not a Linux ABI match, unlike the signal numbers
|
||||
above which deliberately do match). siCodeUser: signum was raised by
|
||||
another process's real userSigSend/kill(2)-shaped syscall (siPid is the
|
||||
SENDER's own pid). siCodeKernel: raised by the kernel itself with no
|
||||
specific sending process (SIGALRM's real timer expiry; also sigRaise's
|
||||
own thin-wrapper default for any caller that supplies no detail at all).
|
||||
siCodeChld{Exited,Killed,Stopped,Continued}: sigChld specifically,
|
||||
distinguishing WHY a child's status changed (siPid is the CHILD's pid,
|
||||
siStatus its real exit code for Exited, threadKilledExitCode for Killed,
|
||||
or the job-control signal number for Stopped/Continued) -- real Unix's
|
||||
own WIFEXITED/WIFSIGNALED/WIFSTOPPED/WIFCONTINUED distinction, exposed
|
||||
directly instead of needing a separate macro to decode a packed status
|
||||
word the way real wait(2)'s plain `int status` still does. */
|
||||
#define siCodeUser 0
|
||||
#define siCodeKernel 1
|
||||
#define siCodeChldExited 2
|
||||
#define siCodeChldKilled 3
|
||||
#define siCodeChldStopped 4
|
||||
#define siCodeChldContinued 5
|
||||
|
||||
/* Real siginfo_t, cut down to exactly the fields this kernel ever actually
|
||||
populates (see siCode* above for what each one means per code) -- shared
|
||||
verbatim between kernel and userspace like every other type in this
|
||||
header, which is exactly why it is built from plain `int`, not a
|
||||
types.h-only typedef (see this header's own file comment). siSignum
|
||||
duplicates the handler's own first argument (signum) -- real siginfo_t
|
||||
keeps si_signo too, for the same reason: a single handler function
|
||||
registered against more than one signal number can tell them apart from
|
||||
*info alone, without needing its own first argument at all. Handed to a
|
||||
sigFlagSigInfo handler as a real pointer (signal.c's sigConsumePending)
|
||||
into a small kernel-owned, user-readable (never user-writable) page
|
||||
mapped at a fixed address -- see signal.h's sigInfoVirtualAddr -- the
|
||||
same "one shared page, like a vDSO" trick this kernel's trampoline page
|
||||
already uses, not memory the handler owns or must free. */
|
||||
typedef struct SigInfo {
|
||||
int siSignum;
|
||||
int siCode;
|
||||
int siPid;
|
||||
int siStatus;
|
||||
} SigInfo;
|
||||
|
||||
/* A retryable syscall (sysRead/sysWrite/sysWait -- see syscall.c) that got
|
||||
interrupted by a signal without sigFlagRestart returns this instead of
|
||||
retrying. Mirrors a raw Linux syscall's own convention of returning
|
||||
-errno directly (here, -EINTR, whose real errno value is 4) rather than
|
||||
a separate errno variable, since this kernel has no per-thread errno of
|
||||
its own to set. Written without a uint64 cast, like every other
|
||||
userspace-visible constant in this header, so it stays includable from
|
||||
freestanding user code. */
|
||||
#define errInterrupted (-4)
|
||||
|
||||
#endif
|
||||
Reference in new issue
Block a user