morca · API

orca.proc

Starting processes: what the scheduler needs to run pipeline binaries.

spawn forks and executes a binary without waiting for it, its output appended to a log file if one is given; reap collects the ones that ended, with what wait4 says they used (orca.usage). capture runs a command to the end, killing it past a timeout, and returns what it printed; Capture is the same started without waiting, for the scheduler to check on from tick to tick. Everything a child needs is prepared before fork, so the child calls only write (into a run's cgroup, on a descriptor the parent opened), setpgid, fopen, dup2, setenv, setpriority, fwrite (Linux), execv (or execvp) and _exit.

Structs

Reaped

struct Reaped

A child that ended, as reap collects it.

Implements Copyable, ImplicitlyCopyable, Movable

Fields
pid: Int
code: Int: Its exit code; 128 + the signal if a signal killed it.
max_rss: Int: wait4's ru_maxrss in bytes: the largest resident set of it or of a descendant it waited for, one process's, not their sum.
cpu_seconds: Float64: Its user and system CPU seconds, with its waited-for descendants'.

Capture

struct Capture

A command started with its standard output going to a file of its own, to be read when it ends (capture waits; the scheduler checks on it from tick to tick). It leads a process group of its own, so killing it kills what it started too.

Implements Copyable, Movable

Fields
pid: Int
path: String
what: String: The command, for messages.
started: Int: When it started, on the monotonic clock in nanoseconds.
code: Int: Its exit code once it has ended, else -1.

start

def start(argv: List[String]) -> Self

Starts argv (argv[0] looked up on PATH), its stdout to a new file under TMPDIR, its stderr shared with this process.

seconds

def seconds(self) -> Float64

How long it has been going.

ended

def ended(mut self) -> Bool

Whether it has ended, waiting for it if it has (not if the scheduler's reap got to it first, which sets code).

kill

def kill(mut self)

Kills it and what it started, and forgets its output.

output

def output(mut self) -> String

What it printed, once it has ended; the file is removed.

timed_out

def timed_out(self, limit: Float64) -> Error

Functions

spawn

def spawn(argv: List[String], log: String = "", env: List[String] = List(), nice: Int = Int(0), group: Bool = False, first_to_go: Bool = False, cgroup: String = "") -> Int

Starts argv[0] (a path) with arguments argv, and returns its pid. Its stdout and stderr are appended to log, if given, else shared with this process. env's NAME=VALUEs are added to its environment only, so they're on no command line; nice lowers its CPU priority; group makes it lead a process group of its own, which kill(-pid) ends whole; first_to_go, on Linux, makes it (and what it forks) the first the kernel kills when memory runs out (oom_score_adj 1000). cgroup, a cgroup v2 directory (orca.cgroup), is where it goes before it execs: the parent opens its cgroup.procs (close-on-exec) and the child writes 0 to it, its first act and an async-signal-safe one, so all it runs and starts is in the cgroup.

reap

def reap() -> List[Reaped]

The children that ended, without waiting, with what wait4 says they used.

binary_seconds

def binary_seconds() -> Float64

ORCA_BINARY_SECONDS (default 300): how long a pipeline binary's describe, sense or keys may take before it's killed.

capture

def capture(argv: List[String], timeout: Float64 = Float64("0")) -> Tuple[Int, String]

Runs argv to the end and returns its exit code and standard output. With a timeout (seconds), a command still going then is killed, with what it started, and this raises saying so.

absolute

def absolute(path: String) -> String

path, made absolute against the working directory.