commit d5d48c6f4ea8a16c2fa9dc9b083c1917a3accee0 (tree)
parent 682a29aefde09e31247088144a7e543daefb63f4
Author: Andrew Kelley <andrew@ziglang.org>
Date: Mon, 5 Oct 2020 01:54:38 -0400
Merge pull request #6496 from xackus/rlimit
std: implement {get, set}rlimit for linux
Diffstat:
6 files changed, 141 insertions(+), 0 deletions(-)
diff --git a/lib/std/c.zig b/lib/std/c.zig
@@ -342,3 +342,6 @@ pub extern "c" fn fsync(fd: c_int) c_int;
pub extern "c" fn fdatasync(fd: c_int) c_int;
pub extern "c" fn prctl(option: c_int, ...) c_int;
+
+pub extern "c" fn getrlimit(resource: rlimit_resource, rlim: *rlimit) c_int;
+pub extern "c" fn setrlimit(resource: rlimit_resource, rlim: *const rlimit) c_int;
diff --git a/lib/std/c/linux.zig b/lib/std/c/linux.zig
@@ -100,6 +100,8 @@ pub extern "c" fn copy_file_range(fd_in: fd_t, off_in: ?*i64, fd_out: fd_t, off_
pub extern "c" fn signalfd(fd: fd_t, mask: *const sigset_t, flags: c_uint) c_int;
+pub extern "c" fn prlimit(pid: pid_t, resource: rlimit_resource, new_limit: *const rlimit, old_limit: *rlimit) c_int;
+
pub const pthread_attr_t = extern struct {
__size: [56]u8,
__align: c_long,
diff --git a/lib/std/os.zig b/lib/std/os.zig
@@ -5410,3 +5410,33 @@ pub fn prctl(option: i32, args: anytype) PrctlError!u31 {
else => |err| return std.os.unexpectedErrno(err),
}
}
+
+pub const GetrlimitError = UnexpectedError;
+
+pub fn getrlimit(resource: rlimit_resource) GetrlimitError!rlimit {
+ // TODO implement for systems other than linux and enable test
+ var limits: rlimit = undefined;
+ const rc = system.getrlimit(resource, &limits);
+ switch (errno(rc)) {
+ 0 => return limits,
+ EFAULT => unreachable, // bogus pointer
+ EINVAL => unreachable,
+ else => |err| return std.os.unexpectedErrno(err),
+ }
+}
+
+pub const SetrlimitError = error{
+ PermissionDenied,
+} || UnexpectedError;
+
+pub fn setrlimit(resource: rlimit_resource, limits: rlimit) SetrlimitError!void {
+ // TODO implement for systems other than linux and enable test
+ const rc = system.setrlimit(resource, &limits);
+ switch (errno(rc)) {
+ 0 => return,
+ EFAULT => unreachable, // bogus pointer
+ EINVAL => unreachable,
+ EPERM => return error.PermissionDenied,
+ else => |err| return std.os.unexpectedErrno(err),
+ }
+}
diff --git a/lib/std/os/bits/linux.zig b/lib/std/os/bits/linux.zig
@@ -1890,3 +1890,79 @@ pub const ifreq = extern struct {
data: ?[*]u8,
},
};
+
+// doc comments copied from musl
+pub const rlimit_resource = extern enum(c_int) {
+ /// Per-process CPU limit, in seconds.
+ CPU,
+
+ /// Largest file that can be created, in bytes.
+ FSIZE,
+
+ /// Maximum size of data segment, in bytes.
+ DATA,
+
+ /// Maximum size of stack segment, in bytes.
+ STACK,
+
+ /// Largest core file that can be created, in bytes.
+ CORE,
+
+ /// Largest resident set size, in bytes.
+ /// This affects swapping; processes that are exceeding their
+ /// resident set size will be more likely to have physical memory
+ /// taken from them.
+ RSS,
+
+ /// Number of processes.
+ NPROC,
+
+ /// Number of open files.
+ NOFILE,
+
+ /// Locked-in-memory address space.
+ MEMLOCK,
+
+ /// Address space limit.
+ AS,
+
+ /// Maximum number of file locks.
+ LOCKS,
+
+ /// Maximum number of pending signals.
+ SIGPENDING,
+
+ /// Maximum bytes in POSIX message queues.
+ MSGQUEUE,
+
+ /// Maximum nice priority allowed to raise to.
+ /// Nice levels 19 .. -20 correspond to 0 .. 39
+ /// values of this resource limit.
+ NICE,
+
+ /// Maximum realtime priority allowed for non-priviledged
+ /// processes.
+ RTPRIO,
+
+ /// Maximum CPU time in µs that a process scheduled under a real-time
+ /// scheduling policy may consume without making a blocking system
+ /// call before being forcibly descheduled.
+ RTTIME,
+
+ _,
+};
+
+pub const rlim_t = u64;
+
+/// No limit
+pub const RLIM_INFINITY = ~@as(rlim_t, 0);
+
+pub const RLIM_SAVED_MAX = RLIM_INFINITY;
+pub const RLIM_SAVED_CUR = RLIM_INFINITY;
+
+pub const rlimit = extern struct {
+ /// Soft limit
+ cur: rlim_t,
+ /// Hard limit
+ max: rlim_t,
+};
diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig
@@ -1263,6 +1263,26 @@ pub fn prctl(option: i32, arg2: usize, arg3: usize, arg4: usize, arg5: usize) us
return syscall5(.prctl, @bitCast(usize, @as(isize, option)), arg2, arg3, arg4, arg5);
}
+pub fn getrlimit(resource: rlimit_resource, rlim: *rlimit) usize {
+ // use prlimit64 to have 64 bit limits on 32 bit platforms
+ return prlimit(0, resource, null, rlim);
+}
+
+pub fn setrlimit(resource: rlimit_resource, rlim: *const rlimit) usize {
+ // use prlimit64 to have 64 bit limits on 32 bit platforms
+ return prlimit(0, resource, rlim, null);
+}
+
+pub fn prlimit(pid: pid_t, resource: rlimit_resource, new_limit: ?*const rlimit, old_limit: ?*rlimit) usize {
+ return syscall4(
+ .prlimit64,
+ @bitCast(usize, @as(isize, pid)),
+ @bitCast(usize, @as(isize, @enumToInt(resource))),
+ @ptrToInt(new_limit),
+ @ptrToInt(old_limit)
+ );
+}
+
test "" {
if (builtin.os.tag == .linux) {
_ = @import("linux/test.zig");
diff --git a/lib/std/os/test.zig b/lib/std/os/test.zig
@@ -591,3 +591,13 @@ test "fsync" {
try os.fsync(file.handle);
try os.fdatasync(file.handle);
}
+
+test "getrlimit and setrlimit" {
+ // TODO enable for other systems when implemented
+ if(builtin.os.tag != .linux){
+ return error.SkipZigTest;
+ }
+
+ const cpuLimit = try os.getrlimit(.CPU);
+ try os.setrlimit(.CPU, cpuLimit);
+}