Documentation
¶
Overview ¶
Package cgroup probes the host for cgroup v2 support and the presence of a delegated subtree the praxis runtime can use to enforce per-plugin memory and CPU caps. Phase 5 out-of-process resource isolation (M3.1 follow-up).
Detection is the only thing this package does; spawning the child into a cgroup and applying memory.max / cpu.max happens in follow-up tasks (t-cgroup-v2-spawn / t-cgroup-v2-usage-metrics).
Linux-only. The other-OS file returns Status{Available: false} so the caller can fall back to setrlimit without a build error on macOS or other developer platforms.
Index ¶
Constants ¶
const DefaultRootDir = "/sys/fs/cgroup/praxis"
DefaultRootDir is the conventional location of the praxis-managed cgroup subtree. Operators can override via DetectAt for tests or non-standard layouts.
const UnifiedMount = "/sys/fs/cgroup"
UnifiedMount is the canonical cgroup v2 root on systemd hosts.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Budget ¶
Budget mirrors the subset of plugin.ResourceBudget the cgroup applier consumes. Defined here to keep this package free of an import cycle with internal/plugin.
type Handle ¶
type Handle struct {
Path string
}
Handle owns one per-plugin cgroup directory. Callers create it via Prepare, attach a child PID with AddPID, and reclaim the directory with Cleanup once the child exits.
func Prepare ¶
Prepare creates a per-plugin cgroup under parent and writes memory.max + cpu.max from b. Returns ErrUnavailable when parent does not exist or is not writable so the caller can fall back to setrlimit without further branching.
CPU is encoded as "<quota> <period>" microseconds. We pick a 100ms period and a quota matching b.CPUTimeout / period_count so the effective rate is "1 CPU until budget is exhausted." Budget=0 fields are skipped (no enforcement on that dimension).
Atomicity caveat: this Prepare creates the cgroup before Start; the parent attaches the child via AddPID after fork+exec. There is a brief window (microseconds) where the child runs unconstrained. True atomicity requires clone3 + CLONE_INTO_CGROUP and a per-fd open of the cgroup directory, which Go's exec.Cmd does not expose. The window is acceptable for resource isolation; it is NOT acceptable for adversarial workloads — those require the future landlock+seccomp layer.
func (*Handle) AddPID ¶
AddPID attaches an existing process to the cgroup by writing its PID to cgroup.procs. The kernel applies the cgroup's limits the next time the process is scheduled.
func (*Handle) Cleanup ¶
Cleanup removes the cgroup directory. Safe to call from a defer in the parent's spawn flow; no-op when the directory has already been reclaimed (e.g. by the kernel after the last process exits).
func (*Handle) ReadCPUUsageNs ¶
ReadCPUUsageNs parses cpu.stat for cumulative CPU time. cgroup v2 reports microseconds; the result is converted to nanoseconds so it composes cleanly with time.Duration arithmetic.
func (*Handle) ReadMemoryPeak ¶
ReadMemoryPeak returns the high-water-mark memory usage in bytes the kernel recorded for this cgroup. Used by usage-metrics reporting (t-cgroup-v2-usage-metrics).
type Status ¶
type Status struct {
Available bool
Root string // e.g. /sys/fs/cgroup/praxis
UnifiedMount string // e.g. /sys/fs/cgroup
Reason string // human-readable fallback explanation when Available=false
}
Status reports what the runtime can rely on at startup. Available is the headline: when false, the caller falls back to setrlimit (the Phase 4 mechanism) and emits Reason in a structured log so operators understand why the stricter mechanism was unavailable.
func Detect ¶
func Detect() Status
Detect probes the conventional locations and reports whether Praxis can use cgroup v2 enforcement on this host. Returns Status.Available=false (with a populated Reason) on:
- non-Linux platforms (the other-OS file short-circuits this);
- cgroup v1 hosts (cgroup.controllers absent);
- hosts where the praxis subtree does not exist;
- hosts where the praxis subtree is not writable by the runtime user.
Detection is fast (a few stat / read calls) and never blocks.