• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
getrlimit(resource: Resource) -> Result<(rlim_t, rlim_t)>176 pub fn getrlimit(resource: Resource) -> Result<(rlim_t, rlim_t)> {
177     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             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     Errno::result(res).map(|_| {
191         let rlimit { rlim_cur, rlim_max } = unsafe { old_rlim.assume_init() };
192         (rlim_cur, rlim_max)
193     })
194 }
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`.
setrlimit( resource: Resource, soft_limit: rlim_t, hard_limit: rlim_t, ) -> Result<()>226 pub fn setrlimit(
227     resource: Resource,
228     soft_limit: rlim_t,
229     hard_limit: rlim_t,
230 ) -> Result<()> {
231     let new_rlim = rlimit {
232         rlim_cur: soft_limit,
233         rlim_max: hard_limit,
234     };
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             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     Errno::result(res).map(drop)
247 }
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 {
as_ref(&self) -> &rusage274     fn as_ref(&self) -> &rusage {
275         &self.0
276     }
277 }
278 
279 impl AsMut<rusage> for Usage {
as_mut(&mut self) -> &mut rusage280     fn as_mut(&mut self) -> &mut rusage {
281         &mut self.0
282     }
283 }
284 
285 impl Usage {
286     /// Total amount of time spent executing in user mode.
user_time(&self) -> TimeVal287     pub fn user_time(&self) -> TimeVal {
288         TimeVal::from(self.0.ru_utime)
289     }
290 
291     /// Total amount of time spent executing in kernel mode.
system_time(&self) -> TimeVal292     pub fn system_time(&self) -> TimeVal {
293         TimeVal::from(self.0.ru_stime)
294     }
295 
296     /// The resident set size at its peak,
297     #[cfg_attr(apple_targets, doc = " in bytes.")]
298     #[cfg_attr(not(apple_targets), doc = " in kilobytes.")]
max_rss(&self) -> c_long299     pub fn max_rss(&self) -> c_long {
300         self.0.ru_maxrss
301     }
302 
303     /// Integral value expressed in kilobytes times ticks of execution indicating
304     /// the amount of text memory shared with other processes.
shared_integral(&self) -> c_long305     pub fn shared_integral(&self) -> c_long {
306         self.0.ru_ixrss
307     }
308 
309     /// Integral value expressed in kilobytes times ticks of execution indicating
310     /// the amount of unshared memory used by data.
unshared_data_integral(&self) -> c_long311     pub fn unshared_data_integral(&self) -> c_long {
312         self.0.ru_idrss
313     }
314 
315     /// Integral value expressed in kilobytes times ticks of execution indicating
316     /// the amount of unshared memory used for stack space.
unshared_stack_integral(&self) -> c_long317     pub fn unshared_stack_integral(&self) -> c_long {
318         self.0.ru_isrss
319     }
320 
321     /// Number of page faults that were served without resorting to I/O, with pages
322     /// that have been allocated previously by the kernel.
minor_page_faults(&self) -> c_long323     pub fn minor_page_faults(&self) -> c_long {
324         self.0.ru_minflt
325     }
326 
327     /// Number of page faults that were served through I/O (i.e. swap).
major_page_faults(&self) -> c_long328     pub fn major_page_faults(&self) -> c_long {
329         self.0.ru_majflt
330     }
331 
332     /// Number of times all of the memory was fully swapped out.
full_swaps(&self) -> c_long333     pub fn full_swaps(&self) -> c_long {
334         self.0.ru_nswap
335     }
336 
337     /// Number of times a read was done from a block device.
block_reads(&self) -> c_long338     pub fn block_reads(&self) -> c_long {
339         self.0.ru_inblock
340     }
341 
342     /// Number of times a write was done to a block device.
block_writes(&self) -> c_long343     pub fn block_writes(&self) -> c_long {
344         self.0.ru_oublock
345     }
346 
347     /// Number of IPC messages sent.
ipc_sends(&self) -> c_long348     pub fn ipc_sends(&self) -> c_long {
349         self.0.ru_msgsnd
350     }
351 
352     /// Number of IPC messages received.
ipc_receives(&self) -> c_long353     pub fn ipc_receives(&self) -> c_long {
354         self.0.ru_msgrcv
355     }
356 
357     /// Number of signals received.
signals(&self) -> c_long358     pub fn signals(&self) -> c_long {
359         self.0.ru_nsignals
360     }
361 
362     /// Number of times a context switch was voluntarily invoked.
voluntary_context_switches(&self) -> c_long363     pub fn voluntary_context_switches(&self) -> c_long {
364         self.0.ru_nvcsw
365     }
366 
367     /// Number of times a context switch was imposed by the kernel (usually due to
368     /// time slice expiring or preemption by a higher priority process).
involuntary_context_switches(&self) -> c_long369     pub fn involuntary_context_switches(&self) -> c_long {
370         self.0.ru_nivcsw
371     }
372 }
373 
374 /// Get usage information for a process, its children or the current thread
375 ///
376 /// Real time information can be obtained for either the current process or (in some
377 /// systems) thread, but information about children processes is only provided for
378 /// those that have terminated and been waited for (see [`super::wait::wait`]).
379 ///
380 /// Some information may be missing depending on the platform, and the way information
381 /// is provided for children may also vary. Check the manuals for details.
382 ///
383 /// # References
384 ///
385 /// * [getrusage(2)](https://pubs.opengroup.org/onlinepubs/009696699/functions/getrusage.html)
386 /// * [Linux](https://man7.org/linux/man-pages/man2/getrusage.2.html)
387 /// * [FreeBSD](https://www.freebsd.org/cgi/man.cgi?query=getrusage)
388 /// * [NetBSD](https://man.netbsd.org/getrusage.2)
389 /// * [MacOS](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/getrusage.2.html)
390 ///
391 /// [`UsageWho`]: enum.UsageWho.html
392 ///
393 /// Note: `getrusage` provides a safe wrapper to libc's [`libc::getrusage`].
getrusage(who: UsageWho) -> Result<Usage>394 pub fn getrusage(who: UsageWho) -> Result<Usage> {
395     unsafe {
396         let mut rusage = mem::MaybeUninit::<rusage>::uninit();
397         let res = libc::getrusage(who as c_int, rusage.as_mut_ptr());
398         Errno::result(res).map(|_| Usage(rusage.assume_init()))
399     }
400 }
401