feat: introduce streq and printErr
This commit is contained in:
1 parent
0f4437ed80
commit
f9973a7fe8
3 files changed
+159
No files matched your search
@@ -0,0 +1,65 @@
|
|||||||
|
#include "ulib.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Right half of shell.c's new `cmd1 | cmd2` pipeline syntax's live demo --
|
||||||
|
* see pipesrc.c's own header comment for the full picture. jobctlSpawnPiped
|
||||||
|
* bakes the SAME pipe's read end into this process's own fd 0 before it
|
||||||
|
* ever runs, so the blocking userRead below has to genuinely retry across
|
||||||
|
* timer ticks (fd 0's pipe end is flagged fdFlagBlocking, see
|
||||||
|
* vfsPipeAttachInto) until pipesrc.c's own write actually lands, exactly
|
||||||
|
* the same real cross-process wake this kernel's every other pipe/fifo
|
||||||
|
* demo already proves (schedWakeChannel via pipeWrite, pipe.c) -- never a
|
||||||
|
* coincidence of scheduling order (jobctlSpawnPiped installs pipesrc.c's
|
||||||
|
* write end into the pipe's writer count the moment IT is created, well
|
||||||
|
* before it ever runs, so this process can never see a false "no writer,
|
||||||
|
* EOF" even if it is scheduled to run first).
|
||||||
|
*
|
||||||
|
* Reads in a loop until a real EOF (0 return, once pipesrc.c has both
|
||||||
|
* written and exited -- see that file's own comment on why exit matters
|
||||||
|
* here) rather than trusting a single userRead call to receive the whole
|
||||||
|
* payload in one shot, the honest way a real pipe reader has to work.
|
||||||
|
*
|
||||||
|
* Unlike pipesrc.c, this process's own fd 1 (stdout) is NOT part of the
|
||||||
|
* pipeline (only fd 0 was redirected) -- print()/printDec() (ulib.h) reach
|
||||||
|
* the real console exactly like any unpiped demo, so the needle below is
|
||||||
|
* exactly as observable to ci-test.sh as every other one.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int streq(const char* a, const char* b)
|
||||||
|
{
|
||||||
|
while (*a && *a == *b) {
|
||||||
|
a++;
|
||||||
|
b++;
|
||||||
|
}
|
||||||
|
return *a == *b;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
print("pipesink: blocking on read, waiting for pipesrc\n");
|
||||||
|
|
||||||
|
char buffer[64];
|
||||||
|
unsigned long total = 0;
|
||||||
|
for (;;) {
|
||||||
|
long got = userRead(0, buffer + total, sizeof(buffer) - 1 - total);
|
||||||
|
if (got < 0) {
|
||||||
|
print("pipesink: FAIL read\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (got == 0)
|
||||||
|
break;
|
||||||
|
total += (unsigned long)got;
|
||||||
|
if (total >= sizeof(buffer) - 1)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
buffer[total] = 0;
|
||||||
|
|
||||||
|
print("pipesink: got: ");
|
||||||
|
print(buffer);
|
||||||
|
print("\n");
|
||||||
|
|
||||||
|
int ok = streq(buffer, "pipeline-payload-ok");
|
||||||
|
print(ok ? "pipesink: payload-ok\n" : "pipesink: payload-FAIL\n");
|
||||||
|
|
||||||
|
return ok ? 0 : 1;
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
#include "ulib.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Left half of shell.c's new `cmd1 | cmd2` pipeline syntax's live demo.
|
||||||
|
* jobctlSpawnPiped (jobctl.h) bakes a real pipe end into this process's own
|
||||||
|
* fd 1 BEFORE it ever runs a single instruction (vfsPipeAttachInto, vfs.h)
|
||||||
|
* -- from this program's own point of view it writes its stdout exactly
|
||||||
|
* like any well-behaved Unix filter, with no idea a pipe is on the other
|
||||||
|
* end instead of the real console. fd 2 (stderr) is deliberately left
|
||||||
|
* alone by the pipeline setup (only fd 0/fd 1 are ever redirected, matching
|
||||||
|
* a real shell), so the diagnostic lines below go straight to the real
|
||||||
|
* console even though fd 1's own payload does not -- writing them through
|
||||||
|
* fd 1 instead (print()/printDec(), ulib.h, both hardcoded to fd 1) would
|
||||||
|
* corrupt the exact payload pipesink.c compares against.
|
||||||
|
*
|
||||||
|
* Deliberately writes once and exits immediately: pipesink.c's own
|
||||||
|
* blocking read has to notice the resulting EOF (this process's own exit
|
||||||
|
* reclaims its fd 1, dropping the pipe's writer count to 0 -- see
|
||||||
|
* sched.c's reclaimOpenFds) the same way every other pipe/fifo EOF demo in
|
||||||
|
* this kernel already does, not just receive the payload.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define pipelinePayload "pipeline-payload-ok"
|
||||||
|
|
||||||
|
static void printErr(const char* text)
|
||||||
|
{
|
||||||
|
userWrite(2, text, stringLength(text));
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
printErr("pipesrc: writing payload to stdout (pipe)\n");
|
||||||
|
|
||||||
|
unsigned long length = stringLength(pipelinePayload);
|
||||||
|
long written = userWrite(1, pipelinePayload, length);
|
||||||
|
if (written != (long)length) {
|
||||||
|
printErr("pipesrc: FAIL short/failed write\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
printErr("pipesrc: wrote payload\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
#include "ulib.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Only ever spawned by polltest.c, with the shared pipe's handle number as
|
||||||
|
* argv[1] (decToString'd -- see polltest.c, mirrors fifomaster.c's own
|
||||||
|
* handle-passing convention). Sleeps well past when polltest.c will
|
||||||
|
* already be parked inside its own userPoll(..., -1) call, so the write
|
||||||
|
* below has to actually wake it back up (schedWakeChannel(schedPollChannel()),
|
||||||
|
* pipeWrite in pipe.c) instead of polltest simply finding the pipe already
|
||||||
|
* readable -- proof the block was real, not a lucky race, the same shape
|
||||||
|
* fifowriter.c already proves for a plain blocking read().
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Comfortably longer than polltest.c's own phase-2 bounded-timeout poll
|
||||||
|
(pollTimeoutMs, polltest.c) -- pollwriter is spawned immediately, at the
|
||||||
|
very start of polltest.c (mirroring fifomaster.c's own immediate double-
|
||||||
|
spawn), so by the time polltest reaches its phase-3 blocking multi-fd
|
||||||
|
poll, phase 2's own wait has already used up part of this delay; the
|
||||||
|
margin here guarantees phase 3 still genuinely has to block and be woken
|
||||||
|
by the write below, not race a write that already happened. */
|
||||||
|
#define pollWriterDelayMs 500
|
||||||
|
|
||||||
|
static const char* payload = "poll payload";
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
if (argc != 2) {
|
||||||
|
print("pollwriter: FAIL expected one argv (pipe handle)\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
long handle = parseDec(argv[1]);
|
||||||
|
long fd = userPipeAttach(handle, 1);
|
||||||
|
if (fd < 0) {
|
||||||
|
print("pollwriter: FAIL attach\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
print("pollwriter: attached, sleeping before write\n");
|
||||||
|
userSleep(pollWriterDelayMs);
|
||||||
|
|
||||||
|
long written = userWrite((int)fd, payload, stringLength(payload));
|
||||||
|
if (written != (long)stringLength(payload)) {
|
||||||
|
print("pollwriter: FAIL short/failed write\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
print("pollwriter: wrote payload\n");
|
||||||
|
|
||||||
|
userClose((int)fd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in new issue
Block a user