summaryrefslogtreecommitdiffstats
path: root/third_party/rust/nix/src/sys/resource.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /third_party/rust/nix/src/sys/resource.rs
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/nix/src/sys/resource.rs')
-rw-r--r--third_party/rust/nix/src/sys/resource.rs447
1 files changed, 447 insertions, 0 deletions
diff --git a/third_party/rust/nix/src/sys/resource.rs b/third_party/rust/nix/src/sys/resource.rs
new file mode 100644
index 0000000000..f42d32e3ca
--- /dev/null
+++ b/third_party/rust/nix/src/sys/resource.rs
@@ -0,0 +1,447 @@
+//! Configure the process resource limits.
+use cfg_if::cfg_if;
+use libc::{c_int, c_long, rusage};
+
+use crate::errno::Errno;
+use crate::sys::time::TimeVal;
+use crate::Result;
+pub use libc::rlim_t;
+pub use libc::RLIM_INFINITY;
+use std::mem;
+
+cfg_if! {
+ if #[cfg(all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")))]{
+ use libc::{__rlimit_resource_t, rlimit};
+ } else if #[cfg(any(
+ target_os = "freebsd",
+ target_os = "openbsd",
+ target_os = "netbsd",
+ target_os = "macos",
+ target_os = "ios",
+ target_os = "android",
+ target_os = "dragonfly",
+ target_os = "aix",
+ all(target_os = "linux", not(target_env = "gnu"))
+ ))]{
+ use libc::rlimit;
+ }
+}
+
+libc_enum! {
+ /// Types of process resources.
+ ///
+ /// The Resource enum is platform dependent. Check different platform
+ /// manuals for more details. Some platform links have been provided for
+ /// easier reference (non-exhaustive).
+ ///
+ /// * [Linux](https://man7.org/linux/man-pages/man2/getrlimit.2.html)
+ /// * [FreeBSD](https://www.freebsd.org/cgi/man.cgi?query=setrlimit)
+ /// * [NetBSD](https://man.netbsd.org/setrlimit.2)
+
+ // linux-gnu uses u_int as resource enum, which is implemented in libc as
+ // well.
+ //
+ // https://gcc.gnu.org/legacy-ml/gcc/2015-08/msg00441.html
+ // https://github.com/rust-lang/libc/blob/master/src/unix/linux_like/linux/gnu/mod.rs
+ #[cfg_attr(all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")), repr(u32))]
+ #[cfg_attr(any(
+ target_os = "freebsd",
+ target_os = "openbsd",
+ target_os = "netbsd",
+ target_os = "macos",
+ target_os = "ios",
+ target_os = "android",
+ target_os = "dragonfly",
+ target_os = "aix",
+ all(target_os = "linux", not(any(target_env = "gnu", target_env = "uclibc")))
+ ), repr(i32))]
+ #[non_exhaustive]
+ pub enum Resource {
+ #[cfg(not(any(target_os = "freebsd", target_os = "netbsd", target_os = "openbsd")))]
+ #[cfg_attr(docsrs, doc(cfg(all())))]
+ /// The maximum amount (in bytes) of virtual memory the process is
+ /// allowed to map.
+ RLIMIT_AS,
+ /// The largest size (in bytes) core(5) file that may be created.
+ RLIMIT_CORE,
+ /// The maximum amount of cpu time (in seconds) to be used by each
+ /// process.
+ RLIMIT_CPU,
+ /// The maximum size (in bytes) of the data segment for a process
+ RLIMIT_DATA,
+ /// The largest size (in bytes) file that may be created.
+ RLIMIT_FSIZE,
+ /// The maximum number of open files for this process.
+ RLIMIT_NOFILE,
+ /// The maximum size (in bytes) of the stack segment for a process.
+ RLIMIT_STACK,
+
+ #[cfg(target_os = "freebsd")]
+ #[cfg_attr(docsrs, doc(cfg(all())))]
+ /// The maximum number of kqueues this user id is allowed to create.
+ RLIMIT_KQUEUES,
+
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ #[cfg_attr(docsrs, doc(cfg(all())))]
+ /// A limit on the combined number of flock locks and fcntl leases that
+ /// this process may establish.
+ RLIMIT_LOCKS,
+
+ #[cfg(any(
+ target_os = "android",
+ target_os = "freebsd",
+ target_os = "openbsd",
+ target_os = "linux",
+ target_os = "netbsd"
+ ))]
+ #[cfg_attr(docsrs, doc(cfg(all())))]
+ /// The maximum size (in bytes) which a process may lock into memory
+ /// using the mlock(2) system call.
+ RLIMIT_MEMLOCK,
+
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ #[cfg_attr(docsrs, doc(cfg(all())))]
+ /// A limit on the number of bytes that can be allocated for POSIX
+ /// message queues for the real user ID of the calling process.
+ RLIMIT_MSGQUEUE,
+
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ #[cfg_attr(docsrs, doc(cfg(all())))]
+ /// A ceiling to which the process's nice value can be raised using
+ /// setpriority or nice.
+ RLIMIT_NICE,
+
+ #[cfg(any(
+ target_os = "android",
+ target_os = "freebsd",
+ target_os = "netbsd",
+ target_os = "openbsd",
+ target_os = "linux",
+ target_os = "aix",
+ ))]
+ #[cfg_attr(docsrs, doc(cfg(all())))]
+ /// The maximum number of simultaneous processes for this user id.
+ RLIMIT_NPROC,
+
+ #[cfg(target_os = "freebsd")]
+ #[cfg_attr(docsrs, doc(cfg(all())))]
+ /// The maximum number of pseudo-terminals this user id is allowed to
+ /// create.
+ RLIMIT_NPTS,
+
+ #[cfg(any(target_os = "android",
+ target_os = "freebsd",
+ target_os = "netbsd",
+ target_os = "openbsd",
+ target_os = "linux",
+ target_os = "aix",
+ ))]
+ #[cfg_attr(docsrs, doc(cfg(all())))]
+ /// When there is memory pressure and swap is available, prioritize
+ /// eviction of a process' resident pages beyond this amount (in bytes).
+ RLIMIT_RSS,
+
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ #[cfg_attr(docsrs, doc(cfg(all())))]
+ /// A ceiling on the real-time priority that may be set for this process
+ /// using sched_setscheduler and sched_set‐ param.
+ RLIMIT_RTPRIO,
+
+ #[cfg(any(target_os = "linux"))]
+ #[cfg_attr(docsrs, doc(cfg(all())))]
+ /// A limit (in microseconds) on the amount of CPU time that a process
+ /// scheduled under a real-time scheduling policy may con‐ sume without
+ /// making a blocking system call.
+ RLIMIT_RTTIME,
+
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ #[cfg_attr(docsrs, doc(cfg(all())))]
+ /// A limit on the number of signals that may be queued for the real
+ /// user ID of the calling process.
+ RLIMIT_SIGPENDING,
+
+ #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
+ #[cfg_attr(docsrs, doc(cfg(all())))]
+ /// The maximum size (in bytes) of socket buffer usage for this user.
+ RLIMIT_SBSIZE,
+
+ #[cfg(target_os = "freebsd")]
+ #[cfg_attr(docsrs, doc(cfg(all())))]
+ /// The maximum size (in bytes) of the swap space that may be reserved
+ /// or used by all of this user id's processes.
+ RLIMIT_SWAP,
+
+ #[cfg(target_os = "freebsd")]
+ #[cfg_attr(docsrs, doc(cfg(all())))]
+ /// An alias for RLIMIT_AS.
+ RLIMIT_VMEM,
+ }
+}
+
+/// Get the current processes resource limits
+///
+/// The special value [`RLIM_INFINITY`] indicates that no limit will be
+/// enforced.
+///
+/// # Parameters
+///
+/// * `resource`: The [`Resource`] that we want to get the limits of.
+///
+/// # Examples
+///
+/// ```
+/// # use nix::sys::resource::{getrlimit, Resource};
+///
+/// let (soft_limit, hard_limit) = getrlimit(Resource::RLIMIT_NOFILE).unwrap();
+/// println!("current soft_limit: {}", soft_limit);
+/// println!("current hard_limit: {}", hard_limit);
+/// ```
+///
+/// # References
+///
+/// [getrlimit(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getrlimit.html#tag_16_215)
+///
+/// [`Resource`]: enum.Resource.html
+pub fn getrlimit(resource: Resource) -> Result<(rlim_t, rlim_t)> {
+ let mut old_rlim = mem::MaybeUninit::<rlimit>::uninit();
+
+ cfg_if! {
+ if #[cfg(all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")))]{
+ let res = unsafe { libc::getrlimit(resource as __rlimit_resource_t, old_rlim.as_mut_ptr()) };
+ } else {
+ let res = unsafe { libc::getrlimit(resource as c_int, old_rlim.as_mut_ptr()) };
+ }
+ }
+
+ Errno::result(res).map(|_| {
+ let rlimit { rlim_cur, rlim_max } = unsafe { old_rlim.assume_init() };
+ (rlim_cur, rlim_max)
+ })
+}
+
+/// Set the current processes resource limits
+///
+/// # Parameters
+///
+/// * `resource`: The [`Resource`] that we want to set the limits of.
+/// * `soft_limit`: The value that the kernel enforces for the corresponding
+/// resource.
+/// * `hard_limit`: The ceiling for the soft limit. Must be lower or equal to
+/// the current hard limit for non-root users.
+///
+/// The special value [`RLIM_INFINITY`] indicates that no limit will be
+/// enforced.
+///
+/// # Examples
+///
+/// ```
+/// # use nix::sys::resource::{setrlimit, Resource};
+///
+/// let soft_limit = 512;
+/// let hard_limit = 1024;
+/// setrlimit(Resource::RLIMIT_NOFILE, soft_limit, hard_limit).unwrap();
+/// ```
+///
+/// # References
+///
+/// [setrlimit(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getrlimit.html#tag_16_215)
+///
+/// [`Resource`]: enum.Resource.html
+///
+/// Note: `setrlimit` provides a safe wrapper to libc's `setrlimit`.
+pub fn setrlimit(
+ resource: Resource,
+ soft_limit: rlim_t,
+ hard_limit: rlim_t,
+) -> Result<()> {
+ let new_rlim = rlimit {
+ rlim_cur: soft_limit,
+ rlim_max: hard_limit,
+ };
+ cfg_if! {
+ if #[cfg(all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")))]{
+ let res = unsafe { libc::setrlimit(resource as __rlimit_resource_t, &new_rlim as *const rlimit) };
+ }else{
+ let res = unsafe { libc::setrlimit(resource as c_int, &new_rlim as *const rlimit) };
+ }
+ }
+
+ Errno::result(res).map(drop)
+}
+
+libc_enum! {
+ /// Whose resource usage should be returned by [`getrusage`].
+ #[repr(i32)]
+ #[non_exhaustive]
+ pub enum UsageWho {
+ /// Resource usage for the current process.
+ RUSAGE_SELF,
+
+ /// Resource usage for all the children that have terminated and been waited for.
+ RUSAGE_CHILDREN,
+
+ #[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "openbsd"))]
+ #[cfg_attr(docsrs, doc(cfg(all())))]
+ /// Resource usage for the calling thread.
+ RUSAGE_THREAD,
+ }
+}
+
+/// Output of `getrusage` with information about resource usage. Some of the fields
+/// may be unused in some platforms, and will be always zeroed out. See their manuals
+/// for details.
+#[repr(transparent)]
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+pub struct Usage(rusage);
+
+impl AsRef<rusage> for Usage {
+ fn as_ref(&self) -> &rusage {
+ &self.0
+ }
+}
+
+impl AsMut<rusage> for Usage {
+ fn as_mut(&mut self) -> &mut rusage {
+ &mut self.0
+ }
+}
+
+impl Usage {
+ /// Total amount of time spent executing in user mode.
+ pub fn user_time(&self) -> TimeVal {
+ TimeVal::from(self.0.ru_utime)
+ }
+
+ /// Total amount of time spent executing in kernel mode.
+ pub fn system_time(&self) -> TimeVal {
+ TimeVal::from(self.0.ru_stime)
+ }
+
+ /// The resident set size at its peak, in kilobytes.
+ pub fn max_rss(&self) -> c_long {
+ self.0.ru_maxrss
+ }
+
+ /// Integral value expressed in kilobytes times ticks of execution indicating
+ /// the amount of text memory shared with other processes.
+ pub fn shared_integral(&self) -> c_long {
+ self.0.ru_ixrss
+ }
+
+ /// Integral value expressed in kilobytes times ticks of execution indicating
+ /// the amount of unshared memory used by data.
+ pub fn unshared_data_integral(&self) -> c_long {
+ self.0.ru_idrss
+ }
+
+ /// Integral value expressed in kilobytes times ticks of execution indicating
+ /// the amount of unshared memory used for stack space.
+ pub fn unshared_stack_integral(&self) -> c_long {
+ self.0.ru_isrss
+ }
+
+ /// Number of page faults that were served without resorting to I/O, with pages
+ /// that have been allocated previously by the kernel.
+ pub fn minor_page_faults(&self) -> c_long {
+ self.0.ru_minflt
+ }
+
+ /// Number of page faults that were served through I/O (i.e. swap).
+ pub fn major_page_faults(&self) -> c_long {
+ self.0.ru_majflt
+ }
+
+ /// Number of times all of the memory was fully swapped out.
+ pub fn full_swaps(&self) -> c_long {
+ self.0.ru_nswap
+ }
+
+ /// Number of times a read was done from a block device.
+ pub fn block_reads(&self) -> c_long {
+ self.0.ru_inblock
+ }
+
+ /// Number of times a write was done to a block device.
+ pub fn block_writes(&self) -> c_long {
+ self.0.ru_oublock
+ }
+
+ /// Number of IPC messages sent.
+ pub fn ipc_sends(&self) -> c_long {
+ self.0.ru_msgsnd
+ }
+
+ /// Number of IPC messages received.
+ pub fn ipc_receives(&self) -> c_long {
+ self.0.ru_msgrcv
+ }
+
+ /// Number of signals received.
+ pub fn signals(&self) -> c_long {
+ self.0.ru_nsignals
+ }
+
+ /// Number of times a context switch was voluntarily invoked.
+ pub fn voluntary_context_switches(&self) -> c_long {
+ self.0.ru_nvcsw
+ }
+
+ /// Number of times a context switch was imposed by the kernel (usually due to
+ /// time slice expiring or preemption by a higher priority process).
+ pub fn involuntary_context_switches(&self) -> c_long {
+ self.0.ru_nivcsw
+ }
+}
+
+/// Get usage information for a process, its children or the current thread
+///
+/// Real time information can be obtained for either the current process or (in some
+/// systems) thread, but information about children processes is only provided for
+/// those that have terminated and been waited for (see [`super::wait::wait`]).
+///
+/// Some information may be missing depending on the platform, and the way information
+/// is provided for children may also vary. Check the manuals for details.
+///
+/// # References
+///
+/// * [getrusage(2)](https://pubs.opengroup.org/onlinepubs/009696699/functions/getrusage.html)
+/// * [Linux](https://man7.org/linux/man-pages/man2/getrusage.2.html)
+/// * [FreeBSD](https://www.freebsd.org/cgi/man.cgi?query=getrusage)
+/// * [NetBSD](https://man.netbsd.org/getrusage.2)
+/// * [MacOS](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/getrusage.2.html)
+///
+/// [`UsageWho`]: enum.UsageWho.html
+///
+/// Note: `getrusage` provides a safe wrapper to libc's [`libc::getrusage`].
+pub fn getrusage(who: UsageWho) -> Result<Usage> {
+ unsafe {
+ let mut rusage = mem::MaybeUninit::<rusage>::uninit();
+ let res = libc::getrusage(who as c_int, rusage.as_mut_ptr());
+ Errno::result(res).map(|_| Usage(rusage.assume_init()))
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::{getrusage, UsageWho};
+
+ #[test]
+ pub fn test_self_cpu_time() {
+ // Make sure some CPU time is used.
+ let mut numbers: Vec<i32> = (1..1_000_000).collect();
+ numbers.iter_mut().for_each(|item| *item *= 2);
+
+ // FIXME: this is here to help ensure the compiler does not optimize the whole
+ // thing away. Replace the assert with test::black_box once stabilized.
+ assert_eq!(numbers[100..200].iter().sum::<i32>(), 30_100);
+
+ let usage = getrusage(UsageWho::RUSAGE_SELF)
+ .expect("Failed to call getrusage for SELF");
+ let rusage = usage.as_ref();
+
+ let user = usage.user_time();
+ assert!(user.tv_sec() > 0 || user.tv_usec() > 0);
+ assert_eq!(user.tv_sec(), rusage.ru_utime.tv_sec);
+ assert_eq!(user.tv_usec(), rusage.ru_utime.tv_usec);
+ }
+}