procfs_core/process/
limit.rs

1use crate::{ProcError, ProcResult};
2
3use std::collections::HashMap;
4use std::io::BufRead;
5use std::str::FromStr;
6
7#[cfg(feature = "serde1")]
8use serde::{Deserialize, Serialize};
9
10/// Process limits
11///
12/// For more details about each of these limits, see the `getrlimit` man page.
13#[derive(Debug, Clone)]
14#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
15pub struct Limits {
16    /// Max Cpu Time
17    ///
18    /// This is a limit, in seconds, on the amount of CPU time that the process can consume.
19    pub max_cpu_time: Limit,
20
21    /// Max file size
22    ///
23    /// This is the maximum size in bytes of files that the process may create.
24    pub max_file_size: Limit,
25
26    /// Max data size
27    ///
28    /// This is the maximum size of the process's data segment (initialized data, uninitialized
29    /// data, and heap).
30    pub max_data_size: Limit,
31
32    /// Max stack size
33    ///
34    /// This is the maximum size of the process stack, in bytes.
35    pub max_stack_size: Limit,
36
37    /// Max core file size
38    ///
39    /// This is the maximum size of a *core* file in bytes that the process may dump.
40    pub max_core_file_size: Limit,
41
42    /// Max resident set
43    ///
44    /// This is a limit (in bytes) on the process's resident set (the number of virtual pages
45    /// resident in RAM).
46    pub max_resident_set: Limit,
47
48    /// Max processes
49    ///
50    /// This is a limit on the number of extant process (or, more precisely on Linux, threads) for
51    /// the real user rID of the calling process.
52    pub max_processes: Limit,
53
54    /// Max open files
55    ///
56    /// This specifies a value one greater than the maximum file descriptor number that can be
57    /// opened by this process.
58    pub max_open_files: Limit,
59
60    /// Max locked memory
61    ///
62    /// This is the maximum number of bytes of memory that may be locked into RAM.
63    pub max_locked_memory: Limit,
64
65    /// Max address space
66    ///
67    /// This is the maximum size of the process's virtual memory (address space).
68    pub max_address_space: Limit,
69
70    /// Max file locks
71    ///
72    /// This is a limit on the combined number of flock locks and fcntl leases that this process
73    /// may establish.
74    pub max_file_locks: Limit,
75
76    /// Max pending signals
77    ///
78    /// This is a limit on the number of signals that may be queued for the real user rID of the
79    /// calling process.
80    pub max_pending_signals: Limit,
81
82    /// Max msgqueue size
83    ///
84    /// This is a limit on the number of bytes that can be allocated for POSIX message queues for
85    /// the real user rID of the calling process.
86    pub max_msgqueue_size: Limit,
87
88    /// Max nice priority
89    ///
90    /// This specifies a ceiling to which the process's nice value can be raised using
91    /// `setpriority` or `nice`.
92    pub max_nice_priority: Limit,
93
94    /// Max realtime priority
95    ///
96    /// This specifies a ceiling on the real-time priority that may be set for this process using
97    /// `sched_setscheduler` and `sched_setparam`.
98    pub max_realtime_priority: Limit,
99
100    /// Max realtime timeout
101    ///
102    /// This is a limit (in microseconds) on the amount of CPU time that a process scheduled under
103    /// a real-time scheduling policy may consume without making a blocking system call.
104    pub max_realtime_timeout: Limit,
105}
106
107impl crate::FromBufRead for Limits {
108    fn from_buf_read<R: BufRead>(r: R) -> ProcResult<Self> {
109        let mut lines = r.lines();
110
111        let mut map = HashMap::new();
112
113        while let Some(Ok(line)) = lines.next() {
114            let line = line.trim();
115            if line.starts_with("Limit") {
116                continue;
117            }
118            let s: Vec<_> = line.split_whitespace().collect();
119            let l = s.len();
120
121            let (hard_limit, soft_limit, name) =
122                if line.starts_with("Max nice priority") || line.starts_with("Max realtime priority") {
123                    // these two limits don't have units, and so need different offsets:
124                    let hard_limit = expect!(s.get(l - 1)).to_owned();
125                    let soft_limit = expect!(s.get(l - 2)).to_owned();
126                    let name = s[0..l - 2].join(" ");
127                    (hard_limit, soft_limit, name)
128                } else {
129                    let hard_limit = expect!(s.get(l - 2)).to_owned();
130                    let soft_limit = expect!(s.get(l - 3)).to_owned();
131                    let name = s[0..l - 3].join(" ");
132                    (hard_limit, soft_limit, name)
133                };
134            let _units = expect!(s.get(l - 1));
135
136            map.insert(name.to_owned(), (soft_limit.to_owned(), hard_limit.to_owned()));
137        }
138
139        let limits = Limits {
140            max_cpu_time: Limit::from_pair(expect!(map.remove("Max cpu time")))?,
141            max_file_size: Limit::from_pair(expect!(map.remove("Max file size")))?,
142            max_data_size: Limit::from_pair(expect!(map.remove("Max data size")))?,
143            max_stack_size: Limit::from_pair(expect!(map.remove("Max stack size")))?,
144            max_core_file_size: Limit::from_pair(expect!(map.remove("Max core file size")))?,
145            max_resident_set: Limit::from_pair(expect!(map.remove("Max resident set")))?,
146            max_processes: Limit::from_pair(expect!(map.remove("Max processes")))?,
147            max_open_files: Limit::from_pair(expect!(map.remove("Max open files")))?,
148            max_locked_memory: Limit::from_pair(expect!(map.remove("Max locked memory")))?,
149            max_address_space: Limit::from_pair(expect!(map.remove("Max address space")))?,
150            max_file_locks: Limit::from_pair(expect!(map.remove("Max file locks")))?,
151            max_pending_signals: Limit::from_pair(expect!(map.remove("Max pending signals")))?,
152            max_msgqueue_size: Limit::from_pair(expect!(map.remove("Max msgqueue size")))?,
153            max_nice_priority: Limit::from_pair(expect!(map.remove("Max nice priority")))?,
154            max_realtime_priority: Limit::from_pair(expect!(map.remove("Max realtime priority")))?,
155            max_realtime_timeout: Limit::from_pair(expect!(map.remove("Max realtime timeout")))?,
156        };
157        if cfg!(test) {
158            assert!(map.is_empty(), "Map isn't empty: {:?}", map);
159        }
160        Ok(limits)
161    }
162}
163
164#[derive(Debug, Copy, Clone)]
165#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
166pub struct Limit {
167    pub soft_limit: LimitValue,
168    pub hard_limit: LimitValue,
169}
170
171impl Limit {
172    fn from_pair(l: (String, String)) -> ProcResult<Limit> {
173        let (soft, hard) = l;
174        Ok(Limit {
175            soft_limit: LimitValue::from_str(&soft)?,
176            hard_limit: LimitValue::from_str(&hard)?,
177        })
178    }
179}
180
181#[derive(Debug, Copy, Clone)]
182#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
183pub enum LimitValue {
184    Unlimited,
185    Value(u64),
186}
187
188impl FromStr for LimitValue {
189    type Err = ProcError;
190    fn from_str(s: &str) -> Result<Self, Self::Err> {
191        if s == "unlimited" {
192            Ok(LimitValue::Unlimited)
193        } else {
194            Ok(LimitValue::Value(from_str!(u64, s)))
195        }
196    }
197}