1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
//! Resource caps applied to a [`ProcessGroup`](crate::ProcessGroup).
/// Resource limits enforced on a process group as a whole.
///
/// Set these via [`ProcessGroupOptions`](crate::ProcessGroupOptions) (the
/// `max_memory` / `max_processes` / `cpu_quota` builders, or by setting the
/// public fields on a `ResourceLimits::default()` value) before creating the
/// group. Every limit bounds the **whole tree**, not a single process, and is
/// applied to the kernel container at creation time.
///
/// # Platform support
///
/// Enforcement needs a real container — a **Windows Job Object** or a **Linux
/// cgroup v2**. On macOS/the BSDs and the Linux process-group fallback there is
/// no whole-tree limit primitive, so
/// requesting *any* limit there fails fast with
/// [`Error::ResourceLimit`](crate::Error::ResourceLimit) rather than silently
/// leaving the tree unbounded.
///
/// **Linux (cgroup v2): limits need this process at the *real* cgroup root.**
/// The crate creates the limit cgroup as a **child of this process's own cgroup**
/// and enables the controllers in *that* cgroup's `cgroup.subtree_control`. cgroup
/// v2's "no internal processes" rule permits enabling controllers in a cgroup that
/// holds member processes only for the **root of the real hierarchy** — the one
/// exempt cgroup. A cgroup *namespace* root does **not** qualify: it only
/// virtualizes the view (`/proc/self/cgroup` reads `0::/`), but the cgroup still
/// isn't the real root, so a container with a private cgroup namespace (the
/// Docker/Kubernetes default) hits `EBUSY` exactly like a systemd scope. So in
/// practice these limits apply only when this process is a direct member of the
/// real hierarchy root (a minimal init not managed by systemd) — **not** under any
/// systemd session/scope/service, and **not** in an ordinary container. When the
/// controllers can't be enabled, group creation **fails fast**
/// ([`Error::ResourceLimit`](crate::Error::ResourceLimit)) rather than silently
/// leaving the tree unbounded — an unenforced limit is no protection. The crate
/// deliberately does **not** migrate your process into a sub-cgroup to make limits
/// work elsewhere (the create-leaf→migrate-self→enable dance); do that externally
/// if you need them. (When the controllers are already enabled — at the root — no
/// `subtree_control` write is attempted.)
///
/// Derives `PartialEq` but **not** `Eq` (unlike the sibling config/stats types):
/// [`cpu_quota`](Self::cpu_quota) is an `Option<f64>`, and `f64` is not `Eq`. So
/// `ResourceLimits` compares with `==` but can't be a `HashMap`/`BTreeSet` key.
/// Which [`ResourceLimits`] field an
/// [`Error::ResourceLimit`](crate::Error::ResourceLimit) failure is about —
/// [`Memory`](Self::Memory) for [`max_memory`](ResourceLimits::max_memory),
/// [`Processes`](Self::Processes) for
/// [`max_processes`](ResourceLimits::max_processes), [`Cpu`](Self::Cpu) for
/// [`cpu_quota`](ResourceLimits::cpu_quota).
///
/// When a caller requests more than one limit at once and the failure can't be
/// pinned to a single one (e.g. a Linux cgroup that can't enable any controller
/// because this process isn't at the real hierarchy root), `kind` names the
/// **first** requested limit in `max_memory`, `max_processes`, `cpu_quota` order
/// — a fixed, documented tie-break rather than an arbitrary one.
/// Why a requested resource limit could not be applied — the classification an
/// [`Error::ResourceLimit`](crate::Error::ResourceLimit) failure carries so a
/// caller (e.g. the `processkit-py` binding) can branch on the *kind* of failure
/// without parsing the English `detail` text.