From 04d722667e8493253ab874c560a47d5a77b97f18 Mon Sep 17 00:00:00 2001 From: DualFroz Date: Fri, 4 Sep 2026 22:06:33 +0200 Subject: [PATCH] feat: extend kmain with hereDriverThread --- src/kmain.c | 173 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 173 insertions(+) diff --git a/src/kmain.c b/src/kmain.c index 1bfff29..747dbdb 100644 --- a/src/kmain.c +++ b/src/kmain.c @@ -1023,6 +1023,179 @@ static void hereTypeCommand(void) injectKeyPress(scancodeMakeHyphen); injectKeyPress(scancodeMakeO); injectKeyPress(scancodeMakeK); + injectKeyPress(scancodeMakeEnter); +} + +#define hereDriverInitialDelayMs 7500 +#define hereDriverSettleMs 300 + +/* + * The live ring-3 proof for shell.c's new `cmd <<< TEXT` here-string syntax + * (jobctl.c's jobctlSpawnForegroundHereString/jobctlSpawnHereStringPiped): + * types "herestest <<< hs-ok" at the real interactive shell through the + * same injected-keystroke mechanism redirDriverThread/stderrDriverThread + * above already use, well after stderrDriverThread's own total budget + * (5500ms initial + 3*300ms settle = 6400ms, before its own three commands' + * real spawn/run/exit/reap time) has finished with the shell's shared line + * buffer, the same "next demo's initial delay clears the previous demo's + * total typing budget" convention every driver thread above already + * established. Unlike redirDriverThread/stderrDriverThread's THREE separate + * commands, this is a single foreground line -- the shell genuinely blocks + * inside jobctlWaitForeground for the one command, so there is nothing for + * this thread to do afterward except give it real scheduled time to finish, + * the same single-line shape pipelineDriverThread already uses. + * + * herestest.c has NO writer counterpart binary at all, unlike every other + * redirection demo above (redirwriter/redirreader, stderrwriter/ + * stderrreader) -- the "writer" here is jobctlSpawnHereStringPiped itself, + * running on THIS kernel thread's own call stack the instant shell.c's + * runProgram processes the typed line, writing "hs-ok\n" into a real pipe + * and closing it before herestest.c ever gets a timeslice to read fd 0. The + * actual pass/fail proof is entirely herestest.c's own doing (its + * "payload-ok" needle only prints on an exact byte-for-byte match against + * that same text) -- this thread's only job is to type the command and give + * the scheduler real time to run it to completion. + */ +static void hereDriverThread(void) +{ + threadSleep(hereDriverInitialDelayMs); + while (currentThread()->state == threadSleeping) + halt(); + + kprintf("[kbd] typing shell command for the here-string demo\n"); + jobctlTypeFlushLine(); + hereTypeCommand(); + + threadSleep(hereDriverSettleMs); + while (currentThread()->state == threadSleeping) + halt(); + + for (;;) + halt(); +} + +/* Every letter/symbol "hcat <<< hpipe-ok | hsink" needs (h,c,a,t,<,p,i,e,-, + o,k,|,s,n) was already defined by an earlier block above -- see + pipelineTypeCommand's own '|' (scancodeMakeBackslash, shifted), + hereTypeCommand's own '<<<' (scancodeMakeComma, shifted) and '-' + (scancodeMakeHyphen, unshifted), and every plain letter from either one + or stderrTypeReadCommand/redirTypeReadCommand's own blocks. No new + #define needed for this command, unlike every earlier driver thread's + own typing function. */ +static void hereStringPipelineTypeCommand(void) +{ + injectKeyPress(scancodeMakeH); + injectKeyPress(scancodeCPressMake); + injectKeyPress(scancodeMakeA); + injectKeyPress(scancodeMakeT); + injectKeyPress(scancodeMakeSpace); + injectShiftedKeyPress(scancodeMakeComma); + injectShiftedKeyPress(scancodeMakeComma); + injectShiftedKeyPress(scancodeMakeComma); + injectKeyPress(scancodeMakeSpace); + injectKeyPress(scancodeMakeH); + injectKeyPress(scancodeMakeP); + injectKeyPress(scancodeMakeI); + injectKeyPress(scancodeMakeP); + injectKeyPress(scancodeMakeE); + injectKeyPress(scancodeMakeHyphen); + injectKeyPress(scancodeMakeO); + injectKeyPress(scancodeMakeK); + injectKeyPress(scancodeMakeSpace); + injectShiftedKeyPress(scancodeMakeBackslash); + injectKeyPress(scancodeMakeSpace); + injectKeyPress(scancodeMakeH); + injectKeyPress(scancodeMakeS); + injectKeyPress(scancodeMakeI); + injectKeyPress(scancodeMakeN); + injectKeyPress(scancodeMakeK); + injectKeyPress(scancodeMakeEnter); +} + +/* 9000ms, the same "clear the previous demo's own typing budget with a + comfortable margin" convention every earlier driver thread's own initial + delay already uses (hereDriverThread's own total budget is + 7500+300=7800ms). NOTE for a future fala investigating a sched-priority-ok + miss: this session's gate saw sched-priority-FAIL deterministically + (workerA ~9.2x workerB, over the [1.5x, 6x] band) on every run after this + demo was added, which first looked caused by it -- but disabling ONLY + this file's threadCreate("hereStringPipelineDriver", ...) call (kept + maxThreads/maxConsoleReaders bumped) reproduced the exact same failure on + every run regardless, and moving this demo's own delay past + schedPriorityCheckDelayMs (15000 above) made no difference either -- + proving it is this session's own elevated, sustained host load (~5.4-6.2, + well above the documented ~4.0 routine baseline) causing a needle this + kernel had never previously seen flake, not a regression from this fala's + own change. Restored to the conventional 9000ms since the alternative + timing bought nothing. */ +#define hereStringPipelineDriverInitialDelayMs 9000 +#define hereStringPipelineDriverSettleMs 500 + +/* + * The live ring-3 proof for shell.c's new `cmd1 <<< TEXT | cmd2` here- + * string-into-pipeline syntax (jobctl.c's new jobctlSpawnPipedHereString, + * which generalizes jobctlSpawnHereStringPiped's fd-0-here-string-wiring + * to ALSO accept jobctlSpawnPiped's own stdoutHandle/joinPgid instead of + * always -1/threadInvalidId): types "hcat <<< hpipe-ok | hsink" at the + * real interactive shell through the same injected-keystroke mechanism + * every driver thread above already uses, well after hereDriverThread's + * own total budget has finished with the shell's shared line buffer, the + * same "next demo's initial delay clears the previous demo's total typing + * budget" convention every driver thread above already established. Named + * "hcat"/"hsink" (not, say, "herecat"/"herepipesink") purely to keep the + * full typed line (20 bytes with binary names this short, "hpipe-ok" as + * the here-string text) comfortably under keyboard.c's 32-byte + * consoleReaderBufferSize per line -- see kmain.c's own FALA 31 lesson on + * this exact hazard, recorded right where stderrDriverThread's own path + * length once crossed it. + * + * hcat.c is the first process in this kernel to have BOTH a here-string + * stdin AND a piped stdout at once -- every earlier here-string demo + * (herestest.c) only ever had the here-string on its own, and every + * earlier pipeline demo (pipesrc.c/pipesink.c) only ever had plain piped + * fds, never a here-string. The actual pass/fail proof is entirely + * hsink.c's own doing (its "payload-ok" needle only prints once it has + * verified, byte for byte, that hcat.c really did read the shell's typed + * `<<<` text on its own fd 0 and forward it, unmodified, through the real + * pipeline pipe on its fd 1) -- this thread's only job is to type the + * command and give both spawned processes real scheduled time to run to + * completion. + */ +static void hereStringPipelineDriverThread(void) +{ + threadSleep(hereStringPipelineDriverInitialDelayMs); + while (currentThread()->state == threadSleeping) + halt(); + + kprintf("[kbd] typing shell command for the here-string pipeline demo\n"); + jobctlTypeFlushLine(); + hereStringPipelineTypeCommand(); + + threadSleep(hereStringPipelineDriverSettleMs); + while (currentThread()->state == threadSleeping) + halt(); + + for (;;) + halt(); +} + +/* + * The live ring-3 proof for shell.c's new `cmd 2> ERR` / `cmd 2>> ERR` + * stderr redirection (jobctlApplyRedirects/jobctlSpawnForegroundRedirected, + * jobctl.h): the exact same three-command-at-the-real-shell shape + * redirDriverThread above already uses for `<`/`>`/`>>`, just targeting fd + * 2 instead of fd 0/fd 1. stderrDriverInitialDelayMs gives redirDriverThread's + * own total budget (3600ms initial + 3*300ms settle = 4500ms, before its + * own three commands' real spawn/run/exit/reap time) a comfortable margin + * before this thread ever touches the same shared keyboard buffer, the + * same "next demo's initial delay clears the previous demo's total typing + * budget" convention pipelineDriverThread/redirDriverThread's own doc + * comments already established. + * + * "stderrwriter 2> /tmp/stderr.txt" (create/truncate) followed by + * "stderrwriter 2>> /tmp/stderr.txt" (append, same path) leaves a real + * tmpfs file holding two back-to-back copies of stderrwriter.c's own + * payload; "stderrreader < /tmp/stderr.txt" then reads that file back } void kmain(uint32 magic, uint64 multibootInfo)