Documentation
¶
Overview ¶
Package proc is the process boundary: the one subprocess gateway in CSF. Starting another program crosses into another address space through fork and exec, so it happens only through a capability granted by the binary that owns the process, and this is the only package in candace/ that imports os/exec.
A binary constructs one HostLauncher and passes it, as an ILauncher, to whatever needs to run a program; a service receives the capability in its constructor and never builds an exec.Cmd itself. The gateway owns the whole life of a child:
- launch: an argument vector, never a shell string, in an explicit directory and environment;
- input and output: caller-supplied readers and writers, or captured output returned as a structured Result;
- cancellation: the context passed to HostLauncher.Run or HostLauncher.Start bounds the child, and canceling it kills the child's whole process group, so a shell's own children die with it;
- waiting and cleanup: HostLauncher.Run always reaps its child, and a started Process is reaped by Process.Wait, so no child is left a zombie.
The package starts no goroutines of its own. The copying goroutines os/exec runs for non-file writers, and the one that watches a context, are owned by the call: they start in Run or Start and are joined by the Wait that completes it.
Index ¶
- Constants
- Variables
- func MemoryField(meminfo string, key string) uint64
- func ReadMemoryAvailable(processes iofs.IFiles) (uint64, error)
- func WatchPressure(ctx context.Context, resource PressureResource, trigger PressureTrigger) (<-chan struct{}, error)
- func WatchPressureSource(ctx context.Context, source IPressureSource, trigger PressureTrigger) (<-chan struct{}, error)
- type Command
- type ExitError
- type HostLauncher
- type HostLauncherOption
- type HostPressure
- type ILauncher
- type IPressureSource
- type Pressure
- type PressureKind
- type PressureLine
- type PressureResource
- type PressureTrigger
- type Process
- func (process *Process) Kill() error
- func (process *Process) Pid() int
- func (process *Process) Resize(size TerminalSize) error
- func (process *Process) Signal(signal os.Signal) error
- func (process *Process) Stdout() io.Reader
- func (process *Process) Terminal() *os.File
- func (process *Process) Wait() (Result, error)
- type Result
- type TerminalSize
Constants ¶
const ( // DefaultWaitDelay bounds how long Wait keeps reading a canceled child's // output pipes after the kill: a grandchild that escaped the group must // not hold the caller forever. DefaultWaitDelay = 5 * time.Second // DefaultDiagnosticBytes bounds captured standard error. DefaultDiagnosticBytes = 64 << 10 )
const ( MemoryInfoFile = "meminfo" MemoryTotal = "MemTotal:" MemoryAvailable = "MemAvailable:" )
The kernel's memory accounting in the process table, one "Key: N kB" line per measure.
Variables ¶
var ( // ErrTerminalRun is returned when a terminal is requested from Run: an // interactive terminal belongs to a started [Process]. ErrTerminalRun = errors.New("ipc/proc: a terminal command must be started, not run") // ErrStreamConflict is returned for a command whose stream fields // contradict each other. ErrStreamConflict = errors.New("ipc/proc: conflicting standard stream configuration") // ErrExecutableRequired is returned for a command with no executable. ErrExecutableRequired = errors.New("ipc/proc: executable is required") // ErrInvalidOption is returned by NewHostLauncher for a nil or // out-of-range option. ErrInvalidOption = errors.New("ipc/proc: invalid launcher option") // ErrNoTerminal is returned by Resize on a process started without one. ErrNoTerminal = errors.New("ipc/proc: process has no terminal") )
var ( // ErrUnknownPressure reports a resource the kernel has no pressure file for. ErrUnknownPressure = errors.New("ipc/proc: unknown pressure resource") // ErrPressureFormat reports a pressure file this parser cannot read. ErrPressureFormat = errors.New("ipc/proc: unreadable pressure file") // ErrInvalidTrigger reports a trigger outside the kernel's bounds, or one // the kernel refused. ErrInvalidTrigger = errors.New("ipc/proc: invalid pressure trigger") )
var ErrPressureClosed = errors.New("ipc/proc: pressure file failed")
ErrPressureClosed reports a wait on a pressure file the kernel closed or failed.
Functions ¶
func MemoryField ¶
MemoryField is one "Key: N kB" line of meminfo content, in bytes, or zero when the line is absent.
func ReadMemoryAvailable ¶
ReadMemoryAvailable is the memory the kernel estimates is available for a new workload without swapping, read from the granted process table.
func WatchPressure ¶
func WatchPressure(ctx context.Context, resource PressureResource, trigger PressureTrigger) (<-chan struct{}, error)
WatchPressure opens the host's pressure file for resource and watches it with trigger, as WatchPressureSource does. It needs no privilege beyond the kernel's limit on an unprivileged trigger's window.
func WatchPressureSource ¶
func WatchPressureSource(ctx context.Context, source IPressureSource, trigger PressureTrigger) (<-chan struct{}, error)
WatchPressureSource arms trigger on source and delivers one value per event the kernel raises, dropping an event while the previous one is undelivered. The channel closes, and source is closed, when ctx ends or the source fails; the caller reads the reading it wants with ReadPressure.
Types ¶
type Command ¶
type Command struct {
// Executable is a path, or a name resolved on PATH.
Executable string
// Arguments follow the executable in the argument vector.
Arguments []string
// Directory is the working directory; empty means the caller's.
Directory string
// Environment replaces the inherited environment when non-nil.
Environment []string
// ExtraEnvironment is appended to the environment the child receives,
// inherited or replaced, so a caller adds a variable without reading the
// process environment itself.
ExtraEnvironment []string
// Stdin is the child's standard input; nil means none.
Stdin io.Reader
// Stdout receives standard output. When nil it is captured into
// [Result.Stdout] (unbounded, like exec.Cmd.Output), unless StdoutPipe
// is set on a started process.
Stdout io.Writer
// Stderr receives standard error. When nil it is captured, bounded by the
// launcher's diagnostic limit, into [Result.Stderr] and [ExitError],
// whose message then carries it. A caller whose child's diagnostics may
// hold secrets passes io.Discard to keep them out of every error.
Stderr io.Writer
// StdoutPipe exposes standard output as [Process.Stdout] on a started
// process. Read it to the end before Wait.
StdoutPipe bool
// Terminal attaches the child to a new pseudo-terminal of this size, in
// its own session. Stdin, Stdout and Stderr must be nil: the terminal is
// all three, read and written through [Process.Terminal].
Terminal *TerminalSize
}
Command is one program invocation.
type ExitError ¶
type ExitError struct {
Executable string
Code int
Stderr []byte
// contains filtered or unexported fields
}
ExitError reports a child that ran and exited unsuccessfully.
type HostLauncher ¶
type HostLauncher struct {
// contains filtered or unexported fields
}
HostLauncher is this host's process table, granted as a capability.
func NewHostLauncher ¶
func NewHostLauncher(options ...HostLauncherOption) (*HostLauncher, error)
NewHostLauncher returns the host's process capability.
func (*HostLauncher) LookPath ¶
func (launcher *HostLauncher) LookPath(name string) (string, error)
LookPath resolves name on PATH.
func (*HostLauncher) Run ¶
Run starts command, waits for it, and returns its result. A child that exits unsuccessfully returns an *ExitError; a canceled context kills the child's process group and returns the context's cause. The result carries whatever output was captured in every case.
type HostLauncherOption ¶
type HostLauncherOption func(launcher *HostLauncher) error
HostLauncherOption configures a HostLauncher.
func WithDiagnosticBytes ¶
func WithDiagnosticBytes(limit int64) HostLauncherOption
WithDiagnosticBytes bounds captured standard error.
func WithWaitDelay ¶
func WithWaitDelay(delay time.Duration) HostLauncherOption
WithWaitDelay bounds how long a canceled child's pipes are drained.
type HostPressure ¶
type HostPressure struct {
// contains filtered or unexported fields
}
HostPressure is the kernel's pressure file for one resource, opened for a trigger, and an eventfd that wakes a Wait when its context ends, so a waiting goroutine blocks in poll(2) with no timeout.
func OpenHostPressure ¶
func OpenHostPressure(resource PressureResource) (*HostPressure, error)
OpenHostPressure opens the kernel's pressure file for resource, read and write, as a trigger needs.
func (*HostPressure) Arm ¶
func (pressure *HostPressure) Arm(trigger string) error
Arm writes the trigger, with its terminating NUL as the kernel asks.
func (*HostPressure) Close ¶
func (pressure *HostPressure) Close() error
Close closes the file, which removes its trigger, and the eventfd.
type ILauncher ¶
type ILauncher interface {
// Run starts command, waits for it and returns its structured result.
Run(ctx context.Context, command Command) (Result, error)
// Start launches command and returns the running process, which the
// caller must Wait for.
Start(ctx context.Context, command Command) (*Process, error)
// LookPath resolves an executable name the way Run would.
LookPath(name string) (string, error)
}
ILauncher runs programs. It is the process-boundary capability.
type IPressureSource ¶
type IPressureSource interface {
// Arm writes the trigger; a refused write is ErrInvalidTrigger.
Arm(trigger string) error
// Wait blocks until the trigger fires, ctx ends (its error), or the
// file fails.
Wait(ctx context.Context) error
Close() error
}
IPressureSource is one opened pressure file a trigger is armed on: the kernel file on the host, a double in a spec.
type Pressure ¶
type Pressure struct {
Some PressureLine
Full PressureLine
}
Pressure is one resource's pressure: some tasks stalled, and all of them. The kernel reports no full line for CPU before 5.13; it then reads zero.
func ParsePressure ¶
ParsePressure reads the text of a pressure file.
func ReadPressure ¶
func ReadPressure(processes iofs.IFiles, resource PressureResource) (Pressure, error)
ReadPressure reads one resource's pressure from the process table granted as /proc.
type PressureKind ¶
type PressureKind string
PressureKind is a pressure line: some tasks stalled, or all of them.
const ( PressureSome PressureKind = "some" PressureFull PressureKind = "full" )
type PressureLine ¶
PressureLine is one line of a pressure file: the stalled share of time, in percent, over the last 10, 60 and 300 seconds, and the total stall.
type PressureResource ¶
type PressureResource string
PressureResource names one of the kernel's pressure stall files.
const ( PressureCPU PressureResource = "cpu" PressureMemory PressureResource = "memory" PressureIO PressureResource = "io" )
The resources the kernel reports pressure for, under /proc/pressure.
type PressureTrigger ¶
type PressureTrigger struct {
Kind PressureKind
Stall time.Duration
Window time.Duration
}
PressureTrigger is a kernel pressure trigger: an event whenever the kind of stall reaches Stall within any Window.
func (PressureTrigger) String ¶
func (trigger PressureTrigger) String() string
String is the trigger as the kernel reads it: "some 150000 1000000".
func (PressureTrigger) Validate ¶
func (trigger PressureTrigger) Validate() error
Validate refuses a trigger the kernel would: an unknown kind, a window outside 500 ms to 10 s, or a stall that is not positive or exceeds the window. An unprivileged process may also be held to a window that is a multiple of 2 s; the kernel says so when the trigger is armed.
type Process ¶
type Process struct {
// contains filtered or unexported fields
}
Process is one started child. Exactly one goroutine calls Process.Wait; Process.Kill, Process.Signal and Process.Resize may be called from any goroutine before or during that Wait.
func (*Process) Kill ¶
Kill ends the child and everything it started: its process group, and for a terminal every process in its session, including background jobs a shell moved into groups of their own. It does not wait; Wait reaps the child.
func (*Process) Pid ¶
Pid is the child's process identifier; for a terminal it is also the session and process-group identifier.
func (*Process) Resize ¶
func (process *Process) Resize(size TerminalSize) error
Resize changes a terminal command's window size.
func (*Process) Signal ¶
Signal delivers signal to the child alone, the way an interrupt asks a program to run its own shutdown.
func (*Process) Stdout ¶
Stdout is standard output when the command asked for StdoutPipe, else nil. Read it to the end before Wait.
type Result ¶
type Result struct {
// ExitCode is the child's exit status, or -1 if it was killed by a
// signal or never ran.
ExitCode int
// Stdout is captured standard output when Command.Stdout was nil.
Stdout []byte
// Stderr is captured standard error when Command.Stderr was nil.
Stderr []byte
// StderrTruncated reports that captured standard error exceeded the
// diagnostic limit and only its prefix was kept.
StderrTruncated bool
}
Result is what a finished child left behind.
type TerminalSize ¶
TerminalSize is a pseudo-terminal window in character cells.