diff --git a/user/siginfotarget.c b/user/siginfotarget.c new file mode 100644 index 0000000..91b2481 --- /dev/null +++ b/user/siginfotarget.c @@ -0,0 +1,111 @@ +#include "ulib.h" + +/* + * Only ever spawned by siginfotest.c, with argv[1]=the ready-pipe handle + * (decToString'd, exactly like sigtarget.c's own argv[1]) and argv[2]= + * siginfotest's own pid (also decToString'd) -- the one extra argument + * this process needs that sigtarget.c's own version of this rendezvous + * did not, since proving SA_SIGINFO's si_pid is real means comparing it + * against a KNOWN sender pid, not just observing "some nonzero value came + * through". + * + * Otherwise the exact same happens-before shape sigtarget.c already + * established (userSigActionInfo BEFORE the ready byte is written, a real + * blocking read on siginfotest.c's side of the pipe before it ever calls + * userSigSend) -- see that file's own comment for why a plain sleep is not + * enough here either: sigUsr1's default disposition is Terminate, so a + * signal delivered before the handler is installed would kill this + * process outright. + */ + +static volatile int handlerFired = 0; +static volatile int capturedSignum = 0; +static volatile int capturedCode = -1; +static volatile int capturedPid = -1; + +static void onUsr1(int signum, SigInfo* info, void* context) +{ + (void)context; + capturedSignum = signum; + capturedCode = info->siCode; + capturedPid = info->siPid; + handlerFired = 1; + print("siginfotarget: handler invoked signum="); + printDec(signum); + print(" siCode="); + printDec(info->siCode); + print(" siPid="); + printDec(info->siPid); + print("\n"); +} + +int main(int argc, char** argv) +{ + print("siginfotarget: start, pid="); + printDec(userGetpid()); + print("\n"); + + if (argc != 3) { + print("siginfotarget: FAIL expected two argv (pipe handle, parent pid)\n"); + return 1; + } + + /* sigFlagSigInfo (signalnum.h) is what actually makes the kernel call + onUsr1 with three arguments instead of one -- without it, this + handler would be invoked as if it were a plain SigHandler, reading + `info`/`context` out of whatever garbage rsi/rdx happened to hold + (see userSigActionInfo's own doc comment, ulib.h). */ + if (userSigActionInfo(sigUsr1, onUsr1, 0, sigFlagSigInfo) == (long)sigSetFailed) { + print("siginfotarget: FAIL install siginfo handler\n"); + return 1; + } + + long parentPid = parseDec(argv[2]); + + long handle = parseDec(argv[1]); + long readyFd = userPipeAttach(handle, 1); + if (readyFd < 0) { + print("siginfotarget: FAIL attach ready pipe\n"); + return 1; + } + if (userWrite((int)readyFd, "r", 1) != 1) { + print("siginfotarget: FAIL write ready byte\n"); + return 1; + } + userClose((int)readyFd); + + print("siginfotarget: waiting for signal\n"); + + for (int i = 0; i < 40 && !handlerFired; i++) + userSleep(20); + + if (!handlerFired) { + print("siginfotarget: FAIL handler never fired\n"); + return 1; + } + if (capturedSignum != sigUsr1) { + print("siginfotarget: FAIL wrong signum delivered\n"); + return 1; + } + if (capturedCode != siCodeUser) { + print("siginfotarget: FAIL expected siCodeUser\n"); + return 1; + } + if (capturedPid != (int)parentPid) { + print("siginfotarget: FAIL si_pid="); + printDec(capturedPid); + print(" does not match real sender pid="); + printDec(parentPid); + print("\n"); + return 1; + } + print("siginfotarget: siginfo-sender-pid-ok\n"); + + /* Reached only if sysSigReturn correctly restored the exact pre-signal + context (same proof sigtarget.c's own tail comment gives), plus this + time only if the trampoline's three-argument call into onUsr1 above + (rdi/rsi/rdx all genuinely set up, not just rdi) did not corrupt + anything either. */ + print("siginfotarget: resumed-after-siginfo-handler-ok\n"); + return 77; +}