feat: extend kmain with pipelineDriverThread and redirTypePath

This commit is contained in:
dualfroz committed 2026-09-04 21:28:35 +02:00
1 parent 750354f099
commit a59ae7a9f8
1 file changed
+173
+173
View File
@@ -677,6 +677,179 @@ static void pipelineTypeCommand(void)
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 `cmd1 | cmd2` pipeline syntax
* (jobctl.h's jobctlSpawnPiped/jobctlWaitPipelineStages do the actual
* fd-baking and multi-wait work): types "pipesrc | pipesink" at the real interactive
* shell through the same injected-keystroke mechanism jobctlDriverThread
* above already uses, well after that thread's own demo has fully
* finished with the shell's shared line buffer (both threads' typed
* characters go through the exact same broadcast keyboardHandleScancode
* path, so they cannot safely interleave -- pipelineDriverInitialDelayMs
* is chosen with a comfortable margin over jobctlDriverThread's own total
* ~1550ms explicit sleep budget above to guarantee that). The actual
* pass/fail proof is entirely pipesink.c's own doing (its "payload-ok"
* needle only prints once it has verified, byte for byte, the exact
* payload pipesrc.c wrote through the real pipe) -- this thread's only job
* is to type the command and give the two spawned processes (neither of
* which ever sleeps or waits on a real timer, unlike alarmtest/polltest) a
* comfortable amount of real scheduled time to run to completion.
*/
static void pipelineDriverThread(void)
{
threadSleep(pipelineDriverInitialDelayMs);
while (currentThread()->state == threadSleeping)
halt();
kprintf("[kbd] typing shell command for the pipeline demo\n");
jobctlTypeFlushLine();
pipelineTypeCommand();
threadSleep(pipelineDriverSettleMs);
while (currentThread()->state == threadSleeping)
halt();
for (;;)
halt();
}
/* Additional letters/symbols needed only by redirDriverThread's own three
commands below -- same cross-checked-against-scancodeLower sourcing as
every block above (index 0x20 is 'd', 0x11 is 'w', 0x32 is 'm', 0x2D is
'x', 0x34 is '.', 0x35 is '/', 0x1E is 'a', 0x33 is ',' -- '>' is
shift+'.' and '<' is shift+',' on a real US keyboard, scancodeUpper's
own mapping for those two indices, the same way scancodeMakeSeven is
shifted into '&' and scancodeMakeBackslash into '|' above). */
#define scancodeMakeD 0x20
#define scancodeMakeW 0x11
#define scancodeMakeM 0x32
#define scancodeMakeX 0x2D
#define scancodeMakeDot 0x34
#define scancodeMakeSlash 0x35
#define scancodeMakeA 0x1E
#define scancodeMakeComma 0x33
static void redirTypePath(void)
{
injectKeyPress(scancodeMakeSlash);
injectKeyPress(scancodeMakeT);
injectKeyPress(scancodeMakeM);
injectKeyPress(scancodeMakeP);
injectKeyPress(scancodeMakeSlash);
injectKeyPress(scancodeMakeR);
injectKeyPress(scancodeMakeE);
injectKeyPress(scancodeMakeD);
injectKeyPress(scancodeMakeI);
injectKeyPress(scancodeMakeR);
injectKeyPress(scancodeMakeDot);
injectKeyPress(scancodeMakeT);
injectKeyPress(scancodeMakeX);
injectKeyPress(scancodeMakeT);
}
static void redirTypeWriterName(void)
{
injectKeyPress(scancodeMakeR);
injectKeyPress(scancodeMakeE);
injectKeyPress(scancodeMakeD);
injectKeyPress(scancodeMakeI);
injectKeyPress(scancodeMakeR);
injectKeyPress(scancodeMakeW);
injectKeyPress(scancodeMakeR);
injectKeyPress(scancodeMakeI);
injectKeyPress(scancodeMakeT);
injectKeyPress(scancodeMakeE);
injectKeyPress(scancodeMakeR);
}
static void redirTypeReaderName(void)
{
injectKeyPress(scancodeMakeR);
injectKeyPress(scancodeMakeE);
injectKeyPress(scancodeMakeD);
injectKeyPress(scancodeMakeI);
injectKeyPress(scancodeMakeR);
injectKeyPress(scancodeMakeR);
injectKeyPress(scancodeMakeE);
injectKeyPress(scancodeMakeA);
injectKeyPress(scancodeMakeD);
injectKeyPress(scancodeMakeE);
injectKeyPress(scancodeMakeR);
}
static void redirTypeWriteTruncateCommand(void)
{
redirTypeWriterName();
injectKeyPress(scancodeMakeSpace);
injectShiftedKeyPress(scancodeMakeDot);
injectKeyPress(scancodeMakeSpace);
redirTypePath();
injectKeyPress(scancodeMakeEnter);
}
static void redirTypeWriteAppendCommand(void)
{
redirTypeWriterName();
injectKeyPress(scancodeMakeSpace);
injectShiftedKeyPress(scancodeMakeDot);
injectShiftedKeyPress(scancodeMakeDot);
injectKeyPress(scancodeMakeSpace);
redirTypePath();
injectKeyPress(scancodeMakeEnter);
}
static void redirTypeReadCommand(void)
{
redirTypeReaderName();
injectKeyPress(scancodeMakeSpace);
injectShiftedKeyPress(scancodeMakeComma);
injectKeyPress(scancodeMakeSpace);
redirTypePath();
injectKeyPress(scancodeMakeEnter);
}
#define redirDriverInitialDelayMs 3600
#define redirDriverStepSettleMs 300
/*
* The live ring-3 proof for shell.c's new `cmd < IN` / `cmd > OUT` /
* `cmd >> OUT` file redirection (jobctlApplyRedirects/
* jobctlSpawnForegroundRedirected, jobctl.h): types three commands, one at
* a time, at the real interactive shell through the same injected-
* keystroke mechanism jobctlDriverThread/pipelineDriverThread above
* already use -- redirDriverInitialDelayMs gives pipelineDriverThread's
* own total ~3000ms budget (2500ms initial + 500ms settle) a comfortable
* margin before this thread ever touches the same shared keyboard buffer.
*
* Unlike pipelineDriverThread's single typed line, this is THREE separate
* commands, each one run to completion in the FOREGROUND (the shell
* genuinely blocks inside jobctlWaitForeground for each), so
* redirDriverStepSettleMs between them is not just cosmetic pacing --
* typing the next command's keystrokes while the shell is still mid-line
* on the previous one would queue them in the same 32-byte console-reader
* ring buffer (keyboard.c) that a real user's own typing shares, with no
* guarantee they would not overflow it or be echoed against the wrong
* still-open line. Each settle is comfortably longer than
* redirwriter/redirreader's own trivial one-shot work (a single write or
* read-to-EOF, neither ever sleeps or blocks on a timer) needs to spawn,
* run, exit, and be reaped, the same safety margin philosophy every
* other injected multi-step demo above already uses.
*
* "redirwriter > /tmp/redir.txt" (create/truncate) followed by
* "redirwriter >> /tmp/redir.txt" (append, same path) leaves a real tmpfs
* file holding two back-to-back copies of redirwriter.c's own payload;
* "redirreader < /tmp/redir.txt" then reads that file back through a
}
void kmain(uint32 magic, uint64 multibootInfo)