test: cover timetest and waitanytest

This commit is contained in:
dualfroz committed 2026-09-14 02:51:08 +02:00
1 parent d4f2912238
commit 24803ae957
2 files changed
+191

No files matched your search

+102
View File
@@ -0,0 +1,102 @@
#include "ulib.h"
/*
* Boot-time driver for waitpid(-1)-style userWaitAny (ulib.c/sched.c's new
* threadJoinAnyChild) -- proves a parent can reap TWO independently exiting
* children without ever naming either pid, in whichever order they
* actually die, and correctly reports ECHILD (-1, no blocking) once none
* are left.
*
* Spawns waitanyfast.c (exits immediately) then waitanyslow.c (sleeps
* 150ms first), then calls userWaitAny() twice:
* - the first call happens essentially immediately after both spawns, so
* waitanyslow.c cannot possibly be Dead yet (its own 150ms sleep alone
* dwarfs the handful of syscalls in between) -- it must be
* waitanyfast.c that gets reaped here, exercising
* threadJoinAnyChild's waitScanFoundDead branch without ever blocking.
* - the second call therefore has only waitanyslow.c left, which is
* genuinely still alive at that point -- it must take the
* waitScanNoneDead branch and actually block through sysWait's real
* retry-syscall path (schedBlockCurrent(currentThread()), sched.c's
* new any-child wake in threadExit) until waitanyslow.c's sleep
* elapses and it exits.
* Verified without leaning on that ordering being guaranteed, though: both
* reaped pids together must equal exactly {fastPid, slowPid} as a set, and
* each one's own exit code must match whichever pid it actually was, in
* whatever order they came back.
* A third userWaitAny() call, once both children are gone, must return -1
* immediately (ECHILD) rather than hang forever with no children left to
* wait for -- proves threadJoinAnyChild's waitScanNoChildren branch live.
*/
int main(void)
{
print("waitanytest: start, pid=");
printDec(userGetpid());
print("\n");
long fastPid = userSpawn("/bin/waitanyfast", 0);
if (fastPid < 0) {
print("waitanytest: FAIL spawn waitanyfast\n");
return 1;
}
long slowPid = userSpawn("/bin/waitanyslow", 0);
if (slowPid < 0) {
print("waitanytest: FAIL spawn waitanyslow\n");
return 1;
}
long reapedPid[2];
long reapedCode[2];
for (int i = 0; i < 2; i++) {
long pid = -1;
long code = userWaitAny(&pid);
print("waitanytest: reaped pid=");
printDec(pid);
print(" code=");
printDec(code);
print("\n");
if (code < 0) {
print("waitanytest: FAIL userWaitAny reported no children too early\n");
return 1;
}
reapedPid[i] = pid;
reapedCode[i] = code;
}
int sawFast = 0;
int sawSlow = 0;
for (int i = 0; i < 2; i++) {
if (reapedPid[i] == fastPid) {
sawFast = 1;
if (reapedCode[i] != 44) {
print("waitanytest: FAIL waitanyfast exit code mismatch\n");
return 1;
}
} else if (reapedPid[i] == slowPid) {
sawSlow = 1;
if (reapedCode[i] != 33) {
print("waitanytest: FAIL waitanyslow exit code mismatch\n");
return 1;
}
} else {
print("waitanytest: FAIL reaped an unrecognized pid\n");
return 1;
}
}
if (!sawFast || !sawSlow) {
print("waitanytest: FAIL did not reap both known children exactly once\n");
return 1;
}
print("waitanytest: any-child-reap-set-ok\n");
long pid = 0;
long status = userWaitAny(&pid);
if (status != -1) {
print("waitanytest: FAIL expected -1 (ECHILD) once no children remain\n");
return 1;
}
print("waitanytest: echild-when-no-children-ok\n");
return 0;
}