proc

package
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 7, 2026 License: Apache-2.0 Imports: 19 Imported by: 0

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

View Source
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
)
View Source
const (
	MemoryInfoFile  = "meminfo"
	MemoryTotal     = "MemTotal:"
	MemoryAvailable = "MemAvailable:"
)

The kernel's memory accounting in the process table, one "Key: N kB" line per measure.

Variables

View Source
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")
)
View Source
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")
)
View Source
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

func MemoryField(meminfo string, key string) uint64

MemoryField is one "Key: N kB" line of meminfo content, in bytes, or zero when the line is absent.

func ReadMemoryAvailable

func ReadMemoryAvailable(processes iofs.IFiles) (uint64, error)

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.

func (*ExitError) Error

func (exitError *ExitError) Error() string

Error names the program, its status and, when captured, its diagnostics.

func (*ExitError) Unwrap

func (exitError *ExitError) Unwrap() error

Unwrap exposes the operating system's report.

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

func (launcher *HostLauncher) Run(ctx context.Context, command Command) (Result, error)

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.

func (*HostLauncher) Start

func (launcher *HostLauncher) Start(ctx context.Context, command Command) (*Process, error)

Start launches command. The returned process must be waited for; the context bounds it exactly as it bounds Run, so a child meant to outlive a request is started with a context that does not end with the request.

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.

func (*HostPressure) Wait

func (pressure *HostPressure) Wait(ctx context.Context) error

Wait blocks in poll(2) until the kernel raises POLLPRI, ctx ends or the file fails.

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

func ParsePressure(text string) (Pressure, error)

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

type PressureLine struct {
	Avg10  float64
	Avg60  float64
	Avg300 float64
	Total  time.Duration
}

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

func (process *Process) Kill() error

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

func (process *Process) Pid() int

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

func (process *Process) Signal(signal os.Signal) error

Signal delivers signal to the child alone, the way an interrupt asks a program to run its own shutdown.

func (*Process) Stdout

func (process *Process) Stdout() io.Reader

Stdout is standard output when the command asked for StdoutPipe, else nil. Read it to the end before Wait.

func (*Process) Terminal

func (process *Process) Terminal() *os.File

Terminal is the controlling side of a terminal command's pseudo-terminal, else nil. The process owns it: Wait closes it.

func (*Process) Wait

func (process *Process) Wait() (Result, error)

Wait blocks until the child exits, reaps it and returns its result, with the same error semantics as HostLauncher.Run.

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

type TerminalSize struct {
	Rows    uint16
	Columns uint16
}

TerminalSize is a pseudo-terminal window in character cells.

Directories

Path Synopsis
Package mocks is a generated GoMock package.
Package mocks is a generated GoMock package.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL