feat: add onUsr1

This commit is contained in:
dualfroz committed 2026-09-09 16:06:55 +02:00
1 parent 5585b11968
commit 35e5dad2f3
1 file changed
+111
+111
View File
@@ -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;
}