test: cover pollTest
This commit is contained in:
1 parent
9dfdd34540
commit
bac6a25d5d
1 file changed
+146
+146
@@ -0,0 +1,146 @@
|
||||
#include "ktest.h"
|
||||
#include "poll.h"
|
||||
#include "vfs.h"
|
||||
#include "pipe.h"
|
||||
|
||||
/*
|
||||
* Pure, scheduler-free coverage for vfsPollReady (vfs.c) and its two
|
||||
* non-consuming peek helpers (pipeHasData/pipeHasSpace, pipe.h;
|
||||
* keyboardReaderHasData, keyboard.h) -- everything that can be driven
|
||||
* single-threaded, exactly like pipeShareTest.c/vfsFifoTest.c already do
|
||||
* for the machinery poll.h's sysPoll is built on top of. The genuine
|
||||
* cross-process block-then-wake handshake (schedule()'s own pollDeadline
|
||||
* expiry scan, sched.c; the shared schedPollChannel wake from a SECOND,
|
||||
* independently scheduled writer) only runs for real at boot
|
||||
* (user/polltest.c + user/pollwriter.c, needles in tools/ci-test.sh) --
|
||||
* the same division of labor this file's neighbors already use, and
|
||||
* schedTest.c's own doc comment explains why: ktestRunAll() runs before
|
||||
* schedStart(), with no second execution context to switch into.
|
||||
*/
|
||||
|
||||
KTEST(vfsPollReadyReportsNvalForClosedOrOutOfRangeFd)
|
||||
{
|
||||
int16 revents = 99;
|
||||
KT_TRUE(t, vfsPollReady(-1, pollIn, &revents));
|
||||
KT_EQ(t, revents, pollNval);
|
||||
|
||||
revents = 99;
|
||||
KT_TRUE(t, vfsPollReady(9999, pollIn | pollOut, &revents));
|
||||
KT_EQ(t, revents, pollNval);
|
||||
}
|
||||
|
||||
KTEST(vfsPollReadyPipeReadEndTracksRealData)
|
||||
{
|
||||
int readFd, writeFd;
|
||||
KT_EQ(t, vfsPipe(&readFd, &writeFd), 0);
|
||||
|
||||
int16 revents = 99;
|
||||
KT_FALSE(t, vfsPollReady(readFd, pollIn, &revents));
|
||||
KT_EQ(t, revents, 0);
|
||||
|
||||
KT_EQ(t, vfsWrite(writeFd, "hi", 2), 2);
|
||||
|
||||
revents = 0;
|
||||
KT_TRUE(t, vfsPollReady(readFd, pollIn, &revents));
|
||||
KT_EQ(t, revents, pollIn);
|
||||
|
||||
/* Asking for pollOut on a read-only end is never satisfiable, no
|
||||
matter how much data is queued. */
|
||||
revents = 99;
|
||||
KT_FALSE(t, vfsPollReady(readFd, pollOut, &revents));
|
||||
KT_EQ(t, revents, 0);
|
||||
|
||||
char buffer[8];
|
||||
KT_EQ(t, vfsRead(readFd, buffer, sizeof(buffer)), 2);
|
||||
vfsClose(readFd);
|
||||
vfsClose(writeFd);
|
||||
}
|
||||
|
||||
KTEST(vfsPollReadyPipeWriteEndTracksFreeSpaceThenFull)
|
||||
{
|
||||
int readFd, writeFd;
|
||||
KT_EQ(t, vfsPipe(&readFd, &writeFd), 0);
|
||||
|
||||
int16 revents = 0;
|
||||
KT_TRUE(t, vfsPollReady(writeFd, pollOut, &revents));
|
||||
KT_EQ(t, revents, pollOut);
|
||||
|
||||
/* Fill the ring completely (pipeBufferSize, pipe.h) with non-blocking
|
||||
writes -- vfsPipe's ends are exactly the unshared, "-1 means try
|
||||
again" kind pipetest.c already depends on, so this can never park
|
||||
the calling (only) thread the way a fdFlagBlocking end would. */
|
||||
char chunk[64];
|
||||
for (int i = 0; i < 64; i++)
|
||||
chunk[i] = (char)i;
|
||||
int64 written = 0;
|
||||
for (int guard = 0; guard < 16; guard++) {
|
||||
int64 got = vfsWrite(writeFd, chunk, sizeof(chunk));
|
||||
if (got <= 0)
|
||||
break;
|
||||
written += got;
|
||||
}
|
||||
KT_TRUE(t, written > 0);
|
||||
KT_EQ(t, vfsWrite(writeFd, chunk, sizeof(chunk)), -1);
|
||||
|
||||
revents = 99;
|
||||
KT_FALSE(t, vfsPollReady(writeFd, pollOut, &revents));
|
||||
KT_EQ(t, revents, 0);
|
||||
|
||||
/* Draining even a little frees space back up. */
|
||||
char sink[16];
|
||||
KT_EQ(t, vfsRead(readFd, sink, sizeof(sink)), 16);
|
||||
revents = 0;
|
||||
KT_TRUE(t, vfsPollReady(writeFd, pollOut, &revents));
|
||||
KT_EQ(t, revents, pollOut);
|
||||
|
||||
vfsClose(readFd);
|
||||
vfsClose(writeFd);
|
||||
}
|
||||
|
||||
KTEST(vfsPollReadyReadEndReportsEofAfterWriterCloses)
|
||||
{
|
||||
int readFd, writeFd;
|
||||
KT_EQ(t, vfsPipe(&readFd, &writeFd), 0);
|
||||
|
||||
int16 revents = 0;
|
||||
KT_FALSE(t, vfsPollReady(readFd, pollIn, &revents));
|
||||
|
||||
vfsClose(writeFd);
|
||||
|
||||
/* A true EOF pipe is "readable" in real poll(2) too -- the next read
|
||||
call returning 0 immediately is exactly what pollIn promises here. */
|
||||
revents = 0;
|
||||
KT_TRUE(t, vfsPollReady(readFd, pollIn, &revents));
|
||||
KT_EQ(t, revents, pollIn);
|
||||
char probe[4];
|
||||
KT_EQ(t, vfsRead(readFd, probe, sizeof(probe)), 0);
|
||||
|
||||
vfsClose(readFd);
|
||||
}
|
||||
|
||||
KTEST(vfsPollReadyConsoleWriteAlwaysReadyReadNeverWithoutInput)
|
||||
{
|
||||
/* fd 0 (console) is already live for the current (idle) thread by the
|
||||
time ktestRunAll() runs -- schedInit() calls vfsFdInit before
|
||||
kmain.c ever reaches ktestRunAll(). Every open reader (idle's fd 0
|
||||
included) gets a copy of every keystroke keyboardHandleScancode ever
|
||||
broadcasts (keyboard.h), including the synthetic ones OTHER test
|
||||
files inject (keyboardTest.c's own coverage) -- KTEST execution
|
||||
order across files is whatever the ".ktests" linker section happens
|
||||
to lay them out in, so idle's fd 0 must be drained here rather than
|
||||
assumed empty, or this test's own result would depend on that order. */
|
||||
char drain[16];
|
||||
while (vfsRead(0, drain, sizeof(drain)) > 0) { }
|
||||
|
||||
int16 revents = 99;
|
||||
KT_FALSE(t, vfsPollReady(0, pollIn, &revents));
|
||||
KT_EQ(t, revents, 0);
|
||||
|
||||
revents = 0;
|
||||
KT_TRUE(t, vfsPollReady(0, pollOut, &revents));
|
||||
KT_EQ(t, revents, pollOut);
|
||||
|
||||
revents = 0;
|
||||
KT_TRUE(t, vfsPollReady(0, pollIn | pollOut, &revents));
|
||||
KT_EQ(t, revents, pollOut);
|
||||
}
|
||||
Reference in new issue
Block a user