Documentation
¶
Overview ¶
Package proc — range 0.2.6.* (ADR 0016 core/proc block). The whole domain owns this single PP octet: every sentinel below is declared here and only wrapped (never re-Defined) by the service implementations and pkg/v1 facades.
Package proc — declares the sentinels returned across the process-supervision domain. Each var's name equals its errs.Define Reason in SCREAMING_SNAKE form; service implementations and pkg/v1 facades wrap these, never re-Define them.
Package proc — the ExitValue value type: the outcome of a finished process.
Package proc — the Group port: a cgroup v2 control group handle.
Package proc — the LimitValue value type: a soft/hard setrlimit pair.
Package proc — the Listener port: the supervisor side of sd_notify.
Package proc — the NotificationValue value type: a parsed sd_notify datagram.
Package proc declares the OS process-supervision contract of the SDK: the ports (Process, Reaper, Group, Listener), the immutable value types (Spec, ExitValue, LimitValue, NotificationValue, Signal, Resource), and the domain's complete error-sentinel set (range 0.2.6.*). It is the sixth internal/core sibling (ADR 0016), peer of codec / writer / crypto / logger / transform.
Unlike codec and crypto, proc ships no plug-in registry: each primitive has a single canonical OS implementation chosen at build time by platform tag, not a runtime-registered scheme. Core declares the ports and value types; concrete behaviour lives in internal/service/proc/*; the pkg/v1 facades (process, signal, reaper, rlimit, cgroup, sdnotify) re-export this surface.
proc is stdlib-only (os, syscall, time, strconv, strings) plus internal/kernel/errs — no golang.org/x/sys — preserving the SDK's dep-light invariant. Every error returned by the domain is one of the sentinels in errors.go; service code wraps them with errs.Wrap and never defines new codes.
Package proc — the Process port: lifetime control over a spawned process.
Package proc — the Reaper port: collection of terminated child processes.
Package proc — the Signal value type: a typed, platform-portable OS signal with Parse / String / OS bridging. The name table is platform-specific and lives in signal_unix.go / signal_other.go.
Package proc — Unix signal name table (linux/darwin/bsd).
Package proc — the Spec value type: an immutable process spawn specification.
Index ¶
Constants ¶
const CodeCgroupCreateFailed errs.Code = 0x00_02_06_10 // 0.2.6.16
CodeCgroupCreateFailed identifies a failure creating a control-group directory under the cgroup v2 hierarchy.
const CodeCgroupDeleteFailed errs.Code = 0x00_02_06_12 // 0.2.6.18
CodeCgroupDeleteFailed identifies a failure removing a control-group directory.
CodeCgroupUnavailable identifies a cgroup operation attempted where cgroup v2 is not mounted or not delegated to the caller.
const CodeCgroupWriteFailed errs.Code = 0x00_02_06_11 // 0.2.6.17
CodeCgroupWriteFailed identifies a failure writing a controller file (memory.max, cpu.max, pids.max, io.max, cgroup.procs).
const CodeCredentialMismatch errs.Code = 0x00_02_06_16 // 0.2.6.22
CodeCredentialMismatch identifies a received datagram whose kernel-verified sender credentials did not match the expected supervised process.
const CodeInvalidNotification errs.Code = 0x00_02_06_15 // 0.2.6.21
CodeInvalidNotification identifies a received sd_notify datagram that could not be parsed into NAME=value fields.
const CodeInvalidSpec errs.Code = 0x00_02_06_02 // 0.2.6.2
CodeInvalidSpec identifies a Start call whose Spec is malformed — an empty Path or a contradictory attribute combination.
const CodeListenFailed errs.Code = 0x00_02_06_14 // 0.2.6.20
CodeListenFailed identifies a failure creating or binding the supervisor-side sd_notify datagram socket.
const CodeNotifyFailed errs.Code = 0x00_02_06_13 // 0.2.6.19
CodeNotifyFailed identifies a failure sending an sd_notify datagram to $NOTIFY_SOCKET (distinct from the no-op when the variable is unset).
const CodeReapFailed errs.Code = 0x00_02_06_0C // 0.2.6.12
CodeReapFailed identifies a wait4 failure during a reap sweep other than the benign "no children" condition.
const CodeRelayFailed errs.Code = 0x00_02_06_0A // 0.2.6.10
CodeRelayFailed identifies a Relay that could not forward a received signal to its target process or group.
const CodeRlimitFailed errs.Code = 0x00_02_06_0E // 0.2.6.14
CodeRlimitFailed identifies a setrlimit(2) failure applying a per-process resource limit.
const CodeSignalFailed errs.Code = 0x00_02_06_07 // 0.2.6.7
CodeSignalFailed identifies a kill(2) failure delivering a signal to a process or process group.
const CodeSpawnFailed errs.Code = 0x00_02_06_05 // 0.2.6.5
CodeSpawnFailed identifies a fork/exec failure when starting the process — a missing binary, a permission denial, or a kernel resource fault.
const CodeStopFailed errs.Code = 0x00_02_06_08 // 0.2.6.8
CodeStopFailed identifies a graceful-stop that could not terminate the process group even after escalating to SIGKILL.
const CodeSubreaperFailed errs.Code = 0x00_02_06_0B // 0.2.6.11
CodeSubreaperFailed identifies a prctl(PR_SET_CHILD_SUBREAPER) failure when arming subreaper semantics for a non-PID1 supervisor.
const CodeUnknownGroup errs.Code = 0x00_02_06_04 // 0.2.6.4
CodeUnknownGroup identifies a Spec naming a Group or supplementary group that does not resolve to a gid on the host.
const CodeUnknownResource errs.Code = 0x00_02_06_0D // 0.2.6.13
CodeUnknownResource identifies an Apply call naming a Resource the platform does not map to an RLIMIT_* constant.
const CodeUnknownSignal errs.Code = 0x00_02_06_09 // 0.2.6.9
CodeUnknownSignal identifies a Parse call whose name or number is not in the platform signal table.
const CodeUnknownUser errs.Code = 0x00_02_06_03 // 0.2.6.3
CodeUnknownUser identifies a Spec naming a User that does not resolve to a uid on the host.
const CodeUnsupportedPlatform errs.Code = 0x00_02_06_01 // 0.2.6.1
CodeUnsupportedPlatform identifies a primitive invoked on an operating system that cannot provide it (e.g. cgroup or subreaper off Linux). The no-op stub returns it instead of panicking.
const CodeWaitFailed errs.Code = 0x00_02_06_06 // 0.2.6.6
CodeWaitFailed identifies a wait4 failure while reaping the leader — a host fault, not a normal non-zero exit (which is reported via ExitValue).
const LimitInfinity uint64 = ^uint64(0)
LimitInfinity is the soft/hard value meaning "no limit" (RLIM_INFINITY). Use it in a LimitValue to lift a resource ceiling rather than setting a number.
Variables ¶
var ( // UnsupportedPlatform is returned by a primitive invoked on an operating // system that cannot provide it; the no-op stub returns it, never a panic. UnsupportedPlatform = errs.Define(CodeUnsupportedPlatform, "UNSUPPORTED_PLATFORM", "This operation is not supported on this platform", "core/proc: primitive unavailable on the current GOOS; the stub returns this instead of acting", errs.WithExitCode(exitUnavailable)) // InvalidSpec is returned by Start when the Spec is malformed — an empty Path // or a contradictory attribute combination. InvalidSpec = errs.Define(CodeInvalidSpec, "INVALID_SPEC", "Process specification is invalid", "service/proc/exec.Start: Spec is malformed (empty Path or contradictory attributes)", errs.WithExitCode(exitUsage)) // UnknownUser is returned when a Spec names a User that does not resolve to a // uid on the host. UnknownUser = errs.Define(CodeUnknownUser, "UNKNOWN_USER", "The requested user does not exist", "service/proc/exec.Start: Spec.User did not resolve to a uid via os/user", errs.WithExitCode(exitNoUser)) // UnknownGroup is returned when a Spec names a Group or supplementary group // that does not resolve to a gid on the host. UnknownGroup = errs.Define(CodeUnknownGroup, "UNKNOWN_GROUP", "The requested group does not exist", "service/proc/exec.Start: Spec.Group/Groups did not resolve to a gid via os/user", errs.WithExitCode(exitNoUser)) // SpawnFailed is returned when fork/exec fails — a missing binary, a // permission denial, or a kernel resource fault. SpawnFailed = errs.Define(CodeSpawnFailed, "SPAWN_FAILED", "Could not start the process", "service/proc/exec.Start: fork/exec failed", errs.WithExitCode(exitOSErr)) // WaitFailed is returned when wait4 fails reaping the leader — a host fault, // not a normal non-zero exit (reported via ExitValue instead). WaitFailed = errs.Define(CodeWaitFailed, "WAIT_FAILED", "Could not wait for the process to exit", "service/proc/exec.Wait: wait4 returned an unexpected error", errs.WithExitCode(exitOSErr)) // SignalFailed is returned when kill(2) fails delivering a signal to a // process or process group. SignalFailed = errs.Define(CodeSignalFailed, "SIGNAL_FAILED", "Could not deliver the signal", "service/proc: kill(2) failed for the target pid or process group", errs.WithExitCode(exitOSErr)) // StopFailed is returned when a graceful stop cannot terminate the process // group even after escalating to SIGKILL. StopFailed = errs.Define(CodeStopFailed, "STOP_FAILED", "Could not stop the process", "service/proc/exec.Stop: process group survived signal escalation to SIGKILL", errs.WithExitCode(exitOSErr)) // UnknownSignal is returned by Parse when the name or number is not in the // platform signal table. UnknownSignal = errs.Define(CodeUnknownSignal, "UNKNOWN_SIGNAL", "Unknown signal name or number", "core/proc.Parse: input is not a signal known on this platform", errs.WithExitCode(exitUsage)) // RelayFailed is returned by Relay when a received signal cannot be forwarded // to its target process or group. RelayFailed = errs.Define(CodeRelayFailed, "RELAY_FAILED", "Could not relay the signal to the target", "service/proc/signal.Relay: forwarding the signal to the target failed", errs.WithExitCode(exitOSErr)) // SubreaperFailed is returned when prctl(PR_SET_CHILD_SUBREAPER) fails arming // subreaper semantics for a non-PID1 supervisor. SubreaperFailed = errs.Define(CodeSubreaperFailed, "SUBREAPER_FAILED", "Could not enable child-subreaper mode", "service/proc/reaper.SetChildSubreaper: prctl(PR_SET_CHILD_SUBREAPER) failed", errs.WithExitCode(exitOSErr)) // ReapFailed is returned when a reap sweep hits a wait4 error other than the // benign "no children" condition. ReapFailed = errs.Define(CodeReapFailed, "REAP_FAILED", "Could not reap child processes", "service/proc/reaper.ReapOnce: wait4 failed with an error other than ECHILD", errs.WithExitCode(exitOSErr)) // UnknownResource is returned by Apply when a Resource has no RLIMIT_* // mapping on the platform. UnknownResource = errs.Define(CodeUnknownResource, "UNKNOWN_RESOURCE", "Unknown or unsupported resource limit", "service/proc/rlimit.Apply: Resource has no RLIMIT_* mapping on this platform", errs.WithExitCode(exitUsage)) // RlimitFailed is returned when setrlimit(2) fails applying a per-process // resource limit. RlimitFailed = errs.Define(CodeRlimitFailed, "RLIMIT_FAILED", "Could not apply the resource limit", "service/proc/rlimit.Apply: setrlimit(2) failed", errs.WithExitCode(exitOSErr)) // is not mounted or not delegated to the caller. CgroupUnavailable = errs.Define(CodeCgroupUnavailable, "CGROUP_UNAVAILABLE", "cgroup v2 is not available or not delegated", "service/proc/cgroup: the unified cgroup v2 hierarchy is absent or not writable by the caller", errs.WithExitCode(exitUnavailable)) // CgroupCreateFailed is returned when a control-group directory cannot be // created under the cgroup v2 hierarchy. CgroupCreateFailed = errs.Define(CodeCgroupCreateFailed, "CGROUP_CREATE_FAILED", "Could not create the control group", "service/proc/cgroup.Create: mkdir under the cgroup v2 hierarchy failed", errs.WithExitCode(exitOSErr)) // CgroupWriteFailed is returned when a controller file cannot be written // (memory.max, cpu.max, pids.max, io.max, cgroup.procs). CgroupWriteFailed = errs.Define(CodeCgroupWriteFailed, "CGROUP_WRITE_FAILED", "Could not write the cgroup controller file", "service/proc/cgroup: writing a controller file failed (controller disabled or value rejected)", errs.WithExitCode(exitOSErr)) // CgroupDeleteFailed is returned when a control-group directory cannot be // removed. CgroupDeleteFailed = errs.Define(CodeCgroupDeleteFailed, "CGROUP_DELETE_FAILED", "Could not delete the control group", "service/proc/cgroup.Delete: rmdir of the control group failed (still populated?)", errs.WithExitCode(exitOSErr)) // NotifyFailed is returned when an sd_notify datagram cannot be sent to // $NOTIFY_SOCKET — distinct from the no-op when the variable is unset. NotifyFailed = errs.Define(CodeNotifyFailed, "NOTIFY_FAILED", "Could not send the sd_notify datagram", "service/proc/sdnotify: writing to $NOTIFY_SOCKET failed", errs.WithExitCode(exitOSErr)) // ListenFailed is returned when the supervisor-side sd_notify datagram socket // cannot be created or bound. ListenFailed = errs.Define(CodeListenFailed, "LISTEN_FAILED", "Could not create the sd_notify listener socket", "service/proc/sdnotify.Listen: creating or binding the AF_UNIX datagram socket failed", errs.WithExitCode(exitOSErr)) // InvalidNotification is returned when a received sd_notify datagram cannot // be parsed into NAME=value fields. InvalidNotification = errs.Define(CodeInvalidNotification, "INVALID_NOTIFICATION", "Received sd_notify datagram is malformed", "service/proc/sdnotify.Recv: datagram did not parse into NAME=value fields", errs.WithExitCode(exitDataErr)) // CredentialMismatch is returned when a received datagram's kernel-verified // sender credentials do not match the expected supervised process. CredentialMismatch = errs.Define(CodeCredentialMismatch, "CREDENTIAL_MISMATCH", "Datagram sender credentials did not match", "service/proc/sdnotify.Recv: SO_PASSCRED sender pid is not the expected supervised process", errs.WithExitCode(exitNoPerm)) )
Functions ¶
This section is empty.
Types ¶
type ExitValue ¶
type ExitValue struct {
// Code is the exit status (0–255) when the process exited normally; it is -1
// when the process was terminated by a signal.
Code int
// Signal is the signal that terminated the process, or the zero Signal when
// it exited normally.
Signal Signal
// Signaled reports whether the process was terminated by a signal rather
// than exiting on its own.
Signaled bool
// UserTime is the CPU time spent in user mode.
UserTime time.Duration
// SystemTime is the CPU time spent in kernel mode on the process's behalf.
SystemTime time.Duration
// MaxRSS is the peak resident set size in kilobytes, as reported by wait4's
// rusage; it is 0 when the platform does not supply it.
MaxRSS int64
}
ExitValue is the immutable outcome of a finished process: its exit status, the signal that terminated it (if any), and resource-usage accounting. It is the value returned by Process.Wait.
type Group ¶
type Group interface {
// SetMemoryMax writes memory.max (systemd MemoryMax=); a negative value
// means "max" (no limit).
SetMemoryMax(bytes int64) error
// SetCPUMax writes cpu.max as "quota period" (systemd CPUQuota=); a negative
// quota means "max".
SetCPUMax(quota, period int64) error
// SetPidsMax writes pids.max (systemd TasksMax=); a negative value means
// "max".
SetPidsMax(n int64) error
// SetIOMax writes one io.max line verbatim (systemd IO*Max=), e.g.
// "8:0 rbps=1048576".
SetIOMax(spec string) error
// Add moves the process pid into this group by writing cgroup.procs.
Add(pid int) error
// Delete removes the (empty) control group; callers move processes out first.
Delete() error
}
Group is a handle to a cgroup v2 control group used to confine a process tree: set controller limits, attach processes, and remove the group. Implementations live in internal/service/proc/*; it is Linux-only and non-Linux builds return a no-op satisfying this interface with UNSUPPORTED_PLATFORM.
type LimitValue ¶
type LimitValue struct {
// Soft is the enforced limit; it must not exceed Hard.
Soft uint64
// Hard is the ceiling for Soft; raising it typically requires privilege.
Hard uint64
}
LimitValue is an immutable soft/hard resource-limit pair for setrlimit(2). The soft limit is the enforced value; the hard limit is the ceiling an unprivileged process may raise the soft limit to.
type Listener ¶
type Listener interface {
// Recv blocks until the next datagram arrives and returns it parsed, with the
// sender PID verified by the kernel. It returns a typed error on a malformed
// datagram or once the listener is closed.
Recv() (NotificationValue, error)
// Close releases the socket and unblocks any in-flight Recv.
Close() error
}
Listener is the supervisor side of the sd_notify protocol: it owns the AF_UNIX datagram socket a supervised child writes readiness to, and yields one parsed, credential-verified NotificationValue per received datagram. Implementations live in internal/service/proc/*.
type NotificationValue ¶
type NotificationValue struct {
// State is the raw NAME=value field set from the datagram (READY, STATUS,
// MAINPID, WATCHDOG, RELOADING, STOPPING, …), preserved verbatim.
State map[string]string
// Status is the free-text STATUS= line, empty when absent.
Status string
// MainPID is the PID advertised by MAINPID=, or 0 when absent.
MainPID int
// SenderPID is the sending process's PID as verified by the kernel via
// SO_PASSCRED, not a value the sender can forge; 0 when credentials were
// unavailable.
SenderPID int
}
NotificationValue is a parsed sd_notify(3) datagram received by a Listener: the raw newline-separated state fields plus the kernel-verified sender PID. It carries no policy — a supervisor decides what READY or WATCHDOG means for ordering. The lifecycle flags are read through methods so State stays the single source of truth.
func (NotificationValue) Ready ¶
func (n NotificationValue) Ready() bool
Ready reports whether the datagram carried READY=1.
func (NotificationValue) Reloading ¶
func (n NotificationValue) Reloading() bool
Reloading reports whether the datagram carried RELOADING=1.
func (NotificationValue) Stopping ¶
func (n NotificationValue) Stopping() bool
Stopping reports whether the datagram carried STOPPING=1.
func (NotificationValue) Watchdog ¶
func (n NotificationValue) Watchdog() bool
Watchdog reports whether the datagram carried WATCHDOG=1 (a keep-alive ping).
type Process ¶
type Process interface {
// PID reports the process identifier of the leader.
PID() int
// Wait blocks until the process exits and returns its ExitValue. It is safe
// to call once; concurrent or repeated calls observe the same outcome.
Wait() (ExitValue, error)
// Signal delivers sig to the leader process only.
Signal(sig Signal) error
// SignalGroup delivers sig to the leader's entire process group (kill(-pgid,
// sig)), reaching forked grandchildren — the KillMode=control-group analogue.
SignalGroup(sig Signal) error
// Stop terminates the process group gracefully: it sends sig, waits up to
// grace for exit, then escalates to SIGKILL. It returns when the process has
// exited or ctx is cancelled.
Stop(ctx context.Context, grace time.Duration, sig Signal) error
}
Process is a handle to a spawned process. It exposes only lifetime control — observe completion, deliver a signal to the leader or its whole group, and stop it gracefully. Implementations live in internal/service/proc/*; the pkg/v1/process facade returns this interface.
type Reaper ¶
type Reaper interface {
// Start begins a background SIGCHLD-driven loop that reaps children as they
// exit. It is idempotent: a second Start while running is a no-op.
Start()
// Stop ends the background loop after a final draining sweep, so shutdown
// leaves no un-reaped zombies. It is safe to call without a prior Start.
Stop()
// ReapOnce performs a single non-blocking sweep and reports how many
// children were reaped. It is safe to call concurrently with the loop.
ReapOnce() (int, error)
}
Reaper collects terminated child processes so they do not linger as zombies — the core duty of any PID1 or subreaper. Implementations live in internal/service/proc/*; non-supporting platforms return a no-op reaper.
type Resource ¶
type Resource int
Resource identifies a per-process resource governed by setrlimit(2). It is an abstract, platform-portable enum; the service layer maps each value to the platform's RLIMIT_* constant. The zero value ResourceUnknown is the reserved invalid sentinel.
const ( // ResourceUnknown is the reserved zero value: no resource selected. ResourceUnknown Resource = iota // ResourceNoFile limits the highest open file descriptor (RLIMIT_NOFILE), // mapping systemd's LimitNOFILE=. ResourceNoFile // ResourceNProc limits the number of processes for the real user id // (RLIMIT_NPROC), mapping systemd's LimitNPROC=. ResourceNProc // ResourceCore limits the size of a core dump in bytes (RLIMIT_CORE), // mapping systemd's LimitCORE=. ResourceCore // ResourceAS limits the process virtual address-space size (RLIMIT_AS), // mapping systemd's LimitAS=. ResourceAS // ResourceCPU limits CPU time in seconds (RLIMIT_CPU), mapping systemd's // LimitCPU=. ResourceCPU // ResourceFSize limits the largest file the process may create in bytes // (RLIMIT_FSIZE), mapping systemd's LimitFSIZE=. ResourceFSize // ResourceData limits the process data-segment size (RLIMIT_DATA), mapping // systemd's LimitDATA=. ResourceData // ResourceStack limits the process stack size (RLIMIT_STACK), mapping // systemd's LimitSTACK=. ResourceStack // ResourceMemLock limits bytes that may be locked into RAM (RLIMIT_MEMLOCK), // mapping systemd's LimitMEMLOCK=. ResourceMemLock )
type Signal ¶
type Signal int
Signal is a typed, platform-portable OS signal. Its underlying value is the platform signal number, so Signal(syscall.SIGTERM) and a Signal parsed from "SIGTERM" compare equal. The zero value is the reserved invalid signal.
func Parse ¶
Parse resolves a signal from its name or number into sig. It accepts the canonical "SIGTERM", the bare "TERM", and the numeric "15" (all case-insensitive), returning UnknownSignal for anything the platform table does not define.
type Spec ¶
type Spec struct {
// Path is the absolute or PATH-resolvable executable to run. Required.
Path string
// Args is the full argv including argv[0]; when empty the service uses
// [Path] as the sole argument.
Args []string
// Dir is the working directory; empty means inherit the parent's.
Dir string
// Env is the explicit environment; nil yields an empty environment, never
// implicit inheritance, so a spawned service starts from a known state.
Env []string
// User is the name or numeric uid to setuid to; empty leaves the parent's.
User string
// Group is the name or numeric gid to setgid to; empty leaves the parent's.
Group string
// Groups are supplementary group names or gids (systemd SupplementaryGroups=).
Groups []string
// Setpgid places the child in its own process group, enabling group-kill of
// the whole tree (systemd KillMode=control-group without cgroups).
Setpgid bool
// Setsid starts the child in a new session detached from the controlling tty.
Setsid bool
// Umask, when non-nil, is the file-creation mask applied to the child
// (systemd UMask=).
Umask *int
// Nice, when non-nil, is the scheduling-priority adjustment applied to the
// child (systemd Nice=).
Nice *int
// OOMScoreAdj, when non-nil, is the /proc/<pid>/oom_score_adj value applied
// to the child (systemd OOMScoreAdjust=).
OOMScoreAdj *int
// Rlimits are per-resource soft/hard limits applied post-fork, pre-exec
// (systemd Limit*=); resources unsupported on the platform surface a typed
// error rather than silently no-op.
Rlimits map[Resource]LimitValue
}
Spec is the immutable description of a process to spawn: the executable and its environment, the credentials and isolation topology to apply, and the resource/scheduling attributes to set between fork and exec. It carries no policy — restart, health, and dependency concerns belong to the caller.
Pointer fields (Umask, Nice, OOMScoreAdj) distinguish "leave at the inherited default" (nil) from "set explicitly to zero". Maps and slices are read by the service layer and never mutated.