test: cover pipeShareTest
This commit is contained in:
1 parent
3009fe6f80
commit
82089a684a
1 file changed
+171
@@ -0,0 +1,171 @@
|
||||
#include "ktest.h"
|
||||
#include "pipe.h"
|
||||
#include "vfs.h"
|
||||
#include "string.h"
|
||||
|
||||
/*
|
||||
* Coverage for the shared-pipe machinery added this wave (pipe.h's
|
||||
* pipeCreateDetached/pipeAddReader/pipeAddWriter/pipeWriteBroken/
|
||||
* pipeChannel, plus vfs.h's vfsPipeCreateHandle/vfsPipeAttach/
|
||||
* vfsBlockingChannel) -- everything two independently spawned processes
|
||||
* need to rendezvous over a real blocking pipe without fork(). The genuine
|
||||
* cross-process park/wake handshake itself only runs for real at boot
|
||||
* (fifomaster.c spawning fifowriter.c/fiforeader.c, needles
|
||||
* "fifomaster: pipeshare ok"/"fiforeader: payload-ok" in tools/ci-test.sh),
|
||||
* the same division of labor pipeBlockTest.c already uses for
|
||||
* pipeReadBlocking/pipeWriteBlocking: what is deterministic and
|
||||
* scheduler-free lives here, what genuinely needs two live execution
|
||||
* contexts is proven live.
|
||||
*/
|
||||
|
||||
KTEST(pipeCreateDetachedStartsWithNeitherEndAttached)
|
||||
{
|
||||
int h = pipeCreateDetached();
|
||||
KT_GE(t, h, 0);
|
||||
|
||||
/* Nobody has attached a writer yet: a read must report "try again"
|
||||
(-1), not spurious end-of-file (0) the way a writers-already-0
|
||||
pipeCreate() pipe correctly would. */
|
||||
char buffer[8];
|
||||
KT_EQ(t, pipeRead(h, buffer, sizeof(buffer)), -1);
|
||||
|
||||
/* Nobody has attached a reader yet either, but a write must still
|
||||
succeed (buffered for whenever a reader shows up), not report a
|
||||
broken pipe the way a readers-already-0 pipeCreate() pipe would. */
|
||||
KT_FALSE(t, pipeWriteBroken(h));
|
||||
KT_EQ(t, pipeWrite(h, "hi", 2), 2);
|
||||
|
||||
char got[8];
|
||||
KT_EQ(t, pipeRead(h, got, sizeof(got)), 2);
|
||||
KT_TRUE(t, memcmp(got, "hi", 2) == 0);
|
||||
|
||||
pipeAddReader(h);
|
||||
pipeAddWriter(h);
|
||||
pipeCloseRead(h);
|
||||
pipeCloseWrite(h);
|
||||
}
|
||||
|
||||
KTEST(pipeAddWriterThenCloseMakesRealEofNotBeforehand)
|
||||
{
|
||||
int h = pipeCreateDetached();
|
||||
KT_GE(t, h, 0);
|
||||
pipeAddReader(h);
|
||||
|
||||
/* Still no writer attached: not EOF. */
|
||||
char buffer[4];
|
||||
KT_EQ(t, pipeRead(h, buffer, sizeof(buffer)), -1);
|
||||
|
||||
pipeAddWriter(h);
|
||||
KT_EQ(t, pipeWrite(h, "z", 1), 1);
|
||||
KT_EQ(t, pipeRead(h, buffer, sizeof(buffer)), 1);
|
||||
|
||||
/* Now that a writer really was attached and has left, an empty ring
|
||||
means true end-of-file. */
|
||||
pipeCloseWrite(h);
|
||||
KT_EQ(t, pipeRead(h, buffer, sizeof(buffer)), 0);
|
||||
|
||||
pipeCloseRead(h);
|
||||
}
|
||||
|
||||
KTEST(pipeAddReaderThenCloseMakesRealBrokenPipeNotBeforehand)
|
||||
{
|
||||
int h = pipeCreateDetached();
|
||||
KT_GE(t, h, 0);
|
||||
pipeAddWriter(h);
|
||||
|
||||
/* No reader attached yet: writing still succeeds, not "broken". */
|
||||
KT_FALSE(t, pipeWriteBroken(h));
|
||||
KT_EQ(t, pipeWrite(h, "a", 1), 1);
|
||||
|
||||
pipeAddReader(h);
|
||||
char buffer[4];
|
||||
KT_EQ(t, pipeRead(h, buffer, sizeof(buffer)), 1);
|
||||
|
||||
/* A reader really was attached and has now left: genuinely broken. */
|
||||
pipeCloseRead(h);
|
||||
KT_TRUE(t, pipeWriteBroken(h));
|
||||
KT_EQ(t, pipeWrite(h, "b", 1), -1);
|
||||
|
||||
pipeCloseWrite(h);
|
||||
}
|
||||
|
||||
KTEST(pipeWriteBrokenAndChannelRejectInvalidHandles)
|
||||
{
|
||||
KT_TRUE(t, pipeWriteBroken(-1));
|
||||
KT_TRUE(t, pipeWriteBroken(999));
|
||||
KT_NULL(t, pipeChannel(-1));
|
||||
KT_NULL(t, pipeChannel(999));
|
||||
|
||||
int h = pipeCreateDetached();
|
||||
KT_GE(t, h, 0);
|
||||
KT_NOTNULL(t, pipeChannel(h));
|
||||
|
||||
int h2 = pipeCreateDetached();
|
||||
KT_GE(t, h2, 0);
|
||||
KT_NE(t, pipeChannel(h), pipeChannel(h2));
|
||||
|
||||
pipeAddReader(h);
|
||||
pipeAddWriter(h);
|
||||
pipeCloseRead(h);
|
||||
pipeCloseWrite(h);
|
||||
pipeAddReader(h2);
|
||||
pipeAddWriter(h2);
|
||||
pipeCloseRead(h2);
|
||||
pipeCloseWrite(h2);
|
||||
}
|
||||
|
||||
KTEST(vfsPipeCreateHandleAndAttachInstallBlockingFds)
|
||||
{
|
||||
int handle = vfsPipeCreateHandle();
|
||||
KT_GE(t, handle, 0);
|
||||
|
||||
int readFd = vfsPipeAttach(handle, false);
|
||||
int writeFd = vfsPipeAttach(handle, true);
|
||||
KT_GE(t, readFd, 0);
|
||||
KT_GE(t, writeFd, 0);
|
||||
KT_NE(t, readFd, writeFd);
|
||||
|
||||
/* An empty, both-ends-attached shared pipe is exactly the "would
|
||||
block, but retrying could resolve it" state sysRead's retry path
|
||||
(syscall.c) depends on. */
|
||||
KT_NOTNULL(t, vfsBlockingChannel(readFd, false));
|
||||
|
||||
KT_EQ(t, vfsWrite(writeFd, "shared", 6), 6);
|
||||
char buffer[8];
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
KT_EQ(t, vfsRead(readFd, buffer, sizeof(buffer)), 6);
|
||||
KT_TRUE(t, memcmp(buffer, "shared", 6) == 0);
|
||||
|
||||
/* Wrong direction / wrong fd kind must never hand back a channel. */
|
||||
KT_NULL(t, vfsBlockingChannel(readFd, true));
|
||||
KT_NULL(t, vfsBlockingChannel(writeFd, false));
|
||||
KT_NULL(t, vfsBlockingChannel(-1, false));
|
||||
|
||||
vfsClose(readFd);
|
||||
vfsClose(writeFd);
|
||||
}
|
||||
|
||||
KTEST(vfsPipeAttachRejectsInvalidHandle)
|
||||
{
|
||||
KT_EQ(t, vfsPipeAttach(-1, false), -1);
|
||||
KT_EQ(t, vfsPipeAttach(999, true), -1);
|
||||
}
|
||||
|
||||
KTEST(vfsBlockingChannelIsNullForOrdinaryNonBlockingPipe)
|
||||
{
|
||||
/* vfsPipe's anonymous pipe (both ends in the caller's own table) must
|
||||
keep reporting "try again" (-1) to the caller directly, the way
|
||||
pipetest.c depends on -- vfsBlockingChannel must never treat it as
|
||||
blockable, or sysRead/sysWrite would start parking a single-process
|
||||
pipe reader/writer that expects an immediate -1 back. */
|
||||
int readFd, writeFd;
|
||||
KT_EQ(t, vfsPipe(&readFd, &writeFd), 0);
|
||||
|
||||
char probe[1];
|
||||
KT_EQ(t, vfsRead(readFd, probe, 0), 0);
|
||||
KT_NULL(t, vfsBlockingChannel(readFd, false));
|
||||
KT_NULL(t, vfsBlockingChannel(writeFd, true));
|
||||
|
||||
vfsClose(readFd);
|
||||
vfsClose(writeFd);
|
||||
}
|
||||
Reference in new issue
Block a user