silk.system.child_process_native.
The native provider of the ChildProcess effect: it runs real programs.
When to use#
Provide OsChildProcess for ChildProcess in a native program. Code that runs programs uses
silk.system.child_process, so a test can provide a fake instead.
Details#
Each call starts the program, waits for it to end, and captures all of its standard output and standard error. Each call owns its own pipes and buffers. An exit code that is not 0, and an end by a signal, are normal outcomes. If a call fails, it releases its resources and waits for the child, so no zombie process stays.
Errors#
ProcessErrorif the child cannot start, the wait fails, or the output cannot be captured.OutOfMemoryErrorif theAllocatorcannot supply the request or the captured output.
Gotchas#
A call blocks the thread until the child ends.
Do not wait for a child of this provider in other code.
A trap in the parent can leave resources open.
On GNU/Linux, if the child cannot start and also cannot report why, the outcome looks like an exit with code 127.
The provider exists only on Darwin on aarch64, and Linux with GNU libc on x86_64 or aarch64.
Examples#
Run echo#
import silk.mem.allocator { Allocator, OutOfMemoryError }
import silk.system.child_process { ChildProcess, ProcessError }
import silk.core.effect { Effect }
import silk.system.filesystem { FileError, Path }
import silk.core.option { Option }
import silk.system.child_process_native { OsChildProcess }
effect fn program() -> i32
! FileError | ProcessError | OutOfMemoryError
? &mut Allocator {
let path = run Path.make("/bin/echo")
let mut request = run ChildProcess.request(&path)
run ChildProcess.addArgument(&mut request, "hi")
let mut provider = OsChildProcess.make()
let outcome = run ChildProcess.submit(&request) |> Effect.provideMut<ChildProcess>(&mut provider)
let code = match ChildProcess.exitCode(&outcome) {
Option<i32>.Some { value } => value
Option<i32>.None => {
return 1
}
}
// echo writes its argument and a newline.
let output = ChildProcess.outputBytes(&outcome)
if code != 0 || output.length != 3 || output[0] != 104 {
return 1
}
return 0
}
effect fn failed<E>(error: E) -> i32 {
drop error
return 1
}
pub fn main() -> i32 {
let mut allocator = Allocator.systemAllocatorProvider()
return run Effect.catchAll(program(), failed) |> Effect.provideMut<Allocator>(&mut allocator)
}Import as OsChildProcess with import silk.system.child_process_native { OsChildProcess }.
Public declarations: 1.
OsChildProcess#
pub struct OsChildProcessThe native ChildProcess provider: it runs real programs. It has no state. Each call owns its
resources.
When to use#
Provide it for ChildProcess in a native program. Code that runs programs uses
silk.system.child_process, so a test can provide a fake instead.
Details#
Each call starts the program, waits for it to end, and captures all of its standard output and standard error. An exit code that is not 0, and an end by a signal, are normal outcomes. If a call fails, it releases its resources and waits for the child, so no zombie process stays.
Gotchas#
A call blocks the thread until the child ends.
Do not wait for a child of this provider in other code.
A trap in the parent can leave resources open.
On GNU/Linux, if the child cannot start and also cannot report why, the outcome looks like an exit with code 127.
Implementation OsChildProcess#
impl OsChildProcessAssociated function make#
pub fn make() -> OsChildProcessReturns a provider. It does not allocate or start a process.
Implementation ChildProcess for OsChildProcess#
impl ChildProcess for OsChildProcessOperation execute#
execute: OsChildProcess.executeCategory: System.
Profiles: aarch64-apple-darwin, aarch64-unknown-linux-gnu, x86_64-unknown-linux-gnu.