# orca.proc

> A module of morca's API.

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`

```mojo
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`

```mojo
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`

```mojo
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`

```mojo
def seconds(self) -> Float64
```

How long it has been going.

#### `ended`

```mojo
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`

```mojo
def kill(mut self)
```

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

#### `output`

```mojo
def output(mut self) -> String
```

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

#### `timed_out`

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

## Functions

### `spawn`

```mojo
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=VALUE`s 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`

```mojo
def reap() -> List[Reaped]
```

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

### `binary_seconds`

```mojo
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`

```mojo
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`

```mojo
def absolute(path: String) -> String
```

`path`, made absolute against the working directory.
