13da5c369Sopenharmony_ci//! Configure the process resource limits.
23da5c369Sopenharmony_ciuse cfg_if::cfg_if;
33da5c369Sopenharmony_ciuse libc::{c_int, c_long, rusage};
43da5c369Sopenharmony_ci
53da5c369Sopenharmony_ciuse crate::errno::Errno;
63da5c369Sopenharmony_ciuse crate::sys::time::TimeVal;
73da5c369Sopenharmony_ciuse crate::Result;
83da5c369Sopenharmony_cipub use libc::rlim_t;
93da5c369Sopenharmony_cipub use libc::RLIM_INFINITY;
103da5c369Sopenharmony_ciuse std::mem;
113da5c369Sopenharmony_ci
123da5c369Sopenharmony_cicfg_if! {
133da5c369Sopenharmony_ci    if #[cfg(all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")))]{
143da5c369Sopenharmony_ci        use libc::{__rlimit_resource_t, rlimit};
153da5c369Sopenharmony_ci    } else if #[cfg(any(
163da5c369Sopenharmony_ci        target_os = "freebsd",
173da5c369Sopenharmony_ci        target_os = "openbsd",
183da5c369Sopenharmony_ci        target_os = "netbsd",
193da5c369Sopenharmony_ci        target_os = "macos",
203da5c369Sopenharmony_ci        target_os = "ios",
213da5c369Sopenharmony_ci        target_os = "android",
223da5c369Sopenharmony_ci        target_os = "dragonfly",
233da5c369Sopenharmony_ci        all(target_os = "linux", not(target_env = "gnu"))
243da5c369Sopenharmony_ci    ))]{
253da5c369Sopenharmony_ci        use libc::rlimit;
263da5c369Sopenharmony_ci    }
273da5c369Sopenharmony_ci}
283da5c369Sopenharmony_ci
293da5c369Sopenharmony_cilibc_enum! {
303da5c369Sopenharmony_ci    /// Types of process resources.
313da5c369Sopenharmony_ci    ///
323da5c369Sopenharmony_ci    /// The Resource enum is platform dependent. Check different platform
333da5c369Sopenharmony_ci    /// manuals for more details. Some platform links have been provided for
343da5c369Sopenharmony_ci    /// easier reference (non-exhaustive).
353da5c369Sopenharmony_ci    ///
363da5c369Sopenharmony_ci    /// * [Linux](https://man7.org/linux/man-pages/man2/getrlimit.2.html)
373da5c369Sopenharmony_ci    /// * [FreeBSD](https://www.freebsd.org/cgi/man.cgi?query=setrlimit)
383da5c369Sopenharmony_ci    /// * [NetBSD](https://man.netbsd.org/setrlimit.2)
393da5c369Sopenharmony_ci
403da5c369Sopenharmony_ci    // linux-gnu uses u_int as resource enum, which is implemented in libc as
413da5c369Sopenharmony_ci    // well.
423da5c369Sopenharmony_ci    //
433da5c369Sopenharmony_ci    // https://gcc.gnu.org/legacy-ml/gcc/2015-08/msg00441.html
443da5c369Sopenharmony_ci    // https://github.com/rust-lang/libc/blob/master/src/unix/linux_like/linux/gnu/mod.rs
453da5c369Sopenharmony_ci    #[cfg_attr(all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")), repr(u32))]
463da5c369Sopenharmony_ci    #[cfg_attr(any(
473da5c369Sopenharmony_ci            target_os = "freebsd",
483da5c369Sopenharmony_ci            target_os = "openbsd",
493da5c369Sopenharmony_ci            target_os = "netbsd",
503da5c369Sopenharmony_ci            target_os = "macos",
513da5c369Sopenharmony_ci            target_os = "ios",
523da5c369Sopenharmony_ci            target_os = "android",
533da5c369Sopenharmony_ci            target_os = "dragonfly",
543da5c369Sopenharmony_ci            all(target_os = "linux", not(any(target_env = "gnu", target_env = "uclibc")))
553da5c369Sopenharmony_ci        ), repr(i32))]
563da5c369Sopenharmony_ci    #[non_exhaustive]
573da5c369Sopenharmony_ci    pub enum Resource {
583da5c369Sopenharmony_ci        #[cfg(not(any(target_os = "freebsd", target_os = "netbsd", target_os = "openbsd")))]
593da5c369Sopenharmony_ci        #[cfg_attr(docsrs, doc(cfg(all())))]
603da5c369Sopenharmony_ci        /// The maximum amount (in bytes) of virtual memory the process is
613da5c369Sopenharmony_ci        /// allowed to map.
623da5c369Sopenharmony_ci        RLIMIT_AS,
633da5c369Sopenharmony_ci        /// The largest size (in bytes) core(5) file that may be created.
643da5c369Sopenharmony_ci        RLIMIT_CORE,
653da5c369Sopenharmony_ci        /// The maximum amount of cpu time (in seconds) to be used by each
663da5c369Sopenharmony_ci        /// process.
673da5c369Sopenharmony_ci        RLIMIT_CPU,
683da5c369Sopenharmony_ci        /// The maximum size (in bytes) of the data segment for a process
693da5c369Sopenharmony_ci        RLIMIT_DATA,
703da5c369Sopenharmony_ci        /// The largest size (in bytes) file that may be created.
713da5c369Sopenharmony_ci        RLIMIT_FSIZE,
723da5c369Sopenharmony_ci        /// The maximum number of open files for this process.
733da5c369Sopenharmony_ci        RLIMIT_NOFILE,
743da5c369Sopenharmony_ci        /// The maximum size (in bytes) of the stack segment for a process.
753da5c369Sopenharmony_ci        RLIMIT_STACK,
763da5c369Sopenharmony_ci
773da5c369Sopenharmony_ci        #[cfg(target_os = "freebsd")]
783da5c369Sopenharmony_ci        #[cfg_attr(docsrs, doc(cfg(all())))]
793da5c369Sopenharmony_ci        /// The maximum number of kqueues this user id is allowed to create.
803da5c369Sopenharmony_ci        RLIMIT_KQUEUES,
813da5c369Sopenharmony_ci
823da5c369Sopenharmony_ci        #[cfg(any(target_os = "android", target_os = "linux"))]
833da5c369Sopenharmony_ci        #[cfg_attr(docsrs, doc(cfg(all())))]
843da5c369Sopenharmony_ci        /// A limit on the combined number of flock locks and fcntl leases that
853da5c369Sopenharmony_ci        /// this process may establish.
863da5c369Sopenharmony_ci        RLIMIT_LOCKS,
873da5c369Sopenharmony_ci
883da5c369Sopenharmony_ci        #[cfg(any(
893da5c369Sopenharmony_ci            target_os = "android",
903da5c369Sopenharmony_ci            target_os = "freebsd",
913da5c369Sopenharmony_ci            target_os = "openbsd",
923da5c369Sopenharmony_ci            target_os = "linux",
933da5c369Sopenharmony_ci            target_os = "netbsd"
943da5c369Sopenharmony_ci        ))]
953da5c369Sopenharmony_ci        #[cfg_attr(docsrs, doc(cfg(all())))]
963da5c369Sopenharmony_ci        /// The maximum size (in bytes) which a process may lock into memory
973da5c369Sopenharmony_ci        /// using the mlock(2) system call.
983da5c369Sopenharmony_ci        RLIMIT_MEMLOCK,
993da5c369Sopenharmony_ci
1003da5c369Sopenharmony_ci        #[cfg(any(target_os = "android", target_os = "linux"))]
1013da5c369Sopenharmony_ci        #[cfg_attr(docsrs, doc(cfg(all())))]
1023da5c369Sopenharmony_ci        /// A limit on the number of bytes that can be allocated for POSIX
1033da5c369Sopenharmony_ci        /// message queues  for  the  real  user  ID  of  the  calling process.
1043da5c369Sopenharmony_ci        RLIMIT_MSGQUEUE,
1053da5c369Sopenharmony_ci
1063da5c369Sopenharmony_ci        #[cfg(any(target_os = "android", target_os = "linux"))]
1073da5c369Sopenharmony_ci        #[cfg_attr(docsrs, doc(cfg(all())))]
1083da5c369Sopenharmony_ci        /// A ceiling to which the process's nice value can be raised using
1093da5c369Sopenharmony_ci        /// setpriority or nice.
1103da5c369Sopenharmony_ci        RLIMIT_NICE,
1113da5c369Sopenharmony_ci
1123da5c369Sopenharmony_ci        #[cfg(any(
1133da5c369Sopenharmony_ci            target_os = "android",
1143da5c369Sopenharmony_ci            target_os = "freebsd",
1153da5c369Sopenharmony_ci            target_os = "netbsd",
1163da5c369Sopenharmony_ci            target_os = "openbsd",
1173da5c369Sopenharmony_ci            target_os = "linux",
1183da5c369Sopenharmony_ci        ))]
1193da5c369Sopenharmony_ci        #[cfg_attr(docsrs, doc(cfg(all())))]
1203da5c369Sopenharmony_ci        /// The maximum number of simultaneous processes for this user id.
1213da5c369Sopenharmony_ci        RLIMIT_NPROC,
1223da5c369Sopenharmony_ci
1233da5c369Sopenharmony_ci        #[cfg(target_os = "freebsd")]
1243da5c369Sopenharmony_ci        #[cfg_attr(docsrs, doc(cfg(all())))]
1253da5c369Sopenharmony_ci        /// The maximum number of pseudo-terminals this user id is allowed to
1263da5c369Sopenharmony_ci        /// create.
1273da5c369Sopenharmony_ci        RLIMIT_NPTS,
1283da5c369Sopenharmony_ci
1293da5c369Sopenharmony_ci        #[cfg(any(target_os = "android",
1303da5c369Sopenharmony_ci            target_os = "freebsd",
1313da5c369Sopenharmony_ci            target_os = "netbsd",
1323da5c369Sopenharmony_ci            target_os = "openbsd",
1333da5c369Sopenharmony_ci            target_os = "linux",
1343da5c369Sopenharmony_ci        ))]
1353da5c369Sopenharmony_ci        #[cfg_attr(docsrs, doc(cfg(all())))]
1363da5c369Sopenharmony_ci        /// When there is memory pressure and swap is available, prioritize
1373da5c369Sopenharmony_ci        /// eviction of a process' resident pages beyond this amount (in bytes).
1383da5c369Sopenharmony_ci        RLIMIT_RSS,
1393da5c369Sopenharmony_ci
1403da5c369Sopenharmony_ci        #[cfg(any(target_os = "android", target_os = "linux"))]
1413da5c369Sopenharmony_ci        #[cfg_attr(docsrs, doc(cfg(all())))]
1423da5c369Sopenharmony_ci        /// A ceiling on the real-time priority that may be set for this process
1433da5c369Sopenharmony_ci        /// using sched_setscheduler and  sched_set‐ param.
1443da5c369Sopenharmony_ci        RLIMIT_RTPRIO,
1453da5c369Sopenharmony_ci
1463da5c369Sopenharmony_ci        #[cfg(any(target_os = "linux"))]
1473da5c369Sopenharmony_ci        #[cfg_attr(docsrs, doc(cfg(all())))]
1483da5c369Sopenharmony_ci        /// A limit (in microseconds) on the amount of CPU time that a process
1493da5c369Sopenharmony_ci        /// scheduled under a real-time scheduling policy may con‐ sume without
1503da5c369Sopenharmony_ci        /// making a blocking system call.
1513da5c369Sopenharmony_ci        RLIMIT_RTTIME,
1523da5c369Sopenharmony_ci
1533da5c369Sopenharmony_ci        #[cfg(any(target_os = "android", target_os = "linux"))]
1543da5c369Sopenharmony_ci        #[cfg_attr(docsrs, doc(cfg(all())))]
1553da5c369Sopenharmony_ci        /// A limit on the number of signals that may be queued for the real
1563da5c369Sopenharmony_ci        /// user ID of the  calling  process.
1573da5c369Sopenharmony_ci        RLIMIT_SIGPENDING,
1583da5c369Sopenharmony_ci
1593da5c369Sopenharmony_ci        #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
1603da5c369Sopenharmony_ci        #[cfg_attr(docsrs, doc(cfg(all())))]
1613da5c369Sopenharmony_ci        /// The maximum size (in bytes) of socket buffer usage for this user.
1623da5c369Sopenharmony_ci        RLIMIT_SBSIZE,
1633da5c369Sopenharmony_ci
1643da5c369Sopenharmony_ci        #[cfg(target_os = "freebsd")]
1653da5c369Sopenharmony_ci        #[cfg_attr(docsrs, doc(cfg(all())))]
1663da5c369Sopenharmony_ci        /// The maximum size (in bytes) of the swap space that may be reserved
1673da5c369Sopenharmony_ci        /// or used by all of this user id's processes.
1683da5c369Sopenharmony_ci        RLIMIT_SWAP,
1693da5c369Sopenharmony_ci
1703da5c369Sopenharmony_ci        #[cfg(target_os = "freebsd")]
1713da5c369Sopenharmony_ci        #[cfg_attr(docsrs, doc(cfg(all())))]
1723da5c369Sopenharmony_ci        /// An alias for RLIMIT_AS.
1733da5c369Sopenharmony_ci        RLIMIT_VMEM,
1743da5c369Sopenharmony_ci    }
1753da5c369Sopenharmony_ci}
1763da5c369Sopenharmony_ci
1773da5c369Sopenharmony_ci/// Get the current processes resource limits
1783da5c369Sopenharmony_ci///
1793da5c369Sopenharmony_ci/// The special value [`RLIM_INFINITY`] indicates that no limit will be
1803da5c369Sopenharmony_ci/// enforced.
1813da5c369Sopenharmony_ci///
1823da5c369Sopenharmony_ci/// # Parameters
1833da5c369Sopenharmony_ci///
1843da5c369Sopenharmony_ci/// * `resource`: The [`Resource`] that we want to get the limits of.
1853da5c369Sopenharmony_ci///
1863da5c369Sopenharmony_ci/// # Examples
1873da5c369Sopenharmony_ci///
1883da5c369Sopenharmony_ci/// ```
1893da5c369Sopenharmony_ci/// # use nix::sys::resource::{getrlimit, Resource};
1903da5c369Sopenharmony_ci///
1913da5c369Sopenharmony_ci/// let (soft_limit, hard_limit) = getrlimit(Resource::RLIMIT_NOFILE).unwrap();
1923da5c369Sopenharmony_ci/// println!("current soft_limit: {}", soft_limit);
1933da5c369Sopenharmony_ci/// println!("current hard_limit: {}", hard_limit);
1943da5c369Sopenharmony_ci/// ```
1953da5c369Sopenharmony_ci///
1963da5c369Sopenharmony_ci/// # References
1973da5c369Sopenharmony_ci///
1983da5c369Sopenharmony_ci/// [getrlimit(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getrlimit.html#tag_16_215)
1993da5c369Sopenharmony_ci///
2003da5c369Sopenharmony_ci/// [`Resource`]: enum.Resource.html
2013da5c369Sopenharmony_cipub fn getrlimit(resource: Resource) -> Result<(rlim_t, rlim_t)> {
2023da5c369Sopenharmony_ci    let mut old_rlim = mem::MaybeUninit::<rlimit>::uninit();
2033da5c369Sopenharmony_ci
2043da5c369Sopenharmony_ci    cfg_if! {
2053da5c369Sopenharmony_ci        if #[cfg(all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")))]{
2063da5c369Sopenharmony_ci            let res = unsafe { libc::getrlimit(resource as __rlimit_resource_t, old_rlim.as_mut_ptr()) };
2073da5c369Sopenharmony_ci        } else {
2083da5c369Sopenharmony_ci            let res = unsafe { libc::getrlimit(resource as c_int, old_rlim.as_mut_ptr()) };
2093da5c369Sopenharmony_ci        }
2103da5c369Sopenharmony_ci    }
2113da5c369Sopenharmony_ci
2123da5c369Sopenharmony_ci    Errno::result(res).map(|_| {
2133da5c369Sopenharmony_ci        let rlimit { rlim_cur, rlim_max } = unsafe { old_rlim.assume_init() };
2143da5c369Sopenharmony_ci        (rlim_cur, rlim_max)
2153da5c369Sopenharmony_ci    })
2163da5c369Sopenharmony_ci}
2173da5c369Sopenharmony_ci
2183da5c369Sopenharmony_ci/// Set the current processes resource limits
2193da5c369Sopenharmony_ci///
2203da5c369Sopenharmony_ci/// # Parameters
2213da5c369Sopenharmony_ci///
2223da5c369Sopenharmony_ci/// * `resource`: The [`Resource`] that we want to set the limits of.
2233da5c369Sopenharmony_ci/// * `soft_limit`: The value that the kernel enforces for the corresponding
2243da5c369Sopenharmony_ci///   resource.
2253da5c369Sopenharmony_ci/// * `hard_limit`: The ceiling for the soft limit. Must be lower or equal to
2263da5c369Sopenharmony_ci///   the current hard limit for non-root users.
2273da5c369Sopenharmony_ci///
2283da5c369Sopenharmony_ci/// The special value [`RLIM_INFINITY`] indicates that no limit will be
2293da5c369Sopenharmony_ci/// enforced.
2303da5c369Sopenharmony_ci///
2313da5c369Sopenharmony_ci/// # Examples
2323da5c369Sopenharmony_ci///
2333da5c369Sopenharmony_ci/// ```
2343da5c369Sopenharmony_ci/// # use nix::sys::resource::{setrlimit, Resource};
2353da5c369Sopenharmony_ci///
2363da5c369Sopenharmony_ci/// let soft_limit = 512;
2373da5c369Sopenharmony_ci/// let hard_limit = 1024;
2383da5c369Sopenharmony_ci/// setrlimit(Resource::RLIMIT_NOFILE, soft_limit, hard_limit).unwrap();
2393da5c369Sopenharmony_ci/// ```
2403da5c369Sopenharmony_ci///
2413da5c369Sopenharmony_ci/// # References
2423da5c369Sopenharmony_ci///
2433da5c369Sopenharmony_ci/// [setrlimit(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getrlimit.html#tag_16_215)
2443da5c369Sopenharmony_ci///
2453da5c369Sopenharmony_ci/// [`Resource`]: enum.Resource.html
2463da5c369Sopenharmony_ci///
2473da5c369Sopenharmony_ci/// Note: `setrlimit` provides a safe wrapper to libc's `setrlimit`.
2483da5c369Sopenharmony_cipub fn setrlimit(
2493da5c369Sopenharmony_ci    resource: Resource,
2503da5c369Sopenharmony_ci    soft_limit: rlim_t,
2513da5c369Sopenharmony_ci    hard_limit: rlim_t,
2523da5c369Sopenharmony_ci) -> Result<()> {
2533da5c369Sopenharmony_ci    let new_rlim = rlimit {
2543da5c369Sopenharmony_ci        rlim_cur: soft_limit,
2553da5c369Sopenharmony_ci        rlim_max: hard_limit,
2563da5c369Sopenharmony_ci    };
2573da5c369Sopenharmony_ci    cfg_if! {
2583da5c369Sopenharmony_ci        if #[cfg(all(target_os = "linux", any(target_env = "gnu", target_env = "uclibc")))]{
2593da5c369Sopenharmony_ci            let res = unsafe { libc::setrlimit(resource as __rlimit_resource_t, &new_rlim as *const rlimit) };
2603da5c369Sopenharmony_ci        }else{
2613da5c369Sopenharmony_ci            let res = unsafe { libc::setrlimit(resource as c_int, &new_rlim as *const rlimit) };
2623da5c369Sopenharmony_ci        }
2633da5c369Sopenharmony_ci    }
2643da5c369Sopenharmony_ci
2653da5c369Sopenharmony_ci    Errno::result(res).map(drop)
2663da5c369Sopenharmony_ci}
2673da5c369Sopenharmony_ci
2683da5c369Sopenharmony_cilibc_enum! {
2693da5c369Sopenharmony_ci    /// Whose resource usage should be returned by [`getrusage`].
2703da5c369Sopenharmony_ci    #[repr(i32)]
2713da5c369Sopenharmony_ci    #[non_exhaustive]
2723da5c369Sopenharmony_ci    pub enum UsageWho {
2733da5c369Sopenharmony_ci        /// Resource usage for the current process.
2743da5c369Sopenharmony_ci        RUSAGE_SELF,
2753da5c369Sopenharmony_ci
2763da5c369Sopenharmony_ci        /// Resource usage for all the children that have terminated and been waited for.
2773da5c369Sopenharmony_ci        RUSAGE_CHILDREN,
2783da5c369Sopenharmony_ci
2793da5c369Sopenharmony_ci        #[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "openbsd"))]
2803da5c369Sopenharmony_ci        #[cfg_attr(docsrs, doc(cfg(all())))]
2813da5c369Sopenharmony_ci        /// Resource usage for the calling thread.
2823da5c369Sopenharmony_ci        RUSAGE_THREAD,
2833da5c369Sopenharmony_ci    }
2843da5c369Sopenharmony_ci}
2853da5c369Sopenharmony_ci
2863da5c369Sopenharmony_ci/// Output of `getrusage` with information about resource usage. Some of the fields
2873da5c369Sopenharmony_ci/// may be unused in some platforms, and will be always zeroed out. See their manuals
2883da5c369Sopenharmony_ci/// for details.
2893da5c369Sopenharmony_ci#[repr(transparent)]
2903da5c369Sopenharmony_ci#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
2913da5c369Sopenharmony_cipub struct Usage(rusage);
2923da5c369Sopenharmony_ci
2933da5c369Sopenharmony_ciimpl AsRef<rusage> for Usage {
2943da5c369Sopenharmony_ci    fn as_ref(&self) -> &rusage {
2953da5c369Sopenharmony_ci        &self.0
2963da5c369Sopenharmony_ci    }
2973da5c369Sopenharmony_ci}
2983da5c369Sopenharmony_ci
2993da5c369Sopenharmony_ciimpl AsMut<rusage> for Usage {
3003da5c369Sopenharmony_ci    fn as_mut(&mut self) -> &mut rusage {
3013da5c369Sopenharmony_ci        &mut self.0
3023da5c369Sopenharmony_ci    }
3033da5c369Sopenharmony_ci}
3043da5c369Sopenharmony_ci
3053da5c369Sopenharmony_ciimpl Usage {
3063da5c369Sopenharmony_ci    /// Total amount of time spent executing in user mode.
3073da5c369Sopenharmony_ci    pub fn user_time(&self) -> TimeVal {
3083da5c369Sopenharmony_ci        TimeVal::from(self.0.ru_utime)
3093da5c369Sopenharmony_ci    }
3103da5c369Sopenharmony_ci
3113da5c369Sopenharmony_ci    /// Total amount of time spent executing in kernel mode.
3123da5c369Sopenharmony_ci    pub fn system_time(&self) -> TimeVal {
3133da5c369Sopenharmony_ci        TimeVal::from(self.0.ru_stime)
3143da5c369Sopenharmony_ci    }
3153da5c369Sopenharmony_ci
3163da5c369Sopenharmony_ci    /// The resident set size at its peak, in kilobytes.
3173da5c369Sopenharmony_ci    pub fn max_rss(&self) -> c_long {
3183da5c369Sopenharmony_ci        self.0.ru_maxrss
3193da5c369Sopenharmony_ci    }
3203da5c369Sopenharmony_ci
3213da5c369Sopenharmony_ci    /// Integral value expressed in kilobytes times ticks of execution indicating
3223da5c369Sopenharmony_ci    /// the amount of text memory shared with other processes.
3233da5c369Sopenharmony_ci    pub fn shared_integral(&self) -> c_long {
3243da5c369Sopenharmony_ci        self.0.ru_ixrss
3253da5c369Sopenharmony_ci    }
3263da5c369Sopenharmony_ci
3273da5c369Sopenharmony_ci    /// Integral value expressed in kilobytes times ticks of execution indicating
3283da5c369Sopenharmony_ci    /// the amount of unshared memory used by data.
3293da5c369Sopenharmony_ci    pub fn unshared_data_integral(&self) -> c_long {
3303da5c369Sopenharmony_ci        self.0.ru_idrss
3313da5c369Sopenharmony_ci    }
3323da5c369Sopenharmony_ci
3333da5c369Sopenharmony_ci    /// Integral value expressed in kilobytes times ticks of execution indicating
3343da5c369Sopenharmony_ci    /// the amount of unshared memory used for stack space.
3353da5c369Sopenharmony_ci    pub fn unshared_stack_integral(&self) -> c_long {
3363da5c369Sopenharmony_ci        self.0.ru_isrss
3373da5c369Sopenharmony_ci    }
3383da5c369Sopenharmony_ci
3393da5c369Sopenharmony_ci    /// Number of page faults that were served without resorting to I/O, with pages
3403da5c369Sopenharmony_ci    /// that have been allocated previously by the kernel.
3413da5c369Sopenharmony_ci    pub fn minor_page_faults(&self) -> c_long {
3423da5c369Sopenharmony_ci        self.0.ru_minflt
3433da5c369Sopenharmony_ci    }
3443da5c369Sopenharmony_ci
3453da5c369Sopenharmony_ci    /// Number of page faults that were served through I/O (i.e. swap).
3463da5c369Sopenharmony_ci    pub fn major_page_faults(&self) -> c_long {
3473da5c369Sopenharmony_ci        self.0.ru_majflt
3483da5c369Sopenharmony_ci    }
3493da5c369Sopenharmony_ci
3503da5c369Sopenharmony_ci    /// Number of times all of the memory was fully swapped out.
3513da5c369Sopenharmony_ci    pub fn full_swaps(&self) -> c_long {
3523da5c369Sopenharmony_ci        self.0.ru_nswap
3533da5c369Sopenharmony_ci    }
3543da5c369Sopenharmony_ci
3553da5c369Sopenharmony_ci    /// Number of times a read was done from a block device.
3563da5c369Sopenharmony_ci    pub fn block_reads(&self) -> c_long {
3573da5c369Sopenharmony_ci        self.0.ru_inblock
3583da5c369Sopenharmony_ci    }
3593da5c369Sopenharmony_ci
3603da5c369Sopenharmony_ci    /// Number of times a write was done to a block device.
3613da5c369Sopenharmony_ci    pub fn block_writes(&self) -> c_long {
3623da5c369Sopenharmony_ci        self.0.ru_oublock
3633da5c369Sopenharmony_ci    }
3643da5c369Sopenharmony_ci
3653da5c369Sopenharmony_ci    /// Number of IPC messages sent.
3663da5c369Sopenharmony_ci    pub fn ipc_sends(&self) -> c_long {
3673da5c369Sopenharmony_ci        self.0.ru_msgsnd
3683da5c369Sopenharmony_ci    }
3693da5c369Sopenharmony_ci
3703da5c369Sopenharmony_ci    /// Number of IPC messages received.
3713da5c369Sopenharmony_ci    pub fn ipc_receives(&self) -> c_long {
3723da5c369Sopenharmony_ci        self.0.ru_msgrcv
3733da5c369Sopenharmony_ci    }
3743da5c369Sopenharmony_ci
3753da5c369Sopenharmony_ci    /// Number of signals received.
3763da5c369Sopenharmony_ci    pub fn signals(&self) -> c_long {
3773da5c369Sopenharmony_ci        self.0.ru_nsignals
3783da5c369Sopenharmony_ci    }
3793da5c369Sopenharmony_ci
3803da5c369Sopenharmony_ci    /// Number of times a context switch was voluntarily invoked.
3813da5c369Sopenharmony_ci    pub fn voluntary_context_switches(&self) -> c_long {
3823da5c369Sopenharmony_ci        self.0.ru_nvcsw
3833da5c369Sopenharmony_ci    }
3843da5c369Sopenharmony_ci
3853da5c369Sopenharmony_ci    /// Number of times a context switch was imposed by the kernel (usually due to
3863da5c369Sopenharmony_ci    /// time slice expiring or preemption by a higher priority process).
3873da5c369Sopenharmony_ci    pub fn involuntary_context_switches(&self) -> c_long {
3883da5c369Sopenharmony_ci        self.0.ru_nivcsw
3893da5c369Sopenharmony_ci    }
3903da5c369Sopenharmony_ci}
3913da5c369Sopenharmony_ci
3923da5c369Sopenharmony_ci/// Get usage information for a process, its children or the current thread
3933da5c369Sopenharmony_ci///
3943da5c369Sopenharmony_ci/// Real time information can be obtained for either the current process or (in some
3953da5c369Sopenharmony_ci/// systems) thread, but information about children processes is only provided for
3963da5c369Sopenharmony_ci/// those that have terminated and been waited for (see [`super::wait::wait`]).
3973da5c369Sopenharmony_ci///
3983da5c369Sopenharmony_ci/// Some information may be missing depending on the platform, and the way information
3993da5c369Sopenharmony_ci/// is provided for children may also vary. Check the manuals for details.
4003da5c369Sopenharmony_ci///
4013da5c369Sopenharmony_ci/// # References
4023da5c369Sopenharmony_ci///
4033da5c369Sopenharmony_ci/// * [getrusage(2)](https://pubs.opengroup.org/onlinepubs/009696699/functions/getrusage.html)
4043da5c369Sopenharmony_ci/// * [Linux](https://man7.org/linux/man-pages/man2/getrusage.2.html)
4053da5c369Sopenharmony_ci/// * [FreeBSD](https://www.freebsd.org/cgi/man.cgi?query=getrusage)
4063da5c369Sopenharmony_ci/// * [NetBSD](https://man.netbsd.org/getrusage.2)
4073da5c369Sopenharmony_ci/// * [MacOS](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/getrusage.2.html)
4083da5c369Sopenharmony_ci///
4093da5c369Sopenharmony_ci/// [`UsageWho`]: enum.UsageWho.html
4103da5c369Sopenharmony_ci///
4113da5c369Sopenharmony_ci/// Note: `getrusage` provides a safe wrapper to libc's [`libc::getrusage`].
4123da5c369Sopenharmony_cipub fn getrusage(who: UsageWho) -> Result<Usage> {
4133da5c369Sopenharmony_ci    unsafe {
4143da5c369Sopenharmony_ci        let mut rusage = mem::MaybeUninit::<rusage>::uninit();
4153da5c369Sopenharmony_ci        let res = libc::getrusage(who as c_int, rusage.as_mut_ptr());
4163da5c369Sopenharmony_ci        Errno::result(res).map(|_| Usage(rusage.assume_init()))
4173da5c369Sopenharmony_ci    }
4183da5c369Sopenharmony_ci}
4193da5c369Sopenharmony_ci
4203da5c369Sopenharmony_ci#[cfg(test)]
4213da5c369Sopenharmony_cimod test {
4223da5c369Sopenharmony_ci    use super::{getrusage, UsageWho};
4233da5c369Sopenharmony_ci
4243da5c369Sopenharmony_ci    #[test]
4253da5c369Sopenharmony_ci    pub fn test_self_cpu_time() {
4263da5c369Sopenharmony_ci        // Make sure some CPU time is used.
4273da5c369Sopenharmony_ci        let mut numbers: Vec<i32> = (1..1_000_000).collect();
4283da5c369Sopenharmony_ci        numbers.iter_mut().for_each(|item| *item *= 2);
4293da5c369Sopenharmony_ci
4303da5c369Sopenharmony_ci        // FIXME: this is here to help ensure the compiler does not optimize the whole
4313da5c369Sopenharmony_ci        // thing away. Replace the assert with test::black_box once stabilized.
4323da5c369Sopenharmony_ci        assert_eq!(numbers[100..200].iter().sum::<i32>(), 30_100);
4333da5c369Sopenharmony_ci
4343da5c369Sopenharmony_ci        let usage = getrusage(UsageWho::RUSAGE_SELF)
4353da5c369Sopenharmony_ci            .expect("Failed to call getrusage for SELF");
4363da5c369Sopenharmony_ci        let rusage = usage.as_ref();
4373da5c369Sopenharmony_ci
4383da5c369Sopenharmony_ci        let user = usage.user_time();
4393da5c369Sopenharmony_ci        assert!(user.tv_sec() > 0 || user.tv_usec() > 0);
4403da5c369Sopenharmony_ci        assert_eq!(user.tv_sec(), rusage.ru_utime.tv_sec);
4413da5c369Sopenharmony_ci        assert_eq!(user.tv_usec(), rusage.ru_utime.tv_usec);
4423da5c369Sopenharmony_ci    }
4433da5c369Sopenharmony_ci}
444