yash_env/system/resource.rs
1// This file is part of yash, an extended POSIX shell.
2// Copyright (C) 2024 WATANABE Yuki
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program. If not, see <https://www.gnu.org/licenses/>.
16
17//! Resource types and limits
18//!
19//! This module defines resource types, their limit values, and traits for
20//! getting and setting resource limits.
21
22use super::Result;
23use std::rc::Rc;
24
25#[cfg(unix)]
26type RawLimit = libc::rlim_t;
27#[cfg(not(unix))]
28type RawLimit = u64;
29
30/// Unsigned integer type for resource limits
31///
32/// The size of this type may vary depending on the platform.
33pub type Limit = RawLimit;
34
35#[cfg(unix)]
36const RLIM_INFINITY: Limit = libc::RLIM_INFINITY;
37#[cfg(not(unix))]
38const RLIM_INFINITY: Limit = Limit::MAX;
39
40/// Constant to specify an unlimited resource limit
41///
42/// The value of this constant is platform-specific.
43pub const INFINITY: Limit = RLIM_INFINITY;
44
45// No platforms are known to define `RLIM_SAVED_CUR` and `RLIM_SAVED_MAX` that
46// have different values from `RLIM_INFINITY`, so they are not defined here.
47
48// When adding a new resource type, also update the yash_builtin::ulimit::resource module.
49
50/// Resource type definition
51///
52/// A `Resource` value represents a resource whose limit can be retrieved or
53/// set using [`GetRlimit`] and [`SetRlimit`].
54///
55/// This enum contains all possible resource types that may or may not be
56/// available depending on the platform.
57#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
58#[non_exhaustive]
59pub enum Resource {
60 /// Maximum total memory size of the process
61 AS,
62 /// Maximum size of a core file created by a terminated process
63 CORE,
64 /// Maximum amount of CPU time the process can consume
65 CPU,
66 /// Maximum size of a data segment of the process
67 DATA,
68 /// Maximum size of a file the process can create
69 FSIZE,
70 /// Maximum number of kernel event queues (kqueues)
71 KQUEUES,
72 /// Maximum number of file locks the process can hold
73 LOCKS,
74 /// Maximum size of memory locked into RAM
75 MEMLOCK,
76 /// Maximum total size of POSIX message queues
77 MSGQUEUE,
78 /// Maximum process priority
79 ///
80 /// This resource specifies the highest priority that a process can set using
81 /// `setpriority` or `nice`. When the resource value is set to *n*, the process
82 /// can lower its nice value (that is, raise the priority) to (20 - *n*).
83 NICE,
84 /// Maximum number of open files in the process
85 NOFILE,
86 /// Maximum number of processes the user can run
87 NPROC,
88 /// Maximum physical memory size of the process
89 RSS,
90 /// Maximum real-time priority
91 RTPRIO,
92 /// Maximum amount of CPU time the process can consume in real-time
93 /// scheduling mode without a blocking system call (microseconds)
94 RTTIME,
95 /// Maximum size of the socket buffer
96 SBSIZE,
97 /// Maximum number of signals that can be queued to the process
98 SIGPENDING,
99 /// Maximum size of the process stack
100 STACK,
101 /// Maximum size of the swap space that can be used by the user
102 SWAP,
103}
104
105impl Resource {
106 /// Slice of all resource types (including those not available on the current platform)
107 pub const ALL: &'static [Resource] = &[
108 Self::AS,
109 Self::CORE,
110 Self::CPU,
111 Self::DATA,
112 Self::FSIZE,
113 Self::KQUEUES,
114 Self::LOCKS,
115 Self::MEMLOCK,
116 Self::MSGQUEUE,
117 Self::NICE,
118 Self::NOFILE,
119 Self::NPROC,
120 Self::RSS,
121 Self::RTPRIO,
122 Self::RTTIME,
123 Self::SBSIZE,
124 Self::SIGPENDING,
125 Self::STACK,
126 Self::SWAP,
127 ];
128}
129
130/// Pair of soft and hard limits
131#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
132pub struct LimitPair {
133 pub soft: Limit,
134 pub hard: Limit,
135}
136
137impl LimitPair {
138 /// Returns `true` if the soft limit exceeds the hard limit
139 #[must_use]
140 pub fn soft_exceeds_hard(&self) -> bool {
141 self.hard != INFINITY && (self.soft == INFINITY || self.soft > self.hard)
142 }
143}
144
145pub trait GetRlimit {
146 /// Returns the limits for the specified resource.
147 ///
148 /// This function returns a pair of the soft and hard limits for the given
149 /// resource. The soft limit is the current limit, and the hard limit is the
150 /// maximum value that the soft limit can be set to.
151 ///
152 /// When no limit is set, the limit value is [`INFINITY`].
153 ///
154 /// This is a thin wrapper around the `getrlimit` system call.
155 fn getrlimit(&self, resource: Resource) -> Result<LimitPair>;
156}
157
158impl<S: GetRlimit> GetRlimit for Rc<S> {
159 #[inline]
160 fn getrlimit(&self, resource: Resource) -> Result<LimitPair> {
161 (self as &S).getrlimit(resource)
162 }
163}
164
165pub trait SetRlimit {
166 /// Sets the limits for the specified resource.
167 ///
168 /// Specify [`INFINITY`] as the limit value to remove the limit.
169 ///
170 /// This is a thin wrapper around the `setrlimit` system call.
171 fn setrlimit(&self, resource: Resource, limits: LimitPair) -> Result<()>;
172}
173
174impl<S: SetRlimit> SetRlimit for Rc<S> {
175 #[inline]
176 fn setrlimit(&self, resource: Resource, limits: LimitPair) -> Result<()> {
177 (self as &S).setrlimit(resource, limits)
178 }
179}