116 lines
4.2 KiB
C
116 lines
4.2 KiB
C
#include "ulib.h"
|
|
|
|
/*
|
|
* Boot-time driver for user/restarttarget.c -- see that file's own comment
|
|
* for the full two-phase SA_RESTART/EINTR story. Four real happens-before
|
|
* rendezvous pipes (ready/announce1/announce2/data), never a sleep guess,
|
|
* the same discipline nesttest.c already established for a comparable
|
|
* race: read announce1 before sending the no-restart signal (sigUsr1), then
|
|
* read announce2 -- which restarttarget.c only ever writes AFTER phase 1's
|
|
* read has already come back as errInterrupted and been validated -- before
|
|
* sending the restart-flagged signal (sigUsr2) and writing the real data
|
|
* byte phase 2 expects to receive back.
|
|
*/
|
|
|
|
int main(void)
|
|
{
|
|
print("restarttest: start, pid=");
|
|
printDec(userGetpid());
|
|
print("\n");
|
|
|
|
long readyHandle = userPipeCreate();
|
|
long announce1Handle = userPipeCreate();
|
|
long announce2Handle = userPipeCreate();
|
|
long dataHandle = userPipeCreate();
|
|
if (readyHandle < 0 || announce1Handle < 0 || announce2Handle < 0 || dataHandle < 0) {
|
|
print("restarttest: FAIL create pipes\n");
|
|
return 1;
|
|
}
|
|
|
|
long readyFd = userPipeAttach(readyHandle, 0);
|
|
long announce1Fd = userPipeAttach(announce1Handle, 0);
|
|
long announce2Fd = userPipeAttach(announce2Handle, 0);
|
|
long dataFd = userPipeAttach(dataHandle, 1);
|
|
if (readyFd < 0 || announce1Fd < 0 || announce2Fd < 0 || dataFd < 0) {
|
|
print("restarttest: FAIL attach pipes\n");
|
|
return 1;
|
|
}
|
|
|
|
char readyHandleStr[24];
|
|
char announce1HandleStr[24];
|
|
char announce2HandleStr[24];
|
|
char dataHandleStr[24];
|
|
decToString(readyHandle, readyHandleStr);
|
|
decToString(announce1Handle, announce1HandleStr);
|
|
decToString(announce2Handle, announce2HandleStr);
|
|
decToString(dataHandle, dataHandleStr);
|
|
|
|
char* targetArgv[] = { "/bin/restarttarget", readyHandleStr, announce1HandleStr,
|
|
announce2HandleStr, dataHandleStr, 0 };
|
|
long target = userSpawn("/bin/restarttarget", targetArgv);
|
|
if (target < 0) {
|
|
print("restarttest: FAIL spawn restarttarget\n");
|
|
return 1;
|
|
}
|
|
|
|
char byte;
|
|
if (userRead((int)readyFd, &byte, 1) != 1) {
|
|
print("restarttest: FAIL read ready byte\n");
|
|
return 1;
|
|
}
|
|
userClose((int)readyFd);
|
|
print("restarttest: restarttarget ready\n");
|
|
|
|
/* Real blocking read: does not return until restarttarget has actually
|
|
written announce1, right before it calls its own victim read -- the
|
|
happens-before that makes "sigUsr1 lands while genuinely blocked"
|
|
meaningful rather than a coincidence of timing (same guarantee
|
|
nesttest.c's handlerReadyFd already gives a different race). */
|
|
if (userRead((int)announce1Fd, &byte, 1) != 1) {
|
|
print("restarttest: FAIL read announce1 byte\n");
|
|
return 1;
|
|
}
|
|
userClose((int)announce1Fd);
|
|
print("restarttest: restarttarget about to block (phase1)\n");
|
|
|
|
if (userSigSend(target, sigUsr1) != 0) {
|
|
print("restarttest: FAIL send sigUsr1 to restarttarget\n");
|
|
return 1;
|
|
}
|
|
print("restarttest: sent sigUsr1 (no restart) to restarttarget\n");
|
|
|
|
/* restarttarget only ever writes announce2 after phase 1's read has
|
|
already come back as errInterrupted and been validated, so this read
|
|
doubles as confirmation phase 1 actually passed. */
|
|
if (userRead((int)announce2Fd, &byte, 1) != 1) {
|
|
print("restarttest: FAIL read announce2 byte\n");
|
|
return 1;
|
|
}
|
|
userClose((int)announce2Fd);
|
|
print("restarttest: restarttarget about to block (phase2)\n");
|
|
|
|
if (userSigSend(target, sigUsr2) != 0) {
|
|
print("restarttest: FAIL send sigUsr2 to restarttarget\n");
|
|
return 1;
|
|
}
|
|
print("restarttest: sent sigUsr2 (restart) to restarttarget\n");
|
|
|
|
if (userWrite((int)dataFd, "d", 1) != 1) {
|
|
print("restarttest: FAIL write data byte\n");
|
|
return 1;
|
|
}
|
|
userClose((int)dataFd);
|
|
|
|
long status = userWait(target);
|
|
print("restarttest: restarttarget exit status=");
|
|
printDec(status);
|
|
print("\n");
|
|
if (status != 55) {
|
|
print("restarttest: FAIL expected restarttarget exit status 55\n");
|
|
return 1;
|
|
}
|
|
print("restarttest: sa-restart-eintr-distinction-ok\n");
|
|
|
|
return 0;
|
|
}
|