@std/process.ms#
Import each required symbol with import Name from "@std/process.ms".
CommandError Alternative#
Errors returned when a process cannot start, times out, or exceeds an output bound.
type CommandError:
case InvalidInput
case Unavailable
case Timeout
case OutputLimit
case Failed(message: String)impl Error for CommandError:
fn message() -> String:CommandError.Failed#
The command could not be started or run for another reason reported by the host.
case Failed(message: String)CommandError.InvalidInput#
The program name is empty, or the program, an argument, or a limit holds a NUL byte or is negative.
case InvalidInputCommandError.OutputLimit#
The combined standard output and error exceeded max_output_bytes, and the command was killed.
case OutputLimitCommandError.Timeout#
The command was still running when timeout elapsed, and its process group was killed.
case TimeoutCommandError.Unavailable#
The program could not be found or executed, such as a missing executable.
case UnavailableCommandError.Failed.message#
Host-provided failure text; message() returns it verbatim, so it can name paths.
message: StringCommandError.Error.message#
Returns the Failed text verbatim, and otherwise the fixed diagnostic command: <reason>, such as command: operation timed out.
fn message() -> String:CommandOutput Record#
Captured exit status and standard output/error from a completed command.
type CommandOutput:
exit_code: Int
stdout: Bytes
stderr: BytesCommandOutput.exit_code#
The child’s exit status; 0 conventionally means success. A nonzero status is still an Ok result, and a child ended by a signal reports -1 on Unix.
exit_code: IntCommandOutput.stderr#
Everything the child wrote to standard error, as raw bytes that may not be valid UTF-8.
stderr: BytesCommandOutput.stdout#
Everything the child wrote to standard output, as raw bytes that may not be valid UTF-8.
stdout: BytesCommands Interface#
Runs child programs with empty input by default, optional output bounds and timeout.
interface Commands:
fn run(program: String, arguments: List[String], input: Bytes = "".to_bytes(), max_output_bytes: Optional[Int] = none, timeout: Optional[Duration] = none) -> Result[CommandOutput, CommandError]
fn spawn(program: String, arguments: List[String]) -> Result[Subprocess, CommandError]Commands.run#
Starts program directly, without a shell, searching the PATH, and waits for it to finish. arguments are passed after the program name, input is written to its standard input, and its output is captured.
Output beyond max_output_bytes in total across both streams returns OutputLimit, timeout returns Timeout, and in both cases the child’s process group is killed. Cancelling the calling task also kills it.
fn run(program: String, arguments: List[String], input: Bytes = "".to_bytes(), max_output_bytes: Optional[Int] = none, timeout: Optional[Duration] = none) -> Result[CommandOutput, CommandError]Commands.spawn#
Starts program directly, without a shell, searching the PATH, and returns a live Subprocess for use with with. arguments follow the program name; stdin, stdout, and stderr are OS pipes. Returns InvalidInput, Unavailable, or Failed when it cannot start. Closing the Subprocess, or cancelling the acquiring execution, kills the child’s process group.
fn spawn(program: String, arguments: List[String]) -> Result[Subprocess, CommandError]CpuUsage Record#
Cumulative CPU time consumed by the current process, in integer microseconds.
type CpuUsage:
user_microseconds: Int
system_microseconds: IntCpuUsage.system_microseconds#
Kernel CPU time in microseconds.
system_microseconds: IntCpuUsage.user_microseconds#
User CPU time in microseconds.
user_microseconds: IntMemoryUsage Record#
Memory statistics for the current process; every field is bytes.
type MemoryUsage:
heap_used: Int
heap_total: Int
heap_system: Int
external: Int
resident: IntMemoryUsage.external#
Bytes the runtime obtained from the operating system outside the heap, such as stacks and internal tables.
external: IntMemoryUsage.heap_system#
Bytes of heap memory obtained from the operating system, including idle spans.
heap_system: IntMemoryUsage.heap_total#
Bytes of heap spans currently in use, which is at least heap_used.
heap_total: IntMemoryUsage.heap_used#
Bytes of heap memory occupied by live objects and objects not yet collected.
heap_used: IntMemoryUsage.resident#
Bytes of physical memory the operating system reports as resident for the process.
resident: IntProcessControl Interface#
Process and operating-system controls for the current process.
watch_signals observes signals without claiming them; SIGINT/SIGTERM still cancel the native application.
next() and code following it have no shutdown guarantee. Register with/Closeable cleanup
and finish shutdown work directly in the shielded close call after joining cancelled workers.
interface ProcessControl:
fn monotonic_time() -> Int
fn watch_signals(signals: List[Int], capacity: Optional[Int] = none) -> Result[SignalStream, ProcessError]
fn constrained_memory() -> Result[Int, ProcessError]
fn available_memory() -> Result[Int, ProcessError]
fn title() -> Result[String, ProcessError]
fn set_title(title: String) -> Result[Unit, ProcessError]
fn initialize_groups(username: String, gid: Int) -> Result[Unit, ProcessError]
fn replace(program: String, arguments: List[String], environment: Map[String, String]) -> Result[Unit, ProcessError]
fn info() -> Result[ProcessInfo, ProcessError]
fn memory_usage() -> Result[MemoryUsage, ProcessError]
fn cpu_usage() -> Result[CpuUsage, ProcessError]
fn uptime() -> Result[Duration, ProcessError]
fn environment() -> Result[Map[String, String], ProcessError]
fn set_environment(name: String, value: Optional[String]) -> Result[Unit, ProcessError]
fn load_environment(path: String, max_bytes: Optional[Int] = none) -> Result[Unit, ProcessError]
fn working_directory() -> Result[String, ProcessError]
fn change_directory(path: String) -> Result[Unit, ProcessError]
fn send_signal(pid: Int, signal: Int) -> Result[Unit, ProcessError]
fn groups() -> Result[List[Int], ProcessError]
fn resource_usage() -> Result[ResourceUsage, ProcessError]
fn umask(mask: Int) -> Result[Int, ProcessError]
fn set_identity(kind: String, id: Int) -> Result[Unit, ProcessError]
fn set_groups(groups: List[Int]) -> Result[Unit, ProcessError]ProcessControl.available_memory#
Returns bytes available to new allocations: the host’s available memory, reduced to the remaining headroom when a Linux cgroup memory limit applies.
fn available_memory() -> Result[Int, ProcessError]ProcessControl.change_directory#
Changes the working directory of the whole process, affecting relative paths everywhere. A missing path returns NotFound, a path containing NUL returns InvalidInput, and a denied path returns PermissionDenied.
fn change_directory(path: String) -> Result[Unit, ProcessError]ProcessControl.constrained_memory#
Returns the memory limit in bytes imposed on this process by its Linux cgroup, or 0 when no limit applies or the platform has no such limit.
fn constrained_memory() -> Result[Int, ProcessError]ProcessControl.cpu_usage#
Returns cumulative user and kernel CPU time consumed by this process in microseconds. Platforms without resource accounting return Unsupported.
fn cpu_usage() -> Result[CpuUsage, ProcessError]ProcessControl.environment#
Reads a fresh live process environment map; non-UTF-8 entries return Unsupported.
fn environment() -> Result[Map[String, String], ProcessError]ProcessControl.groups#
Returns the numeric ids of the supplementary groups of the process. Windows returns Unsupported.
fn groups() -> Result[List[Int], ProcessError]ProcessControl.info#
Returns the process id, parent id, executable path, arguments, platform, and real and effective user and group ids. Text that is not valid UTF-8 returns Unsupported.
fn info() -> Result[ProcessInfo, ProcessError]ProcessControl.initialize_groups#
Replaces the supplementary group list with the groups of username from the account database plus gid first. Requires privilege.
A failed user lookup returns Failed, a gid outside 0 through 2147483647 returns InvalidInput, and a lack of privilege returns PermissionDenied.
fn initialize_groups(username: String, gid: Int) -> Result[Unit, ProcessError]ProcessControl.load_environment#
Reads KEY=value lines from the file at path and sets each variable that is not already present in the environment. Existing variables keep their values.
Blank lines, # comments, an export prefix, and single-, double-, or backtick-quoted values spanning lines are accepted. The whole file is validated first, so a malformed or non-UTF-8 file returns InvalidData and changes nothing. A file larger than max_bytes returns LimitExceeded.
fn load_environment(path: String, max_bytes: Optional[Int] = none) -> Result[Unit, ProcessError]ProcessControl.memory_usage#
Returns heap and resident memory statistics for this process, in bytes.
fn memory_usage() -> Result[MemoryUsage, ProcessError]ProcessControl.monotonic_time#
Elapsed nanoseconds since native runtime initialization, sharing the uptime() origin. This is not Unix time or a Clock Instant; prefer clock().now().difference(start) for timing.
fn monotonic_time() -> IntProcessControl.replace#
Replaces the running process image with program using exactly the given arguments as argv, where arguments[0] is the program name, and exactly the given environment. On success it never returns.
program is a path, not a PATH lookup. An empty program, an empty argument list, or NUL bytes return InvalidInput, and exec failures return NotFound, PermissionDenied, or Failed. Unsupported on Windows.
fn replace(program: String, arguments: List[String], environment: Map[String, String]) -> Result[Unit, ProcessError]ProcessControl.resource_usage#
Returns kernel resource counters for this process: CPU times, peak resident size, page faults, block I/O, and context switches. Platforms without them return Unsupported.
fn resource_usage() -> Result[ResourceUsage, ProcessError]ProcessControl.send_signal#
Validates a signed 32-bit PID and signal 0..64; the OS decides supported numbers/permissions. Signal 0 checks existence; Windows positive PIDs support 0 and forced INT/KILL/TERM termination.
fn send_signal(pid: Int, signal: Int) -> Result[Unit, ProcessError]ProcessControl.set_environment#
Sets environment variable name for this process to value, or removes it when value is none.
An empty name, or a name or value with = or NUL, returns InvalidInput. The change is visible to child processes started afterwards.
fn set_environment(name: String, value: Optional[String]) -> Result[Unit, ProcessError]ProcessControl.set_groups#
Replaces the supplementary group list with the given numeric ids, each 0 through 2147483647. Requires privilege. Invalid ids return InvalidInput, a lack of privilege returns PermissionDenied, and Windows returns Unsupported.
fn set_groups(groups: List[Int]) -> Result[Unit, ProcessError]ProcessControl.set_identity#
Accepts exactly uid, gid, euid, or egid and id 0..2147483647; other inputs return InvalidInput. Identity changes require OS permission and are Unsupported on Windows.
fn set_identity(kind: String, id: Int) -> Result[Unit, ProcessError]ProcessControl.set_title#
Sets the process title shown by tools such as ps.
A title with NUL or newline returns InvalidInput, and platforms that cannot rename a process return Unsupported.
fn set_title(title: String) -> Result[Unit, ProcessError]ProcessControl.title#
Returns the current process title. Platforms that cannot read it return Unsupported.
fn title() -> Result[String, ProcessError]ProcessControl.umask#
Sets mask 0..511 (0777) and returns the previous mask; Unsupported on Windows.
fn umask(mask: Int) -> Result[Int, ProcessError]ProcessControl.uptime#
Returns elapsed Duration since runtime initialization, rather than host boot.
fn uptime() -> Result[Duration, ProcessError]ProcessControl.watch_signals#
Observes native signal numbers 1..64, excluding SIGKILL/SIGSTOP; the list must be nonempty. Capacity must be 1..1048576; omission/none uses 128 buffered signals. Numeric validation does not guarantee OS support. Observing does not suppress host cancellation. Code after next() has no shutdown guarantee; use registered with/Closeable cleanup.
fn watch_signals(signals: List[Int], capacity: Optional[Int] = none) -> Result[SignalStream, ProcessError]ProcessControl.working_directory#
Reads the live process directory, preserving OS failures as ProcessError.
fn working_directory() -> Result[String, ProcessError]See the shutdown cookbook for runnable examples and limitations.
ProcessError Alternative#
Errors returned by process-control operations.
type ProcessError:
case InvalidInput
case InvalidData
case LimitExceeded
case NotFound
case AlreadyExists
case PermissionDenied
case Unsupported
case Closed
case Failed(message: String)impl Error for ProcessError:
fn message() -> String:ProcessError.AlreadyExists#
The host reported that the target already exists.
case AlreadyExistsProcessError.Closed#
A signal stream was closed while waiting or before the call.
case ClosedProcessError.Failed#
The host reported another failure while performing the operation.
case Failed(message: String)ProcessError.InvalidData#
Host data or file content was malformed, such as an environment file that does not parse or is not valid UTF-8.
case InvalidDataProcessError.InvalidInput#
An argument is outside its documented range or contains NUL, such as an invalid signal number, id, mask, capacity, or environment name.
case InvalidInputProcessError.LimitExceeded#
An environment file is larger than max_bytes.
case LimitExceededProcessError.NotFound#
The host reported that a path or user does not exist.
case NotFoundProcessError.PermissionDenied#
The host refused the operation for lack of privilege.
case PermissionDeniedProcessError.Unsupported#
The platform does not provide the operation, or a value is not valid UTF-8.
case UnsupportedProcessError.Failed.message#
Host-provided failure text; message() returns it verbatim, so it can name paths.
message: StringProcessError.Error.message#
Returns the Failed text verbatim, and otherwise the fixed diagnostic process: <reason>.
fn message() -> String:ProcessInfo Record#
Identity and invocation details for the current process.
type ProcessInfo:
pid: Int
parent_pid: Int
executable: String
arguments: List[String]
os: String
architecture: String
uid: Int
gid: Int
effective_uid: Int
effective_gid: IntProcessInfo.architecture#
Processor architecture in Go’s naming, such as amd64 or arm64.
architecture: StringProcessInfo.arguments#
Live native argv including argv[0]; cli.arguments() is the supplied startup tail without it.
arguments: List[String]ProcessInfo.effective_gid#
Effective group id used for permission checks; -1 on Windows.
effective_gid: IntProcessInfo.effective_uid#
Effective user id used for permission checks; -1 on Windows.
effective_uid: IntProcessInfo.executable#
Absolute path of the running program file.
executable: StringProcessInfo.gid#
Real group id; -1 on Windows, where ids are not numeric.
gid: IntProcessInfo.os#
Operating system name in Go’s naming, such as linux, darwin, or windows.
os: StringProcessInfo.parent_pid#
Operating system id of the parent process at the time of the call.
parent_pid: IntProcessInfo.pid#
Operating system id of this process.
pid: IntProcessInfo.uid#
Real user id; -1 on Windows, where ids are not numeric.
uid: IntResourceUsage Record#
Kernel resource counters for the current process. CPU times are integer microseconds; max_resident_bytes is bytes; other fields are counts, not durations or byte totals. Filesystem reads/writes count native block I/O on Unix and I/O operations on Windows. Unavailable Windows fault/context-switch counters are zero.
type ResourceUsage:
user_microseconds: Int
system_microseconds: Int
max_resident_bytes: Int
minor_faults: Int
major_faults: Int
filesystem_reads: Int
filesystem_writes: Int
voluntary_switches: Int
involuntary_switches: IntResourceUsage.filesystem_reads#
Block input operations charged to the process, as a count.
filesystem_reads: IntResourceUsage.filesystem_writes#
Block output operations charged to the process, as a count.
filesystem_writes: IntResourceUsage.involuntary_switches#
Context switches where the scheduler preempted the process, as a count.
involuntary_switches: IntResourceUsage.major_faults#
Page faults that required disk I/O, as a count.
major_faults: IntResourceUsage.max_resident_bytes#
Peak physical memory the process has held at once, in bytes.
max_resident_bytes: IntResourceUsage.minor_faults#
Page faults served without disk I/O, as a count.
minor_faults: IntResourceUsage.system_microseconds#
Cumulative CPU time the kernel spent on behalf of this process, in microseconds.
system_microseconds: IntResourceUsage.user_microseconds#
Cumulative CPU time spent running this process’s own code, in microseconds.
user_microseconds: IntResourceUsage.voluntary_switches#
Context switches where the process gave up the CPU, such as to wait for I/O, as a count.
voluntary_switches: IntSignalStream Interface#
A cancellable observer of operating-system signals selected by watch_signals.
SIGINT/SIGTERM still cancel the native application; close() unregisters this observer.
next() and following code have no shutdown guarantee; use registered with/Closeable cleanup.
interface SignalStream:
fn close() -> Unit
fn next() -> Result[Int, ProcessError]SignalStream.close#
Stops observing signals, wakes a pending next with Closed, and waits for it.
Safe to call repeatedly.
fn close() -> UnitSignalStream.next#
Waits for the next observed signal and returns its number. Signals arriving while no call waits are buffered up to the stream’s capacity.
Returns Closed after close. Cancelling the waiting task unwinds it.
fn next() -> Result[Int, ProcessError]See the shutdown cookbook for runnable examples and limitations.
Subprocess Interface#
A long-lived child process with live stdin, stdout, and stderr pipes. Closing it kills the child’s process group, joins it, and closes all three streams.
interface Subprocess:
fn stdin() -> WriteStream
fn stdout() -> ReadStream
fn stderr() -> ReadStream
fn wait(timeout: Optional[Duration] = none) -> Result[Int, CommandError]
fn terminate() -> Unit
fn kill() -> Unit
fn close() -> UnitSubprocess.close#
Kills the process group, joins the child, kills leftover group members, and closes all three streams. Idempotent; with calls it on scope exit.
fn close() -> UnitSubprocess.kill#
Sends SIGKILL to the child’s process group. Does not wait.
fn kill() -> UnitSubprocess.stderr#
The child’s standard error as a ReadStream over the OS pipe, with the same blocking and backpressure behavior as stdout.
fn stderr() -> ReadStreamSubprocess.stdin#
The child’s standard input as a WriteStream; writes block when the pipe is full. Closing the stream delivers end-of-input to the child.
fn stdin() -> WriteStreamSubprocess.stdout#
The child’s standard output as a ReadStream over the OS pipe; reads block until output or end-of-file, and nothing is buffered without bound.
fn stdout() -> ReadStreamSubprocess.terminate#
Sends SIGTERM to the child’s process group on Unix; Windows has no SIGTERM, so it kills the direct process. Does not wait.
fn terminate() -> UnitSubprocess.wait#
Waits for the child to exit and returns its exit status. Returns Timeout if timeout elapses first, leaving the child running.
fn wait(timeout: Optional[Duration] = none) -> Result[Int, CommandError]commands Function#
Returns child-process operations for the current host.
fn commands() -> Commands:control Function#
Returns controls and process information for the current process.
fn control() -> ProcessControl: