test: cover sigtest

This commit is contained in:
dualfroz committed 2026-09-14 02:44:59 +02:00
1 parent 1b0db18265
commit d7f42ecd65
1 file changed
+127
+127
View File
@@ -0,0 +1,127 @@
#include "ulib.h"
/*
* Boot-time driver for the whole signal-delivery demo (signal.h). Spawns
* two independent children -- sigtarget.c (installs a real handler) and
* sigdefault.c (installs none) -- and sends each a real signal through the
* full syscall path (userSigSend, not a kernel-internal shortcut), proving
* both outcomes sigConsumePending can produce: caught-and-resumed, and
* uncaught-and-terminated.
*
* sigtarget needs a real happens-before guarantee, not a sleep guess:
* sigUsr1's default disposition is Terminate, so a signal that arrives
* before sigtarget's userSigAction has actually run would kill it instead
* of being caught -- this was originally "give it 100ms and hope", which
* really did fail under host load (sigtarget killed by the uncaught
* default before it ever installed its handler). See sigtarget.c for the
* shared-pipe rendezvous (fifomaster.c's pattern) that fixes it: this
* process blocks on a real read for sigtarget's own "handler installed"
* byte before ever calling userSigSend.
*
* sigdefault has no such window -- its default disposition applies from
* the moment it exists, whether or not it has run any code yet -- so a
* plain sleep-then-send (mirroring killtest.c's own "give the victim time
* to reach its blocking read") is genuinely sufficient there.
*/
int main(void)
{
print("sigtest: start, pid=");
printDec(userGetpid());
print("\n");
if (userSigSend(999999, sigUsr1) != -1) {
print("sigtest: FAIL signal to bogus pid should fail\n");
return 1;
}
print("sigtest: signal to bad pid rejected\n");
if (userSigAction(sigKill, (SigHandler)0, 0, 0) != (long)sigSetFailed) {
print("sigtest: FAIL installing a sigKill handler should be rejected\n");
return 1;
}
print("sigtest: sigkill-handler-rejected-ok\n");
long readyHandle = userPipeCreate();
if (readyHandle < 0) {
print("sigtest: FAIL create ready pipe\n");
return 1;
}
/* Attach as reader BEFORE sigtarget even exists, let alone before it
can possibly attach+write+close its own end: pipeCloseWrite (pipe.c)
reclaims a detached pipe's slot the moment readers AND writers both
read 0, which they still would right after sigtarget's write+close
if this process had not attached yet -- observed for real (sigtarget
raced ahead, wrote its ready byte, closed, and freed the slot before
this process's own attach below ever ran, which then failed outright
on the now-invalid handle). Attaching first makes readers==1 from
the very start, so that race window never opens. */
long readyFd = userPipeAttach(readyHandle, 0);
if (readyFd < 0) {
print("sigtest: FAIL attach ready pipe\n");
return 1;
}
char readyHandleStr[24];
decToString(readyHandle, readyHandleStr);
char* targetArgv[] = { "/bin/sigtarget", readyHandleStr, 0 };
long target = userSpawn("/bin/sigtarget", targetArgv);
if (target < 0) {
print("sigtest: FAIL spawn sigtarget\n");
return 1;
}
char readyByte;
/* Real blocking read: does not return until sigtarget has actually
installed its handler and written this byte (see sigtarget.c) --
the happens-before guarantee a fixed userSleep could not give. */
if (userRead((int)readyFd, &readyByte, 1) != 1) {
print("sigtest: FAIL read ready byte\n");
return 1;
}
userClose((int)readyFd);
if (userSigSend(target, sigUsr1) != 0) {
print("sigtest: FAIL send sigUsr1 to sigtarget\n");
return 1;
}
print("sigtest: sent sigUsr1 to sigtarget\n");
long status = userWait(target);
print("sigtest: sigtarget exit status=");
printDec(status);
print("\n");
if (status != 42) {
print("sigtest: FAIL expected sigtarget exit status 42\n");
return 1;
}
print("sigtest: handler-roundtrip-ok\n");
long defaultTarget = userSpawn("/bin/sigdefault", 0);
if (defaultTarget < 0) {
print("sigtest: FAIL spawn sigdefault\n");
return 1;
}
userSleep(100);
if (userSigSend(defaultTarget, sigTerm) != 0) {
print("sigtest: FAIL send sigTerm to sigdefault\n");
return 1;
}
print("sigtest: sent sigTerm to sigdefault\n");
long defaultStatus = userWait(defaultTarget);
print("sigtest: sigdefault exit status=");
printDec(defaultStatus);
print("\n");
if (defaultStatus != 128 + sigTerm) {
print("sigtest: FAIL expected sigdefault exit status 128+sigTerm\n");
return 1;
}
print("sigtest: default-terminate-ok\n");
return 0;
}