From b4acf5d4d28427e759896e4b58105fc90c83858d Mon Sep 17 00:00:00 2001 From: DualFroz Date: Tue, 8 Sep 2026 23:22:55 +0200 Subject: [PATCH] feat: add streq and printErr --- user/fifomaster.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++ user/fiforeader.c | 53 ++++++++++++++++++++++++++++++++++++++++++++ user/fifowriter.c | 43 ++++++++++++++++++++++++++++++++++++ user/globcat.c | 51 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 203 insertions(+) create mode 100644 user/fifomaster.c create mode 100644 user/fiforeader.c create mode 100644 user/fifowriter.c create mode 100644 user/globcat.c diff --git a/user/fifomaster.c b/user/fifomaster.c new file mode 100644 index 0000000..539a86f --- /dev/null +++ b/user/fifomaster.c @@ -0,0 +1,56 @@ +#include "ulib.h" + +/* + * Drives the shared-pipe demo added this wave (pipeCreateDetached/ + * pipeAddReader/pipeAddWriter, pipe.h; vfsPipeCreateHandle/vfsPipeAttach, + * vfs.h; sysRead/sysWrite's retry-the-syscall path, syscall.c): creates one + * detached pipe handle and hands it to two INDEPENDENTLY spawned processes + * as a decimal argv string (decToString/parseDec, ulib.c) rather than a + * shared fd -- frostbyte has no fork(), so a raw pipe.h handle number is + * the only thing two unrelated processes can rendezvous on. fifowriter.c + * deliberately sleeps before writing, so fiforeader.c's read() genuinely + * has to block across several timer ticks and be woken later, not just win + * a scheduling race against an already-full buffer -- see fifowriter.c/ + * fiforeader.c for how each end proves that on its own side. + */ + +int main(void) +{ + print("fifomaster: start, pid="); + printDec(userGetpid()); + print("\n"); + + long handle = userPipeCreate(); + if (handle < 0) { + print("fifomaster: FAIL pipe create\n"); + return 1; + } + + char handleStr[24]; + decToString(handle, handleStr); + + char* readerArgv[] = { "/bin/fiforeader", handleStr, 0 }; + long readerPid = userSpawn("/bin/fiforeader", readerArgv); + if (readerPid < 0) { + print("fifomaster: FAIL spawn fiforeader\n"); + return 1; + } + + char* writerArgv[] = { "/bin/fifowriter", handleStr, 0 }; + long writerPid = userSpawn("/bin/fifowriter", writerArgv); + if (writerPid < 0) { + print("fifomaster: FAIL spawn fifowriter\n"); + return 1; + } + + long readerStatus = userWait(readerPid); + long writerStatus = userWait(writerPid); + + if (readerStatus != 0 || writerStatus != 0) { + print("fifomaster: FAIL reader or writer reported failure\n"); + return 1; + } + + print("fifomaster: pipeshare ok\n"); + return 0; +} diff --git a/user/fiforeader.c b/user/fiforeader.c new file mode 100644 index 0000000..0887fc9 --- /dev/null +++ b/user/fiforeader.c @@ -0,0 +1,53 @@ +#include "ulib.h" + +/* + * Only ever spawned by fifomaster.c, with the shared pipe's handle number + * as argv[1]. Attaches its end and immediately calls a blocking read() on + * a pipe fifowriter.c (spawned alongside it, sleeping before it writes) + * has not put anything into yet -- this call must genuinely park (the + * syscall-restart path in syscall.c's sysRead, parked on pipeChannel) and + * only return once fifowriter.c's write wakes it back up, not before. + */ + +static int streq(const char* a, const char* b) +{ + while (*a && *a == *b) { + a++; + b++; + } + return *a == *b; +} + +int main(int argc, char** argv) +{ + if (argc != 2) { + print("fiforeader: FAIL expected one argv (pipe handle)\n"); + return 1; + } + + long handle = parseDec(argv[1]); + long fd = userPipeAttach(handle, 0); + if (fd < 0) { + print("fiforeader: FAIL attach\n"); + return 1; + } + + print("fiforeader: attached, blocking on read\n"); + char buffer[64]; + long got = userRead((int)fd, buffer, sizeof(buffer) - 1); + if (got <= 0) { + print("fiforeader: FAIL read\n"); + return 1; + } + buffer[got] = 0; + + print("fiforeader: got: "); + print(buffer); + print("\n"); + + int ok = streq(buffer, "shared pipe payload"); + print(ok ? "fiforeader: payload-ok\n" : "fiforeader: payload-FAIL\n"); + + userClose((int)fd); + return ok ? 0 : 1; +} diff --git a/user/fifowriter.c b/user/fifowriter.c new file mode 100644 index 0000000..de14e5e --- /dev/null +++ b/user/fifowriter.c @@ -0,0 +1,43 @@ +#include "ulib.h" + +/* + * Only ever spawned by fifomaster.c, with the shared pipe's handle number + * as argv[1] (decToString'd -- see fifomaster.c). Sleeps well past when + * fiforeader.c (spawned moments earlier) will already be parked in a + * blocking read() on the still-empty pipe, so the write below has to + * actually wake it back up (schedWakeChannel, pipeWrite in pipe.c) instead + * of the reader simply finding data already waiting for it -- proof that + * the block was real, not a lucky race. + */ + +#define fifoWriterDelayMs 200 + +static const char* payload = "shared pipe payload"; + +int main(int argc, char** argv) +{ + if (argc != 2) { + print("fifowriter: FAIL expected one argv (pipe handle)\n"); + return 1; + } + + long handle = parseDec(argv[1]); + long fd = userPipeAttach(handle, 1); + if (fd < 0) { + print("fifowriter: FAIL attach\n"); + return 1; + } + + print("fifowriter: attached, sleeping before write\n"); + userSleep(fifoWriterDelayMs); + + long written = userWrite((int)fd, payload, stringLength(payload)); + if (written != (long)stringLength(payload)) { + print("fifowriter: FAIL short/failed write\n"); + return 1; + } + print("fifowriter: wrote payload\n"); + + userClose((int)fd); + return 0; +} diff --git a/user/globcat.c b/user/globcat.c new file mode 100644 index 0000000..03a9e7a --- /dev/null +++ b/user/globcat.c @@ -0,0 +1,51 @@ +#include "ulib.h" + +/* + * Live proof that shell.c's new wildcard glob expansion (shellExpandGlobs) + * really hands a spawned process REAL, distinct filenames resolved from a + * pattern typed at the shell (`globcat /tmp/gd/ *.txt`) -- not a literal, + * unexpanded "*.txt" string, and not every file in the directory (the + * sibling /tmp/gd/c.log the driver thread also creates must NOT appear). + * Prints how many files it actually received, then each one's own path and + * content, all on fd 1 (unlike pipecat.c/hcat.c, this program's own argv + * and stdout ARE the thing being demonstrated, not a pipe payload it must + * keep pristine). + */ + +static void printErr(const char* text) +{ + userWrite(2, text, stringLength(text)); +} + +int main(int argc, char** argv) +{ + print("globcat: got "); + printDec(argc - 1); + print(" files\n"); + + for (int i = 1; i < argc; i++) { + long fd = userOpen(argv[i], oReadOnly); + if (fd < 0) { + printErr("globcat: FAIL cannot open "); + printErr(argv[i]); + printErr("\n"); + return 1; + } + + char buffer[64]; + long got = userRead((int)fd, buffer, sizeof(buffer) - 1); + userClose((int)fd); + if (got < 0) { + printErr("globcat: FAIL read\n"); + return 1; + } + buffer[got] = 0; + + print("globcat: "); + print(argv[i]); + print("="); + print(buffer); + } + + return 0; +}