test: cover pipeBlockTest
This commit is contained in:
1 parent
da86448949
commit
3009fe6f80
1 file changed
+113
@@ -0,0 +1,113 @@
|
||||
#include "ktest.h"
|
||||
#include "pipe.h"
|
||||
#include "string.h"
|
||||
|
||||
/*
|
||||
* pipeReadBlocking/pipeWriteBlocking only return without parking the thread
|
||||
* when the very first attempt already resolves (data/space/EOF/broken-pipe
|
||||
* already true) - any scenario that would genuinely need to park calls
|
||||
* halt(), which requires a live, interrupt-driven scheduler to ever resume
|
||||
* from. ktestRunAll() runs before schedStart() (see ktest.h) on the sole
|
||||
* execution context there is, so these tests deliberately only cover the
|
||||
* "resolves immediately, never blocks" paths. The genuine cross-thread
|
||||
* park/wake handshake is exercised for real at boot by the producer/consumer
|
||||
* demo in kmain.c (needle "pipe demo: eof, count=10" in tools/ci-test.sh).
|
||||
*/
|
||||
|
||||
KTEST(pipeReadBlockingReturnsQueuedDataImmediately)
|
||||
{
|
||||
int h = pipeCreate();
|
||||
KT_GE(t, h, 0);
|
||||
|
||||
const char* msg = "already here";
|
||||
KT_EQ(t, pipeWrite(h, msg, strlen(msg)), (int64)strlen(msg));
|
||||
|
||||
char buffer[32];
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
int64 got = pipeReadBlocking(h, buffer, sizeof(buffer));
|
||||
KT_EQ(t, got, (int64)strlen(msg));
|
||||
KT_TRUE(t, memcmp(buffer, msg, strlen(msg)) == 0);
|
||||
|
||||
pipeCloseRead(h);
|
||||
pipeCloseWrite(h);
|
||||
}
|
||||
|
||||
KTEST(pipeReadBlockingReturnsEofWithoutParking)
|
||||
{
|
||||
int h = pipeCreate();
|
||||
KT_GE(t, h, 0);
|
||||
|
||||
pipeCloseWrite(h);
|
||||
|
||||
char buffer[8];
|
||||
KT_EQ(t, pipeReadBlocking(h, buffer, sizeof(buffer)), 0);
|
||||
|
||||
pipeCloseRead(h);
|
||||
}
|
||||
|
||||
KTEST(pipeReadBlockingRejectsInvalidHandleWithoutParking)
|
||||
{
|
||||
char buffer[8];
|
||||
KT_EQ(t, pipeReadBlocking(-1, buffer, sizeof(buffer)), -1);
|
||||
KT_EQ(t, pipeReadBlocking(999, buffer, sizeof(buffer)), -1);
|
||||
}
|
||||
|
||||
KTEST(pipeWriteBlockingSucceedsImmediatelyWhenRoomExists)
|
||||
{
|
||||
int h = pipeCreate();
|
||||
KT_GE(t, h, 0);
|
||||
|
||||
const char* msg = "room to spare";
|
||||
int64 written = pipeWriteBlocking(h, msg, strlen(msg));
|
||||
KT_EQ(t, written, (int64)strlen(msg));
|
||||
|
||||
char buffer[32];
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
KT_EQ(t, pipeRead(h, buffer, sizeof(buffer)), (int64)strlen(msg));
|
||||
|
||||
pipeCloseRead(h);
|
||||
pipeCloseWrite(h);
|
||||
}
|
||||
|
||||
KTEST(pipeWriteBlockingOnBrokenPipeReturnsWithoutParking)
|
||||
{
|
||||
int h = pipeCreate();
|
||||
KT_GE(t, h, 0);
|
||||
|
||||
pipeCloseRead(h);
|
||||
|
||||
const char* msg = "nobody listening";
|
||||
KT_EQ(t, pipeWriteBlocking(h, msg, strlen(msg)), -1);
|
||||
|
||||
pipeCloseWrite(h);
|
||||
}
|
||||
|
||||
KTEST(pipeWriteBlockingRejectsInvalidHandleWithoutParking)
|
||||
{
|
||||
char buffer[4] = { 0 };
|
||||
KT_EQ(t, pipeWriteBlocking(-1, buffer, sizeof(buffer)), -1);
|
||||
KT_EQ(t, pipeWriteBlocking(999, buffer, sizeof(buffer)), -1);
|
||||
}
|
||||
|
||||
KTEST(pipeWriteBlockingSucceedsRightAfterDrainFreesRoom)
|
||||
{
|
||||
int h = pipeCreate();
|
||||
KT_GE(t, h, 0);
|
||||
|
||||
uint8 chunk[pipeBufferSize];
|
||||
memset(chunk, 0x5A, sizeof(chunk));
|
||||
|
||||
KT_EQ(t, pipeWrite(h, chunk, sizeof(chunk)), (int64)sizeof(chunk));
|
||||
|
||||
/* buffer is completely full: a blocking write would have to park here if
|
||||
nothing ever drained it, so proving this call returns at all (rather
|
||||
than hanging the whole test run) is exactly the point. */
|
||||
uint8 drained[16];
|
||||
KT_EQ(t, pipeRead(h, drained, sizeof(drained)), (int64)sizeof(drained));
|
||||
|
||||
int64 written = pipeWriteBlocking(h, chunk, sizeof(drained));
|
||||
KT_EQ(t, written, (int64)sizeof(drained));
|
||||
|
||||
pipeCloseRead(h);
|
||||
pipeCloseWrite(h);
|
||||
}
|
||||
Reference in new issue
Block a user