diff --git a/lib/std/c.zig b/lib/std/c.zig index aa50fff90..7cfc44714 100644 --- 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 index 538fbdfd7..d48c76c7a 100644 --- 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 index ef342edf5..b89f225ab 100644 --- a/lib/std/os.zig +++ b/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), + } +} diff --git a/lib/std/os/bits/linux.zig b/lib/std/os/bits/linux.zig index df31bc32f..1ead0c796 100644 --- 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 index 50d1e4ae7..e38d9bc10 100644 --- 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");