Commit 4ec26be424

xackus <14938807+xackus@users.noreply.github.com>
2020-10-02 00:20:32
implement {get, set}rlimit for linux
1 parent 0e2d858
Changed files (5)
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,
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,
+};
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");
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;
lib/std/os.zig
@@ -5410,3 +5410,30 @@ 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, limits: *rlimit) GetrlimitError!void {
+    const rc = system.getrlimit(resource, limits);
+    switch (errno(rc)) {
+        0 => return,
+        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: *const rlimit) SetrlimitError!void {
+    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),
+    }
+}