test: cover printLong
This commit is contained in:
1 parent
6d1d46dc14
commit
47b9d3828f
2 files changed
+166
No files matched your search
@@ -0,0 +1,87 @@
|
||||
#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;
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
#include "ulib.h"
|
||||
|
||||
static void printLong(const char* label, long value)
|
||||
{
|
||||
print(label);
|
||||
printDec(value);
|
||||
print("\n");
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
print("pipetest: start, pid=");
|
||||
printDec(userGetpid());
|
||||
print("\n");
|
||||
|
||||
int fds[2];
|
||||
long rc = userPipe(fds);
|
||||
printLong("pipetest: userPipe rc=", rc);
|
||||
if (rc < 0) {
|
||||
print("pipetest: pipe() failed\n");
|
||||
return 1;
|
||||
}
|
||||
int readFd = fds[0];
|
||||
int writeFd = fds[1];
|
||||
|
||||
/* nothing written yet: a read must report "would block" (-1), not EOF */
|
||||
char probe[4];
|
||||
long earlyRead = userRead(readFd, probe, sizeof(probe));
|
||||
printLong("pipetest: read before write rc=", earlyRead);
|
||||
if (earlyRead != -1) {
|
||||
print("pipetest: FAIL expected -1 on empty open pipe\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char* payload = "hello through the pipe\n";
|
||||
long written = userWrite(writeFd, payload, stringLength(payload));
|
||||
printLong("pipetest: wrote bytes=", written);
|
||||
if (written != (long)stringLength(payload)) {
|
||||
print("pipetest: FAIL short write\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
char buffer[64];
|
||||
long got = userRead(readFd, buffer, sizeof(buffer) - 1);
|
||||
if (got < 0) {
|
||||
print("pipetest: FAIL read after write blocked\n");
|
||||
return 1;
|
||||
}
|
||||
buffer[got] = 0;
|
||||
print("pipetest: read back: ");
|
||||
print(buffer);
|
||||
|
||||
userClose(writeFd);
|
||||
|
||||
/* buffer is now empty and the write end is closed: true EOF (0) */
|
||||
long afterClose = userRead(readFd, probe, sizeof(probe));
|
||||
printLong("pipetest: read after writer closed rc=", afterClose);
|
||||
if (afterClose != 0) {
|
||||
print("pipetest: FAIL expected EOF (0) after writer closed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
userClose(readFd);
|
||||
|
||||
/* a second independent pipe proves broken-pipe (write with no reader) */
|
||||
int fds2[2];
|
||||
userPipe(fds2);
|
||||
userClose(fds2[0]);
|
||||
long brokenWrite = userWrite(fds2[1], "x", 1);
|
||||
printLong("pipetest: write after reader closed rc=", brokenWrite);
|
||||
if (brokenWrite != -1) {
|
||||
print("pipetest: FAIL expected broken pipe (-1)\n");
|
||||
return 1;
|
||||
}
|
||||
userClose(fds2[1]);
|
||||
|
||||
print("pipetest: done\n");
|
||||
return 0;
|
||||
}
|
||||
Reference in new issue
Block a user