147 lines
4.8 KiB
C
147 lines
4.8 KiB
C
#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);
|
|
}
|