Files
2026-09-13 18:52:59 +02:00

88 lines
3.0 KiB
C

#include "ulib.h"
/*
* Exercises pidfd.h end to end through the real syscall path
* (sysPidfdOpen/sysPidfdSend/sysPidfdWait) -- the fd-table-wrapped,
* generation-checked handle sched.c's Thread.generation and pidfd.c add
* as an ADDITIVE alternative to a raw pid, mirroring real Linux's own
* pidfd_open(2) (see pidfd.h's own file comment for the full design).
* Reuses killvictim.c (blocks forever in a real, syscall-level pipe read
* with no writer ever attaching, see killtest.c) as its target -- the
* same already-proven "genuinely stuck, only killable from outside"
* shape, no new victim binary needed. Fully synchronous like
* nicetest.c/date.c/timetest.c: no injected keystrokes, no shared shell
* channel, so there is no scheduling-timing race to flake on regardless
* of host load.
*/
int main(void)
{
print("pidfdtest: start, pid=");
printDec(userGetpid());
print("\n");
if (userPidfdOpen(0) != -1) {
print("pidfdtest: FAIL pidfd on pid 0 should be rejected\n");
return 1;
}
if (userPidfdOpen(999999) != -1) {
print("pidfdtest: FAIL pidfd on bogus pid should be rejected\n");
return 1;
}
print("pidfdtest: bad-target rejected\n");
long victim = userSpawn("/bin/killvictim", 0);
if (victim < 0) {
print("pidfdtest: FAIL spawn killvictim\n");
return 1;
}
long pfd = userPidfdOpen(victim);
if (pfd < 0) {
print("pidfdtest: FAIL pidfd open\n");
return 1;
}
print("pidfdtest: pidfd-open-ok\n");
/* Give the victim time to actually attach and reach its blocking read
-- same reasoning as killtest.c's own identical sleep. */
userSleep(100);
if (userPidfdSend(pfd, sigKill) != 0) {
print("pidfdtest: FAIL pidfd send sigKill\n");
return 1;
}
print("pidfdtest: pidfd-send-ok\n");
long status = userPidfdWait(pfd);
print("pidfdtest: victim exit status=");
printDec(status);
print("\n");
if (status != 9) {
print("pidfdtest: FAIL expected exit status 9\n");
return 1;
}
print("pidfdtest: pidfd-wait-ok\n");
/* Already reaped by the wait above: a further send/wait on the SAME
handle must cleanly report the target as gone, not silently act on
whichever thread (if any) now occupies that exact numeric slot --
the whole reason pidfd.h exists (see its own file comment) over
caching victim's raw pid and calling userSigSend(victim, ...)/
userWait(victim) again, which killtest.c's own comment already
documents as unsafe once a slot is recycled. */
if (userPidfdSend(pfd, sigUsr1) != -1) {
print("pidfdtest: FAIL send on reaped pidfd should fail\n");
return 1;
}
if (userPidfdWait(pfd) != -1) {
print("pidfdtest: FAIL wait on reaped pidfd should fail\n");
return 1;
}
print("pidfdtest: reaped-target-detected-ok\n");
userClose((int)pfd);
print("pidfdtest: PASS\n");
return 0;
}