test: add more cases for streq
This commit is contained in:
1 parent
47b9d3828f
commit
aea99e3f67
1 file changed
+152
+152
@@ -0,0 +1,152 @@
|
|||||||
|
#include "ulib.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Boot-time driver for real poll(2) (poll.h's PollFd, syscall.c's sysPoll,
|
||||||
|
* sched.c's schedPollChannel + schedule()'s own pollDeadline expiry scan):
|
||||||
|
* waits for readiness across MORE THAN ONE fd at once, something no
|
||||||
|
* earlier demo in this kernel does -- every previous blocking read/write
|
||||||
|
* always committed ahead of time to exactly one fd (vfsBlockingChannel,
|
||||||
|
* vfs.h). Three phases:
|
||||||
|
*
|
||||||
|
* phase 1: a non-blocking poll (timeoutMs 0) on a shared pipe's read end
|
||||||
|
* nobody has written to yet -- must report zero ready fds WITHOUT ever
|
||||||
|
* parking the calling thread, proven simply by returning at all (a real
|
||||||
|
* accidental-park bug here would hang the whole boot to ci-test.sh's 25s
|
||||||
|
* QEMU timeout instead of merely failing a check, the same
|
||||||
|
* fault-injection-visible shape every other demo in this kernel already
|
||||||
|
* has).
|
||||||
|
*
|
||||||
|
* phase 2: a REAL, bounded-timeout poll on that same still-empty fd --
|
||||||
|
* proves schedule()'s pollDeadline expiry scan actually forces a wake
|
||||||
|
* when no fd ever becomes ready, not just phase 1's immediate-return
|
||||||
|
* fast path.
|
||||||
|
*
|
||||||
|
* phase 3: an INFINITE-timeout (-1) poll across TWO fds at once (the
|
||||||
|
* pipe pollwriter.c will write to, and a SECOND, entirely unrelated pipe
|
||||||
|
* nobody ever writes -- deliberately not fd 0/console: every open
|
||||||
|
* reader, including this process's own fd 0, gets a copy of every
|
||||||
|
* keystroke keyboardHandleScancode ever broadcasts, keyboard.h, and this
|
||||||
|
* same boot image has other demos genuinely typing at the shell
|
||||||
|
* concurrently, so fd 0 could not be trusted to stay silent for the
|
||||||
|
* whole wait) while a freshly spawned child (pollwriter.c) sleeps
|
||||||
|
* briefly then writes to the first pipe -- proves the real cross-process
|
||||||
|
* wake path (pipeWrite -> schedWakeChannel(schedPollChannel()) -> this
|
||||||
|
* thread's retried sysPoll re-checking every fd from scratch) AND that
|
||||||
|
* only the written pipe's own PollFd entry gets revents set, never the
|
||||||
|
* untouched second one's, i.e. the multiplexer is genuinely selective,
|
||||||
|
* not just "anything happened, assume the first entry".
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define pollTimeoutMs 200
|
||||||
|
|
||||||
|
static int streq(const char* a, const char* b)
|
||||||
|
{
|
||||||
|
while (*a && *a == *b) {
|
||||||
|
a++;
|
||||||
|
b++;
|
||||||
|
}
|
||||||
|
return *a == *b;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
print("polltest: start, pid=");
|
||||||
|
printDec(userGetpid());
|
||||||
|
print("\n");
|
||||||
|
|
||||||
|
long handle = userPipeCreate();
|
||||||
|
if (handle < 0) {
|
||||||
|
print("polltest: FAIL pipe create\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
long readFd = userPipeAttach(handle, 0);
|
||||||
|
if (readFd < 0) {
|
||||||
|
print("polltest: FAIL attach read end\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Never written to by anyone -- the second phase-3 fd that must stay
|
||||||
|
not-ready for the whole wait. A private, unshared userPipe() end
|
||||||
|
(rather than a second userPipeCreate/userPipeAttach handle) is
|
||||||
|
enough since nothing else ever touches it. */
|
||||||
|
int idleFds[2];
|
||||||
|
if (userPipe(idleFds) != 0) {
|
||||||
|
print("polltest: FAIL idle pipe create\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Spawned immediately, like fifomaster.c spawns its own two children,
|
||||||
|
rather than after phase 1/2 do their own work below -- every other
|
||||||
|
boot-time demo's runtime spawn happens right at its own start, and
|
||||||
|
pollwriter's own delay (pollWriterDelayMs, pollwriter.c) is already
|
||||||
|
comfortably longer than phase 2's bounded-timeout wait below, so
|
||||||
|
phase 3 still genuinely blocks waiting for it either way. */
|
||||||
|
char handleStr[24];
|
||||||
|
decToString(handle, handleStr);
|
||||||
|
char* writerArgv[] = { "/bin/pollwriter", handleStr, 0 };
|
||||||
|
long writerPid = userSpawn("/bin/pollwriter", writerArgv);
|
||||||
|
if (writerPid < 0) {
|
||||||
|
print("polltest: FAIL spawn pollwriter\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
PollFd single;
|
||||||
|
single.fd = (int)readFd;
|
||||||
|
single.events = pollIn;
|
||||||
|
single.revents = 12345;
|
||||||
|
long n = userPoll(&single, 1, 0);
|
||||||
|
if (n != 0 || single.revents != 0) {
|
||||||
|
print("polltest: FAIL non-blocking poll on empty pipe\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
print("polltest: non-blocking-poll-empty-ok\n");
|
||||||
|
|
||||||
|
single.revents = 12345;
|
||||||
|
n = userPoll(&single, 1, pollTimeoutMs);
|
||||||
|
if (n != 0 || single.revents != 0) {
|
||||||
|
print("polltest: FAIL bounded-timeout poll returned early or ready\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
print("polltest: poll-timeout-ok\n");
|
||||||
|
|
||||||
|
PollFd pfds[2];
|
||||||
|
pfds[0].fd = (int)readFd;
|
||||||
|
pfds[0].events = pollIn;
|
||||||
|
pfds[0].revents = 0;
|
||||||
|
pfds[1].fd = idleFds[0];
|
||||||
|
pfds[1].events = pollIn;
|
||||||
|
pfds[1].revents = 0;
|
||||||
|
|
||||||
|
print("polltest: blocking on multi-fd poll, waiting for pollwriter\n");
|
||||||
|
n = userPoll(pfds, 2, -1);
|
||||||
|
if (n != 1 || !(pfds[0].revents & pollIn) || pfds[1].revents != 0) {
|
||||||
|
print("polltest: FAIL multi-fd poll woke wrong or with wrong revents\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
print("polltest: poll-woken-by-write-ok\n");
|
||||||
|
|
||||||
|
char buffer[32];
|
||||||
|
long got = userRead((int)readFd, buffer, sizeof(buffer) - 1);
|
||||||
|
if (got <= 0) {
|
||||||
|
print("polltest: FAIL read after poll-ready\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
buffer[got] = 0;
|
||||||
|
|
||||||
|
int ok = streq(buffer, "poll payload");
|
||||||
|
print(ok ? "polltest: payload-ok\n" : "polltest: payload-FAIL\n");
|
||||||
|
if (!ok)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
long writerStatus = userWait(writerPid);
|
||||||
|
if (writerStatus != 0) {
|
||||||
|
print("polltest: FAIL pollwriter reported failure\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
userClose((int)readFd);
|
||||||
|
userClose(idleFds[0]);
|
||||||
|
userClose(idleFds[1]);
|
||||||
|
print("polltest: poll-multiplex-ok\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in new issue
Block a user