feat: extend kmain with stderrDriverThread

This commit is contained in:
dualfroz committed 2026-09-04 22:45:01 +02:00
1 parent 04d722667e
commit d621db9147
1 file changed
+173
+173
View File
@@ -1196,6 +1196,179 @@ static void hereStringPipelineDriverThread(void)
* "stderrwriter 2>> /tmp/stderr.txt" (append, same path) leaves a real * "stderrwriter 2>> /tmp/stderr.txt" (append, same path) leaves a real
* tmpfs file holding two back-to-back copies of stderrwriter.c's own * tmpfs file holding two back-to-back copies of stderrwriter.c's own
* payload; "stderrreader < /tmp/stderr.txt" then reads that file back * payload; "stderrreader < /tmp/stderr.txt" then reads that file back
* through a REAL redirected stdin and compares it byte-for-byte against
* exactly that doubled payload. The actual pass/fail proof is entirely
* stderrreader.c's own doing (its "payload-ok" needle only prints on an
* exact match) -- this thread's only job is to type the three commands and
* give the scheduler real time between them.
*/
static void stderrDriverThread(void)
{
threadSleep(stderrDriverInitialDelayMs);
while (currentThread()->state == threadSleeping)
halt();
kprintf("[kbd] typing shell commands for the stderr redirection demo\n");
jobctlTypeFlushLine();
stderrTypeWriteTruncateCommand();
threadSleep(stderrDriverStepSettleMs);
while (currentThread()->state == threadSleeping)
halt();
stderrTypeWriteAppendCommand();
threadSleep(stderrDriverStepSettleMs);
while (currentThread()->state == threadSleeping)
halt();
stderrTypeReadCommand();
threadSleep(stderrDriverStepSettleMs);
while (currentThread()->state == threadSleeping)
halt();
for (;;)
halt();
}
/* 10700ms gives hereStringPipelineDriverThread's own total budget
(9000+500=9500ms, above its own real hcat/hsink spawn/run/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 every driver thread above already
established. Settle is 600ms (slightly more than pipelineDriverThread's
own 500ms for a 2-stage pipe) since this demo's pipe has one more real
process (pipesrc, pipecat, AND pipesink) to spawn, run, and reap before
the final needle can print. */
#define threeStagePipelineDriverInitialDelayMs 10700
#define threeStagePipelineDriverSettleMs 600
static void threeStagePipelineTypeCommand(void)
{
injectKeyPress(scancodeMakeP);
injectKeyPress(scancodeMakeI);
injectKeyPress(scancodeMakeP);
injectKeyPress(scancodeMakeE);
injectKeyPress(scancodeMakeS);
injectKeyPress(scancodeMakeR);
injectKeyPress(scancodeCPressMake);
injectKeyPress(scancodeMakeSpace);
injectShiftedKeyPress(scancodeMakeBackslash);
injectKeyPress(scancodeMakeSpace);
injectKeyPress(scancodeMakeP);
injectKeyPress(scancodeMakeI);
injectKeyPress(scancodeMakeP);
injectKeyPress(scancodeMakeE);
injectKeyPress(scancodeCPressMake);
injectKeyPress(scancodeMakeA);
injectKeyPress(scancodeMakeT);
injectKeyPress(scancodeMakeSpace);
injectShiftedKeyPress(scancodeMakeBackslash);
injectKeyPress(scancodeMakeSpace);
injectKeyPress(scancodeMakeP);
injectKeyPress(scancodeMakeI);
injectKeyPress(scancodeMakeP);
injectKeyPress(scancodeMakeE);
injectKeyPress(scancodeMakeS);
injectKeyPress(scancodeMakeI);
injectKeyPress(scancodeMakeN);
injectKeyPress(scancodeMakeK);
injectKeyPress(scancodeMakeEnter);
}
/*
* The live ring-3 proof for shell.c's new REAL N-stage pipeline
* (runPipelineStages/jobctlWaitPipelineStages) going past two stages: types
* "pipesrc | pipecat | pipesink" at the real interactive shell through the
* same injected-keystroke mechanism every driver thread above already
* uses, well after hereStringPipelineDriverThread's own total budget has
* finished with the shell's shared line buffer.
*
* pipesrc.c and pipesink.c are reused completely unchanged from the
* two-stage pipeline demo (FALA 29) -- their own narration ("wrote
* payload", "blocking on read, waiting for pipesrc", "payload-ok") is still
* literally true here, just relayed through one more real process instead
* of being directly adjacent. The new thing this demo actually proves is
* user/pipecat.c in the middle: jobctlSpawnPiped bakes a real pipe into
* BOTH its fd 0 (from pipesrc's pipe) and its fd 1 (to pipesink's pipe)
* before it ever runs a single instruction -- the first process in this
* kernel with two DIFFERENT real inter-process pipes on its stdio at once
* (hcat.c's own simultaneous piped-stdin-and-stdout, FALA 34, had a
* shell-fed here-string on the stdin side, never a second real pipe). The
* actual pass/fail proof is still entirely pipesink.c's own doing (its
* "payload-ok" needle only prints on an exact byte-for-byte match of
* whatever pipesrc originally wrote) -- this thread's only job is to type
* the command and give all three spawned processes (none of which ever
* sleeps or waits on a real timer) a comfortable amount of real scheduled
* time to run to completion.
*/
static void threeStagePipelineDriverThread(void)
{
threadSleep(threeStagePipelineDriverInitialDelayMs);
while (currentThread()->state == threadSleeping)
halt();
kprintf("[kbd] typing shell command for the three-stage pipeline demo\n");
jobctlTypeFlushLine();
threeStagePipelineTypeCommand();
threadSleep(threeStagePipelineDriverSettleMs);
while (currentThread()->state == threadSleeping)
halt();
for (;;)
halt();
}
/* '=' (sysGetEnv/sysSetEnv's own operator, shell.c's `export N=V`
builtin), 'y'/'Y', and 'v'/'V' are the only three make codes no earlier
driver thread above ever needed -- every other letter "export",
"GREETING", "envprint", and "env" use (e,x,p,o,r,t,g,i,n,f,s,b) was
already defined by an earlier block. Cross-checked against
keyboard.c's own scancodeLower/scancodeUpper tables the same way every
block above documents for its own new codes. */
#define scancodeMakeEquals 0x0D
#define scancodeMakeY 0x15
#define scancodeMakeV 0x2F
static void envTypeExportCommand(void)
{
injectKeyPress(scancodeMakeE);
injectKeyPress(scancodeMakeX);
injectKeyPress(scancodeMakeP);
injectKeyPress(scancodeMakeO);
injectKeyPress(scancodeMakeR);
injectKeyPress(scancodeMakeT);
injectKeyPress(scancodeMakeSpace);
injectShiftedKeyPress(scancodeMakeG);
injectShiftedKeyPress(scancodeMakeR);
injectShiftedKeyPress(scancodeMakeE);
injectShiftedKeyPress(scancodeMakeE);
injectShiftedKeyPress(scancodeMakeT);
injectShiftedKeyPress(scancodeMakeI);
injectShiftedKeyPress(scancodeMakeN);
injectShiftedKeyPress(scancodeMakeG);
injectKeyPress(scancodeMakeEquals);
injectKeyPress(scancodeMakeF);
injectKeyPress(scancodeMakeR);
injectKeyPress(scancodeMakeO);
injectKeyPress(scancodeMakeS);
injectKeyPress(scancodeMakeT);
injectKeyPress(scancodeMakeB);
injectKeyPress(scancodeMakeY);
injectKeyPress(scancodeMakeT);
injectKeyPress(scancodeMakeE);
injectKeyPress(scancodeMakeEnter);
}
static void envTypeEnvprintCommand(void)
{
injectKeyPress(scancodeMakeE);
injectKeyPress(scancodeMakeN);
injectKeyPress(scancodeMakeV);
injectKeyPress(scancodeMakeP);
injectKeyPress(scancodeMakeR);
injectKeyPress(scancodeMakeI);
injectKeyPress(scancodeMakeN);
} }
void kmain(uint32 magic, uint64 multibootInfo) void kmain(uint32 magic, uint64 multibootInfo)