std/process
External-process invocation, async-first.
spawn_async is the primitive: a non-blocking awaitable over a child
process. spawn_start launches the child, the awaitable polls
it to completion on the cooperative scheduler (spawn_poll, re-arming a
short timer between polls: the same timer-driven suspension std/async's
sleep uses), then interns the captured pipes (spawn_take_stdout/_stderr).
Launching N children and joining them with std/async::join_all runs them
concurrently: the OS schedules the child processes across cores.
Blocking spawn is block_on(spawn_async(...)): one mechanism, cross-
platform (the child primitives have a POSIX and a Win32 body).
run_attached is the other shape: the child shares this process's standard
streams instead of having them captured, and the call blocks until it exits.
Native-only in MVP: the child primitives sit on posix_spawn + pipes (POSIX)
and CreateProcessA + pipes (Windows). WASM has no spawn equivalent.
Types
ProcessError :: struct Error from spawn / spawn_async when the child can't be launched or
terminates abnormally (a non-zero exit is NOT an error: it rides in
ProcessResult.exit).
Fields
msg: string stdout: string = "" What the child wrote to stdout before a signal ended it ; empty when it never ran.
stderr: string = "" What the child wrote to stderr before a signal ended it (a panic's message, say) ; empty when it never ran.
ProcessResult :: struct Outcome of a child that ran to completion. exit is the OS exit status ;
stdout / stderr hold the full captured pipe contents.
Fields
exit: i32 stdout: string stderr: string Functions
processor_count :: fn() -> i32 Number of logical processors online: what a caller sizes a parallel fan-out on. At least 1: a platform that cannot tell answers 1.
Returns
i32 spawn_start :: fn(argv: string[]) -> i64 Launch argv without waiting ; returns a handle into the child table, or a
negative value on launch failure. Pipes for stdout/stderr are captured and
drained by spawn_poll.
Parameters
| argv | string[] | No description. |
Returns
i64 spawn_poll :: fn(handle: i64) -> i32 Advance a launched child WITHOUT blocking: drain its pipes and reap if it
exited. Returns RUNNING while alive, SIGNALED on abnormal termination,
else the exit code (>= 0).
Parameters
| handle | i64 | No description. |
Returns
i32 spawn_kill :: fn(handle: i64) -> void Terminate a spawned child and reap it, freeing its slot.
For a caller that has given up: a timeout fired, and without this the child keeps running after its parent stopped caring, holding a core and its table slot. SIGKILL rather than a polite signal: this is the path for code that is not responding. Idempotent: killing a finished or unknown handle does nothing, since a caller cannot know which it holds.
Parameters
| handle | i64 | the handle spawn_start returned. |
spawn_take_stdout :: fn(handle: i64) -> string Intern the child's captured stdout (call after spawn_poll reports done).
Parameters
| handle | i64 | No description. |
Returns
string spawn_take_stderr :: fn(handle: i64) -> string Intern the child's captured stderr AND release the child slot: the last call for a handle. Take order is stdout then stderr.
Parameters
| handle | i64 | No description. |
Returns
string spawn_finished :: fn(handle: i64, program: string) -> ProcessResult | ProcessError | null What a child spawn_start launched came to, WITHOUT waiting: null while it
runs, then its ProcessResult, or a ProcessError when a signal stopped
it. For a caller with an event loop of its own, polling between two events;
once it answers, the handle is spent.
Parameters
| handle | i64 | the handle spawn_start returned. |
| program | string | the program it runs, which names it in a ProcessError. |
Returns
ProcessResult | ProcessError | null null while the child runs, its result once it exited.Errors
ProcessErrorwhen a signal terminated it.
spawn_async :: fn(argv: string[]) -> Async<ProcessResult | ProcessError> Run argv[0] with argv[1..] as an awaitable: launches immediately, then
completes once the child exits, WITHOUT blocking the scheduler. Fan several
out and await join_all([...]) to run them concurrently (the OS parallelises the
child processes). The WASM targets have no subprocess support (unbound).
Parameters
| argv | string[] | the command line ; argv[0] is the program. Empty is an error. |
Returns
Async<ProcessResult | ProcessError> an awaitable completing with the ProcessResult.Errors
ProcessErroron launch failure, a killing signal, or emptyargv.
spawn :: fn(argv: string[]) -> ProcessResult | ProcessError Run argv[0] with argv[1..], BLOCK until exit, and return the exit code
plus captured stdout/stderr. A block_on over spawn_async: prefer
spawn_async when you need concurrency.
Parameters
| argv | string[] | the command line ; argv[0] is the program. Empty is an error. |
Returns
ProcessResult | ProcessError a ProcessResult with the exit code + drained pipes.Errors
ProcessErroron launch failure, a killing signal, or emptyargv.
run_attached :: fn(argv: string[]) -> i32 | ProcessError Run argv[0] with argv[1..] on this process's standard streams, and wait
for it to exit: the child reads what this process would read and writes
where it writes, a terminal or a pipe, with nothing captured.
For a program run on the user's behalf, whose output belongs on the screen as it is written. Blocking: the scheduler does not run meanwhile.
Parameters
| argv | string[] | the command line; argv[0] is the program, looked up on PATH when it names no folder. |
Returns
i32 | ProcessError the child's exit code.Errors
ProcessErrorwhenargvis empty, the program cannot be launched, or a signal (an exception, on Windows) ended it.