feat: add onUsr1 and onUsr2
This commit is contained in:
1 parent
1818463484
commit
67ea1f461e
1 file changed
+153
@@ -0,0 +1,153 @@
|
||||
#include "ulib.h"
|
||||
|
||||
/*
|
||||
* Only ever spawned by restarttest.c, with four shared pipe handles as argv
|
||||
* (ready/announce1/announce2/data, decToString'd -- the same convention
|
||||
* nesttarget.c/jobtarget.c already establish for a multi-pipe rendezvous).
|
||||
*
|
||||
* Proves signal.h's SA_RESTART/EINTR distinction (signalnum.h's
|
||||
* sigFlagRestart, sched.h's Thread.sigInRetryableSyscall) end to end, in
|
||||
* two phases against two independently registered handlers:
|
||||
*
|
||||
* phase 1 (no sigFlagRestart): blocks in a real userRead on a pipe NO ONE
|
||||
* will EVER write (the exact "blocked forever" setup user/eintrtarget.c
|
||||
* already uses for threadKill/early-wake), gets sigUsr1 -- registered
|
||||
* WITHOUT sigFlagRestart -- and must see that read return errInterrupted
|
||||
* the instant onUsr1 returns, not silently retry and hang forever.
|
||||
*
|
||||
* phase 2 (WITH sigFlagRestart): blocks in a real userRead on a SECOND
|
||||
* pipe restarttest.c genuinely does write, gets sigUsr2 -- registered
|
||||
* WITH sigFlagRestart -- while blocked, and must see that read
|
||||
* transparently resume and return the real byte once onUsr2 returns,
|
||||
* exactly like every other retryable syscall already did before this
|
||||
* flag existed (user/nesttarget.c's onUsr1/goFd relies on precisely this
|
||||
* for an unrelated reason -- see that file's own comment).
|
||||
*
|
||||
* Each phase's blocking read is announced ("about to call it now") over
|
||||
* its own pipe immediately beforehand, the same "announce, then the OTHER
|
||||
* process learns it via its own blocking read before acting" discipline
|
||||
* nesttest.c/nesttarget.c already established for the analogous nested-
|
||||
* delivery race -- not airtight against an adversarial scheduler in
|
||||
* principle, but the SAME assumption those already-verified demos (and
|
||||
* eintrtest.c's) rely on in practice. The rigorous, race-free proof of the
|
||||
* actual rip/rax rewrite lives in sigTest.c, driving sigConsumePending
|
||||
* directly.
|
||||
*/
|
||||
|
||||
static volatile int handlerUsr1Fired = 0;
|
||||
static volatile int handlerUsr2Fired = 0;
|
||||
|
||||
static void onUsr1(int signum)
|
||||
{
|
||||
(void)signum;
|
||||
handlerUsr1Fired = 1;
|
||||
print("restarttarget: usr1-handler-fired\n");
|
||||
}
|
||||
|
||||
static void onUsr2(int signum)
|
||||
{
|
||||
(void)signum;
|
||||
handlerUsr2Fired = 1;
|
||||
print("restarttarget: usr2-handler-fired\n");
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
print("restarttarget: start, pid=");
|
||||
printDec(userGetpid());
|
||||
print("\n");
|
||||
|
||||
if (argc != 5) {
|
||||
print("restarttarget: FAIL expected four argv (ready/announce1/announce2/data handles)\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* sigUsr1 deliberately has NO sigFlagRestart (0): phase 1 below expects
|
||||
its own interrupted read to return errInterrupted, not resume.
|
||||
sigUsr2 deliberately DOES have sigFlagRestart: phase 2 expects the
|
||||
opposite, a transparent resume with the real data. */
|
||||
if (userSigAction(sigUsr1, onUsr1, 0, 0) == (long)sigSetFailed ||
|
||||
userSigAction(sigUsr2, onUsr2, 0, sigFlagRestart) == (long)sigSetFailed) {
|
||||
print("restarttarget: FAIL install handlers\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
long victimHandle = userPipeCreate();
|
||||
if (victimHandle < 0) {
|
||||
print("restarttarget: FAIL create victim pipe\n");
|
||||
return 1;
|
||||
}
|
||||
long victimFd = userPipeAttach(victimHandle, 0);
|
||||
if (victimFd < 0) {
|
||||
print("restarttarget: FAIL attach victim pipe\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
long readyHandle = parseDec(argv[1]);
|
||||
long announce1Handle = parseDec(argv[2]);
|
||||
long announce2Handle = parseDec(argv[3]);
|
||||
long dataHandle = parseDec(argv[4]);
|
||||
|
||||
long readyFd = userPipeAttach(readyHandle, 1);
|
||||
long announce1Fd = userPipeAttach(announce1Handle, 1);
|
||||
long announce2Fd = userPipeAttach(announce2Handle, 1);
|
||||
long dataFd = userPipeAttach(dataHandle, 0);
|
||||
if (readyFd < 0 || announce1Fd < 0 || announce2Fd < 0 || dataFd < 0) {
|
||||
print("restarttarget: FAIL attach ready/announce/data pipes\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (userWrite((int)readyFd, "r", 1) != 1) {
|
||||
print("restarttarget: FAIL write ready byte\n");
|
||||
return 1;
|
||||
}
|
||||
userClose((int)readyFd);
|
||||
print("restarttarget: ready, handlers installed\n");
|
||||
|
||||
/* Phase 1: no-restart. */
|
||||
print("restarttarget: phase1 blocking on victim read (expect errInterrupted)\n");
|
||||
if (userWrite((int)announce1Fd, "a", 1) != 1) {
|
||||
print("restarttarget: FAIL write announce1 byte\n");
|
||||
return 1;
|
||||
}
|
||||
userClose((int)announce1Fd);
|
||||
|
||||
char victimBuffer[4];
|
||||
long n1 = userRead((int)victimFd, victimBuffer, sizeof(victimBuffer));
|
||||
userClose((int)victimFd);
|
||||
|
||||
if (!handlerUsr1Fired) {
|
||||
print("restarttarget: FAIL usr1 handler never fired\n");
|
||||
return 1;
|
||||
}
|
||||
if (n1 != errInterrupted) {
|
||||
print("restarttarget: FAIL victim read did not return errInterrupted\n");
|
||||
return 1;
|
||||
}
|
||||
print("restarttarget: phase1-eintr-no-restart-ok\n");
|
||||
|
||||
/* Phase 2: sigFlagRestart. */
|
||||
print("restarttarget: phase2 blocking on data read (expect transparent restart)\n");
|
||||
if (userWrite((int)announce2Fd, "a", 1) != 1) {
|
||||
print("restarttarget: FAIL write announce2 byte\n");
|
||||
return 1;
|
||||
}
|
||||
userClose((int)announce2Fd);
|
||||
|
||||
char dataByte = 0;
|
||||
long n2 = userRead((int)dataFd, &dataByte, 1);
|
||||
userClose((int)dataFd);
|
||||
|
||||
if (!handlerUsr2Fired) {
|
||||
print("restarttarget: FAIL usr2 handler never fired\n");
|
||||
return 1;
|
||||
}
|
||||
if (n2 != 1 || dataByte != 'd') {
|
||||
print("restarttarget: FAIL data read did not transparently resume with real data\n");
|
||||
return 1;
|
||||
}
|
||||
print("restarttarget: phase2-restart-transparent-ok\n");
|
||||
|
||||
print("restarttarget: all-phases-ok\n");
|
||||
return 55;
|
||||
}
|
||||
Reference in new issue
Block a user