113 lines
4.1 KiB
C
113 lines
4.1 KiB
C
#include "ulib.h"
|
|
|
|
/*
|
|
* Boot-time driver for real, ring-3 NESTED signal delivery (signal.h's
|
|
* per-signal sa_mask / Thread.sigHandlerDepth stack): spawns nesttarget.c,
|
|
* and, through three real happens-before rendezvous pipes (never a sleep
|
|
* guess), sends it sigUsr1, waits for genuine confirmation that sigUsr1's
|
|
* handler has actually entered and blocked, and ONLY THEN sends sigUsr2 --
|
|
* proving sigUsr2 interrupts an ALREADY-ACTIVE handler with a second one of
|
|
* its own, rather than either being dropped, deferred until sigUsr1 returns
|
|
* (which is what an empty-but-still-"one handler at a time" gate, the
|
|
* architecture this replaced, would have done), or racing ahead of sigUsr1
|
|
* even starting.
|
|
*
|
|
* userSigSend's pending-bit write happens synchronously, inside the syscall
|
|
* itself, before it ever returns to this process -- so by the time it
|
|
* returns 0 below, sigUsr2 is unconditionally pending against nesttarget
|
|
* regardless of exactly what nesttarget's own thread is doing at that
|
|
* instant. Only the goFd write that follows needs to be strictly ordered
|
|
* after it, which normal program order on THIS process already guarantees.
|
|
*/
|
|
|
|
int main(void)
|
|
{
|
|
print("nesttest: start, pid=");
|
|
printDec(userGetpid());
|
|
print("\n");
|
|
|
|
long readyHandle = userPipeCreate();
|
|
long handlerReadyHandle = userPipeCreate();
|
|
long goHandle = userPipeCreate();
|
|
if (readyHandle < 0 || handlerReadyHandle < 0 || goHandle < 0) {
|
|
print("nesttest: FAIL create pipes\n");
|
|
return 1;
|
|
}
|
|
|
|
/* Attach every end THIS process owns before nesttarget even exists --
|
|
same "attach first" discipline as jobtest.c, so none of these three
|
|
slots can be reclaimed by a same-instant close on the other side. */
|
|
long readyFd = userPipeAttach(readyHandle, 0);
|
|
long handlerReadyFd = userPipeAttach(handlerReadyHandle, 0);
|
|
long goFd = userPipeAttach(goHandle, 1);
|
|
if (readyFd < 0 || handlerReadyFd < 0 || goFd < 0) {
|
|
print("nesttest: FAIL attach pipes\n");
|
|
return 1;
|
|
}
|
|
|
|
char readyHandleStr[24];
|
|
char handlerReadyHandleStr[24];
|
|
char goHandleStr[24];
|
|
decToString(readyHandle, readyHandleStr);
|
|
decToString(handlerReadyHandle, handlerReadyHandleStr);
|
|
decToString(goHandle, goHandleStr);
|
|
|
|
char* targetArgv[] = { "/bin/nesttarget", readyHandleStr,
|
|
handlerReadyHandleStr, goHandleStr, 0 };
|
|
long target = userSpawn("/bin/nesttarget", targetArgv);
|
|
if (target < 0) {
|
|
print("nesttest: FAIL spawn nesttarget\n");
|
|
return 1;
|
|
}
|
|
|
|
char readyByte;
|
|
if (userRead((int)readyFd, &readyByte, 1) != 1) {
|
|
print("nesttest: FAIL read ready byte\n");
|
|
return 1;
|
|
}
|
|
userClose((int)readyFd);
|
|
print("nesttest: nesttarget ready\n");
|
|
|
|
if (userSigSend(target, sigUsr1) != 0) {
|
|
print("nesttest: FAIL send sigUsr1 to nesttarget\n");
|
|
return 1;
|
|
}
|
|
print("nesttest: sent sigUsr1 to nesttarget\n");
|
|
|
|
char handlerReadyByte;
|
|
/* Real blocking read: does not return until onUsr1 (nesttarget.c) has
|
|
actually started running AND is about to block on goFd -- the
|
|
happens-before guarantee that makes the nested-delivery proof below
|
|
meaningful instead of a coincidence of timing. */
|
|
if (userRead((int)handlerReadyFd, &handlerReadyByte, 1) != 1) {
|
|
print("nesttest: FAIL read handler-ready byte\n");
|
|
return 1;
|
|
}
|
|
userClose((int)handlerReadyFd);
|
|
print("nesttest: nesttarget usr1-handler-entered\n");
|
|
|
|
if (userSigSend(target, sigUsr2) != 0) {
|
|
print("nesttest: FAIL send sigUsr2 to nesttarget\n");
|
|
return 1;
|
|
}
|
|
print("nesttest: sent sigUsr2 to nesttarget\n");
|
|
|
|
if (userWrite((int)goFd, "g", 1) != 1) {
|
|
print("nesttest: FAIL write go byte\n");
|
|
return 1;
|
|
}
|
|
userClose((int)goFd);
|
|
|
|
long status = userWait(target);
|
|
print("nesttest: nesttarget exit status=");
|
|
printDec(status);
|
|
print("\n");
|
|
if (status != 77) {
|
|
print("nesttest: FAIL expected nesttarget exit status 77\n");
|
|
return 1;
|
|
}
|
|
print("nesttest: nested-signal-delivery-ok\n");
|
|
|
|
return 0;
|
|
}
|