feat: extend jobctl

This commit is contained in:
dualfroz committed 2026-09-01 19:36:53 +02:00
1 parent 0bdc393f39
commit ed74e6df9b
1 file changed
+84
+84
View File
@@ -146,3 +146,87 @@ bool jobctlRunBackgroundRedirected(const char* path, const char* const* argv, in
const char* errPath, bool errAppend,
uint32* outPid);
/* Generalizes jobctlSpawnPiped for shell.c's new `cmd1 <<< TEXT | cmd2`
pipeline syntax, the same way jobctlSpawnPiped itself generalizes
jobctlSpawnForeground/jobctlRunBackground: spawns `path` with fd 0 wired
to a brand-new here-string pipe (`text` plus a trailing newline, written
and closed by THIS kernel thread before returning, exactly like
jobctlSpawnForegroundHereString below) instead of the console, AND
`stdoutHandle`/`joinPgid` passed straight through to jobctlSpawnPiped so
the spawned process can simultaneously be a pipeline's first stage --
-1/threadInvalidId for either one leaves that side at jobctlSpawnPiped's
own plain defaults (console stdout, new group leader). shell.c's
runPipeline uses this for a pipeline's LEFT stage when it was written
with `<<< TEXT` instead of a plain stdin; every other here-string caller
in this file (jobctlSpawnForegroundHereString/jobctlRunBackgroundHereString
below) is a thin wrapper passing -1/threadInvalidId, matching
jobctlSpawnForeground/jobctlRunBackground's own relationship to
jobctlSpawnPiped. Returns threadInvalidId on the same load/spawn
failures as jobctlSpawnPiped, or if the pipe table itself is exhausted
(vfsPipeCreateHandle, maxPipes slots all in use) -- both leave nothing
spawned. */
uint32 jobctlSpawnPipedHereString(const char* path, const char* const* argv, int argc,
const char* text, int stdoutHandle, uint32 joinPgid);
/* Same as jobctlSpawnForegroundRedirected, but for shell.c's new `NAME
[ARGS] <<< TEXT [> OUT | >> OUT] [2> ERR | 2>> ERR]` here-string syntax
instead of `< IN`: `text` (plus a trailing newline, matching a real
shell's own `<<<` behavior) is fed directly into the child's fd 0
through a real anonymous pipe (jobctlSpawnPipedHereString above) that
THIS kernel thread itself writes and closes -- unlike jobctlApplyRedirects'
inPath, there is no file opened at all, so `outPath`/`errPath` are still
applied exactly as jobctlApplyRedirects already does (fd 0 is simply
pre-wired to the here-string pipe instead of left at the console before
that call runs). The write end is closed (real EOF, not a lingering open
pipe) BEFORE this function ever returns, so by the time the child
actually gets a timeslice to read its own fd 0 it sees exactly `text`
followed by one newline followed by true end-of-file, with no
possibility of racing the shell thread for more data that will never
arrive. Returns threadInvalidId on the same load/spawn/redirect failures
as jobctlSpawnForegroundRedirected, plus a pipe-table-exhaustion failure
(vfsPipeCreateHandle, maxPipes slots all in use) -- both leave nothing
spawned. */
uint32 jobctlSpawnForegroundHereString(const char* path, const char* const* argv, int argc,
const char* text, const char* outPath, bool outAppend,
const char* errPath, bool errAppend);
/* Same as jobctlRunBackgroundRedirected, but with the same here-string
stdin support as jobctlSpawnForegroundHereString above -- shell.c's
`NAME [ARGS] <<< TEXT [> OUT | >> OUT] [2> ERR | 2>> ERR] &`. Returns
false (touching *outPid not at all) on the same load/spawn/redirect/
pipe-exhaustion failures as jobctlSpawnForegroundHereString. */
bool jobctlRunBackgroundHereString(const char* path, const char* const* argv, int argc,
const char* text, const char* outPath, bool outAppend,
const char* errPath, bool errAppend,
uint32* outPid);
/* Runs `path` to completion with its stdout wired to a real pipe THIS
kernel thread reads back as a string -- shell.c's new `$(cmd)` command
substitution, the mirror image of jobctlSpawnForegroundHereString's
"write a fixed string into the child's stdin" above. stdin is left at
its plain default (never redirected), and the terminal is never granted
to the child (unlike every foreground job above) -- command substitution
is not itself "the" foreground job, only a synchronous helper run while
building one. Joins the child FIRST, then drains its captured stdout --
not "read until EOF, then join": this kernel only ever releases a dead
thread's own fds (reclaimOpenFds, sched.c) from inside threadReap
(threadJoin's last step), never at threadExit/threadKill itself, so
reading first would block forever waiting for an end-of-file that only
the very threadJoin call coming after it could ever produce. Joining
first instead means `path`'s own combined stdout must fit within one
pipe buffer's worth (pipeBufferSize, pipe.h) without ever blocking on
free space while it runs -- the same margin jobctlSpawnPipedHereString
already relies on for a here-string write, applied here to a captured
read instead -- an honestly-scoped limit on how chatty a substituted
command may be, not a silent hang for anything that stays under it.
Copies at most outCap-1 captured bytes into outBuf (NUL-terminated,
truncating silently like every other fixed-capacity buffer in this
kernel), draining and discarding anything beyond that rather than
leaving it sitting in the pipe. *outStatus receives the child's real
exit code. Returns false, touching neither outBuf nor *outStatus, on
the same load/spawn/pipe-exhaustion failures as jobctlSpawnPiped/
vfsPipeCreateHandle. */
bool jobctlCaptureOutput(const char* path, const char* const* argv, int argc,
char* outBuf, int outCap, int64* outStatus);
#endif