/rust/registry/src/index.crates.io-1949cf8c6b5b557f/nix-0.28.0/src/sys/resource.rs
Line | Count | Source |
1 | | //! Configure the process resource limits. |
2 | | use cfg_if::cfg_if; |
3 | | use libc::{c_int, c_long, rusage}; |
4 | | |
5 | | use crate::errno::Errno; |
6 | | use crate::sys::time::TimeVal; |
7 | | use crate::Result; |
8 | | pub use libc::rlim_t; |
9 | | pub use libc::RLIM_INFINITY; |
10 | | use std::mem; |
11 | | |
12 | | cfg_if! { |
13 | | if #[cfg(any( |
14 | | all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")), |
15 | | target_os = "hurd" |
16 | | ))]{ |
17 | | use libc::{__rlimit_resource_t, rlimit}; |
18 | | } else if #[cfg(any( |
19 | | bsd, |
20 | | target_os = "android", |
21 | | target_os = "aix", |
22 | | all(target_os = "linux", not(target_env = "gnu")) |
23 | | ))]{ |
24 | | use libc::rlimit; |
25 | | } |
26 | | } |
27 | | |
28 | | libc_enum! { |
29 | | /// Types of process resources. |
30 | | /// |
31 | | /// The Resource enum is platform dependent. Check different platform |
32 | | /// manuals for more details. Some platform links have been provided for |
33 | | /// easier reference (non-exhaustive). |
34 | | /// |
35 | | /// * [Linux](https://man7.org/linux/man-pages/man2/getrlimit.2.html) |
36 | | /// * [FreeBSD](https://www.freebsd.org/cgi/man.cgi?query=setrlimit) |
37 | | /// * [NetBSD](https://man.netbsd.org/setrlimit.2) |
38 | | |
39 | | // linux-gnu uses u_int as resource enum, which is implemented in libc as |
40 | | // well. |
41 | | // |
42 | | // https://gcc.gnu.org/legacy-ml/gcc/2015-08/msg00441.html |
43 | | // https://github.com/rust-lang/libc/blob/master/src/unix/linux_like/linux/gnu/mod.rs |
44 | | #[cfg_attr(any( |
45 | | all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")), |
46 | | target_os = "hurd" |
47 | | ), repr(u32))] |
48 | | #[cfg_attr(any( |
49 | | bsd, |
50 | | target_os = "android", |
51 | | target_os = "aix", |
52 | | all(target_os = "linux", not(any(target_env = "gnu", target_env = "uclibc"))) |
53 | | ), repr(i32))] |
54 | | #[non_exhaustive] |
55 | | pub enum Resource { |
56 | | #[cfg(not(any(target_os = "freebsd", netbsdlike)))] |
57 | | /// The maximum amount (in bytes) of virtual memory the process is |
58 | | /// allowed to map. |
59 | | RLIMIT_AS, |
60 | | /// The largest size (in bytes) core(5) file that may be created. |
61 | | RLIMIT_CORE, |
62 | | /// The maximum amount of cpu time (in seconds) to be used by each |
63 | | /// process. |
64 | | RLIMIT_CPU, |
65 | | /// The maximum size (in bytes) of the data segment for a process |
66 | | RLIMIT_DATA, |
67 | | /// The largest size (in bytes) file that may be created. |
68 | | RLIMIT_FSIZE, |
69 | | /// The maximum number of open files for this process. |
70 | | RLIMIT_NOFILE, |
71 | | /// The maximum size (in bytes) of the stack segment for a process. |
72 | | RLIMIT_STACK, |
73 | | |
74 | | #[cfg(target_os = "freebsd")] |
75 | | /// The maximum number of kqueues this user id is allowed to create. |
76 | | RLIMIT_KQUEUES, |
77 | | |
78 | | #[cfg(linux_android)] |
79 | | /// A limit on the combined number of flock locks and fcntl leases that |
80 | | /// this process may establish. |
81 | | RLIMIT_LOCKS, |
82 | | |
83 | | #[cfg(any(linux_android, target_os = "freebsd", netbsdlike))] |
84 | | /// The maximum size (in bytes) which a process may lock into memory |
85 | | /// using the mlock(2) system call. |
86 | | RLIMIT_MEMLOCK, |
87 | | |
88 | | #[cfg(linux_android)] |
89 | | /// A limit on the number of bytes that can be allocated for POSIX |
90 | | /// message queues for the real user ID of the calling process. |
91 | | RLIMIT_MSGQUEUE, |
92 | | |
93 | | #[cfg(linux_android)] |
94 | | /// A ceiling to which the process's nice value can be raised using |
95 | | /// setpriority or nice. |
96 | | RLIMIT_NICE, |
97 | | |
98 | | #[cfg(any( |
99 | | linux_android, |
100 | | target_os = "freebsd", |
101 | | netbsdlike, |
102 | | target_os = "aix", |
103 | | ))] |
104 | | /// The maximum number of simultaneous processes for this user id. |
105 | | RLIMIT_NPROC, |
106 | | |
107 | | #[cfg(target_os = "freebsd")] |
108 | | /// The maximum number of pseudo-terminals this user id is allowed to |
109 | | /// create. |
110 | | RLIMIT_NPTS, |
111 | | |
112 | | #[cfg(any(linux_android, |
113 | | target_os = "freebsd", |
114 | | netbsdlike, |
115 | | target_os = "aix", |
116 | | ))] |
117 | | /// When there is memory pressure and swap is available, prioritize |
118 | | /// eviction of a process' resident pages beyond this amount (in bytes). |
119 | | RLIMIT_RSS, |
120 | | |
121 | | #[cfg(linux_android)] |
122 | | /// A ceiling on the real-time priority that may be set for this process |
123 | | /// using sched_setscheduler and sched_set‐ param. |
124 | | RLIMIT_RTPRIO, |
125 | | |
126 | | #[cfg(any(target_os = "linux"))] |
127 | | /// A limit (in microseconds) on the amount of CPU time that a process |
128 | | /// scheduled under a real-time scheduling policy may con‐ sume without |
129 | | /// making a blocking system call. |
130 | | RLIMIT_RTTIME, |
131 | | |
132 | | #[cfg(linux_android)] |
133 | | /// A limit on the number of signals that may be queued for the real |
134 | | /// user ID of the calling process. |
135 | | RLIMIT_SIGPENDING, |
136 | | |
137 | | #[cfg(freebsdlike)] |
138 | | /// The maximum size (in bytes) of socket buffer usage for this user. |
139 | | RLIMIT_SBSIZE, |
140 | | |
141 | | #[cfg(target_os = "freebsd")] |
142 | | /// The maximum size (in bytes) of the swap space that may be reserved |
143 | | /// or used by all of this user id's processes. |
144 | | RLIMIT_SWAP, |
145 | | |
146 | | #[cfg(target_os = "freebsd")] |
147 | | /// An alias for RLIMIT_AS. |
148 | | RLIMIT_VMEM, |
149 | | } |
150 | | } |
151 | | |
152 | | /// Get the current processes resource limits |
153 | | /// |
154 | | /// The special value [`RLIM_INFINITY`] indicates that no limit will be |
155 | | /// enforced. |
156 | | /// |
157 | | /// # Parameters |
158 | | /// |
159 | | /// * `resource`: The [`Resource`] that we want to get the limits of. |
160 | | /// |
161 | | /// # Examples |
162 | | /// |
163 | | /// ``` |
164 | | /// # use nix::sys::resource::{getrlimit, Resource}; |
165 | | /// |
166 | | /// let (soft_limit, hard_limit) = getrlimit(Resource::RLIMIT_NOFILE).unwrap(); |
167 | | /// println!("current soft_limit: {}", soft_limit); |
168 | | /// println!("current hard_limit: {}", hard_limit); |
169 | | /// ``` |
170 | | /// |
171 | | /// # References |
172 | | /// |
173 | | /// [getrlimit(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getrlimit.html#tag_16_215) |
174 | | /// |
175 | | /// [`Resource`]: enum.Resource.html |
176 | 0 | pub fn getrlimit(resource: Resource) -> Result<(rlim_t, rlim_t)> { |
177 | 0 | let mut old_rlim = mem::MaybeUninit::<rlimit>::uninit(); |
178 | | |
179 | | cfg_if! { |
180 | | if #[cfg(any( |
181 | | all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")), |
182 | | target_os = "hurd" |
183 | | ))] { |
184 | 0 | let res = unsafe { libc::getrlimit(resource as __rlimit_resource_t, old_rlim.as_mut_ptr()) }; |
185 | | } else { |
186 | | let res = unsafe { libc::getrlimit(resource as c_int, old_rlim.as_mut_ptr()) }; |
187 | | } |
188 | | } |
189 | | |
190 | 0 | Errno::result(res).map(|_| { |
191 | 0 | let rlimit { rlim_cur, rlim_max } = unsafe { old_rlim.assume_init() }; |
192 | 0 | (rlim_cur, rlim_max) |
193 | 0 | }) |
194 | 0 | } |
195 | | |
196 | | /// Set the current processes resource limits |
197 | | /// |
198 | | /// # Parameters |
199 | | /// |
200 | | /// * `resource`: The [`Resource`] that we want to set the limits of. |
201 | | /// * `soft_limit`: The value that the kernel enforces for the corresponding |
202 | | /// resource. |
203 | | /// * `hard_limit`: The ceiling for the soft limit. Must be lower or equal to |
204 | | /// the current hard limit for non-root users. |
205 | | /// |
206 | | /// The special value [`RLIM_INFINITY`] indicates that no limit will be |
207 | | /// enforced. |
208 | | /// |
209 | | /// # Examples |
210 | | /// |
211 | | /// ``` |
212 | | /// # use nix::sys::resource::{setrlimit, Resource}; |
213 | | /// |
214 | | /// let soft_limit = 512; |
215 | | /// let hard_limit = 1024; |
216 | | /// setrlimit(Resource::RLIMIT_NOFILE, soft_limit, hard_limit).unwrap(); |
217 | | /// ``` |
218 | | /// |
219 | | /// # References |
220 | | /// |
221 | | /// [setrlimit(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getrlimit.html#tag_16_215) |
222 | | /// |
223 | | /// [`Resource`]: enum.Resource.html |
224 | | /// |
225 | | /// Note: `setrlimit` provides a safe wrapper to libc's `setrlimit`. |
226 | 0 | pub fn setrlimit( |
227 | 0 | resource: Resource, |
228 | 0 | soft_limit: rlim_t, |
229 | 0 | hard_limit: rlim_t, |
230 | 0 | ) -> Result<()> { |
231 | 0 | let new_rlim = rlimit { |
232 | 0 | rlim_cur: soft_limit, |
233 | 0 | rlim_max: hard_limit, |
234 | 0 | }; |
235 | | cfg_if! { |
236 | | if #[cfg(any( |
237 | | all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")), |
238 | | target_os = "hurd", |
239 | | ))]{ |
240 | 0 | let res = unsafe { libc::setrlimit(resource as __rlimit_resource_t, &new_rlim as *const rlimit) }; |
241 | | }else{ |
242 | | let res = unsafe { libc::setrlimit(resource as c_int, &new_rlim as *const rlimit) }; |
243 | | } |
244 | | } |
245 | | |
246 | 0 | Errno::result(res).map(drop) |
247 | 0 | } |
248 | | |
249 | | libc_enum! { |
250 | | /// Whose resource usage should be returned by [`getrusage`]. |
251 | | #[repr(i32)] |
252 | | #[non_exhaustive] |
253 | | pub enum UsageWho { |
254 | | /// Resource usage for the current process. |
255 | | RUSAGE_SELF, |
256 | | |
257 | | /// Resource usage for all the children that have terminated and been waited for. |
258 | | RUSAGE_CHILDREN, |
259 | | |
260 | | #[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "openbsd"))] |
261 | | /// Resource usage for the calling thread. |
262 | | RUSAGE_THREAD, |
263 | | } |
264 | | } |
265 | | |
266 | | /// Output of `getrusage` with information about resource usage. Some of the fields |
267 | | /// may be unused in some platforms, and will be always zeroed out. See their manuals |
268 | | /// for details. |
269 | | #[repr(transparent)] |
270 | | #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] |
271 | | pub struct Usage(rusage); |
272 | | |
273 | | impl AsRef<rusage> for Usage { |
274 | 0 | fn as_ref(&self) -> &rusage { |
275 | 0 | &self.0 |
276 | 0 | } |
277 | | } |
278 | | |
279 | | impl AsMut<rusage> for Usage { |
280 | 0 | fn as_mut(&mut self) -> &mut rusage { |
281 | 0 | &mut self.0 |
282 | 0 | } |
283 | | } |
284 | | |
285 | | impl Usage { |
286 | | /// Total amount of time spent executing in user mode. |
287 | 0 | pub fn user_time(&self) -> TimeVal { |
288 | 0 | TimeVal::from(self.0.ru_utime) |
289 | 0 | } |
290 | | |
291 | | /// Total amount of time spent executing in kernel mode. |
292 | 0 | pub fn system_time(&self) -> TimeVal { |
293 | 0 | TimeVal::from(self.0.ru_stime) |
294 | 0 | } |
295 | | |
296 | | /// The resident set size at its peak, in kilobytes. |
297 | 0 | pub fn max_rss(&self) -> c_long { |
298 | 0 | self.0.ru_maxrss |
299 | 0 | } |
300 | | |
301 | | /// Integral value expressed in kilobytes times ticks of execution indicating |
302 | | /// the amount of text memory shared with other processes. |
303 | 0 | pub fn shared_integral(&self) -> c_long { |
304 | 0 | self.0.ru_ixrss |
305 | 0 | } |
306 | | |
307 | | /// Integral value expressed in kilobytes times ticks of execution indicating |
308 | | /// the amount of unshared memory used by data. |
309 | 0 | pub fn unshared_data_integral(&self) -> c_long { |
310 | 0 | self.0.ru_idrss |
311 | 0 | } |
312 | | |
313 | | /// Integral value expressed in kilobytes times ticks of execution indicating |
314 | | /// the amount of unshared memory used for stack space. |
315 | 0 | pub fn unshared_stack_integral(&self) -> c_long { |
316 | 0 | self.0.ru_isrss |
317 | 0 | } |
318 | | |
319 | | /// Number of page faults that were served without resorting to I/O, with pages |
320 | | /// that have been allocated previously by the kernel. |
321 | 0 | pub fn minor_page_faults(&self) -> c_long { |
322 | 0 | self.0.ru_minflt |
323 | 0 | } |
324 | | |
325 | | /// Number of page faults that were served through I/O (i.e. swap). |
326 | 0 | pub fn major_page_faults(&self) -> c_long { |
327 | 0 | self.0.ru_majflt |
328 | 0 | } |
329 | | |
330 | | /// Number of times all of the memory was fully swapped out. |
331 | 0 | pub fn full_swaps(&self) -> c_long { |
332 | 0 | self.0.ru_nswap |
333 | 0 | } |
334 | | |
335 | | /// Number of times a read was done from a block device. |
336 | 0 | pub fn block_reads(&self) -> c_long { |
337 | 0 | self.0.ru_inblock |
338 | 0 | } |
339 | | |
340 | | /// Number of times a write was done to a block device. |
341 | 0 | pub fn block_writes(&self) -> c_long { |
342 | 0 | self.0.ru_oublock |
343 | 0 | } |
344 | | |
345 | | /// Number of IPC messages sent. |
346 | 0 | pub fn ipc_sends(&self) -> c_long { |
347 | 0 | self.0.ru_msgsnd |
348 | 0 | } |
349 | | |
350 | | /// Number of IPC messages received. |
351 | 0 | pub fn ipc_receives(&self) -> c_long { |
352 | 0 | self.0.ru_msgrcv |
353 | 0 | } |
354 | | |
355 | | /// Number of signals received. |
356 | 0 | pub fn signals(&self) -> c_long { |
357 | 0 | self.0.ru_nsignals |
358 | 0 | } |
359 | | |
360 | | /// Number of times a context switch was voluntarily invoked. |
361 | 0 | pub fn voluntary_context_switches(&self) -> c_long { |
362 | 0 | self.0.ru_nvcsw |
363 | 0 | } |
364 | | |
365 | | /// Number of times a context switch was imposed by the kernel (usually due to |
366 | | /// time slice expiring or preemption by a higher priority process). |
367 | 0 | pub fn involuntary_context_switches(&self) -> c_long { |
368 | 0 | self.0.ru_nivcsw |
369 | 0 | } |
370 | | } |
371 | | |
372 | | /// Get usage information for a process, its children or the current thread |
373 | | /// |
374 | | /// Real time information can be obtained for either the current process or (in some |
375 | | /// systems) thread, but information about children processes is only provided for |
376 | | /// those that have terminated and been waited for (see [`super::wait::wait`]). |
377 | | /// |
378 | | /// Some information may be missing depending on the platform, and the way information |
379 | | /// is provided for children may also vary. Check the manuals for details. |
380 | | /// |
381 | | /// # References |
382 | | /// |
383 | | /// * [getrusage(2)](https://pubs.opengroup.org/onlinepubs/009696699/functions/getrusage.html) |
384 | | /// * [Linux](https://man7.org/linux/man-pages/man2/getrusage.2.html) |
385 | | /// * [FreeBSD](https://www.freebsd.org/cgi/man.cgi?query=getrusage) |
386 | | /// * [NetBSD](https://man.netbsd.org/getrusage.2) |
387 | | /// * [MacOS](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/getrusage.2.html) |
388 | | /// |
389 | | /// [`UsageWho`]: enum.UsageWho.html |
390 | | /// |
391 | | /// Note: `getrusage` provides a safe wrapper to libc's [`libc::getrusage`]. |
392 | 0 | pub fn getrusage(who: UsageWho) -> Result<Usage> { |
393 | | unsafe { |
394 | 0 | let mut rusage = mem::MaybeUninit::<rusage>::uninit(); |
395 | 0 | let res = libc::getrusage(who as c_int, rusage.as_mut_ptr()); |
396 | 0 | Errno::result(res).map(|_| Usage(rusage.assume_init())) |
397 | | } |
398 | 0 | } |