diff --git a/lib/std/process.zig b/lib/std/process.zig index cf5837a002..ac7e0f6d08 100644 --- a/lib/std/process.zig +++ b/lib/std/process.zig @@ -1742,3 +1742,49 @@ pub fn cleanExit() void { exit(0); } } + +/// Raise the open file descriptor limit. +/// +/// On some systems, this raises the limit before seeing ProcessFdQuotaExceeded +/// errors. On other systems, this does nothing. +pub fn raiseFileDescriptorLimit() void { + const have_rlimit = switch (native_os) { + .windows, .wasi => false, + else => true, + }; + if (!have_rlimit) return; + + var lim = posix.getrlimit(.NOFILE) catch return; // Oh well; we tried. + if (native_os.isDarwin()) { + // On Darwin, `NOFILE` is bounded by a hardcoded value `OPEN_MAX`. + // According to the man pages for setrlimit(): + // setrlimit() now returns with errno set to EINVAL in places that historically succeeded. + // It no longer accepts "rlim_cur = RLIM.INFINITY" for RLIM.NOFILE. + // Use "rlim_cur = min(OPEN_MAX, rlim_max)". + lim.max = @min(std.c.OPEN_MAX, lim.max); + } + if (lim.cur == lim.max) return; + + // Do a binary search for the limit. + var min: posix.rlim_t = lim.cur; + var max: posix.rlim_t = 1 << 20; + // But if there's a defined upper bound, don't search, just set it. + if (lim.max != posix.RLIM.INFINITY) { + min = lim.max; + max = lim.max; + } + + while (true) { + lim.cur = min + @divTrunc(max - min, 2); // on freebsd rlim_t is signed + if (posix.setrlimit(.NOFILE, lim)) |_| { + min = lim.cur; + } else |_| { + max = lim.cur; + } + if (min + 1 >= max) break; + } +} + +test raiseFileDescriptorLimit { + raiseFileDescriptorLimit(); +} diff --git a/src/main.zig b/src/main.zig index d18d085c19..0541d78cd9 100644 --- a/src/main.zig +++ b/src/main.zig @@ -3197,7 +3197,7 @@ fn buildOutputType( break :b .incremental; }; - gimmeMoreOfThoseSweetSweetFileDescriptors(); + process.raiseFileDescriptorLimit(); const comp = Compilation.create(gpa, arena, .{ .zig_lib_directory = zig_lib_directory, @@ -4908,7 +4908,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { .basename = exe_basename, }; - gimmeMoreOfThoseSweetSweetFileDescriptors(); + process.raiseFileDescriptorLimit(); var zig_lib_directory: Compilation.Directory = if (override_lib_dir) |lib_dir| .{ .path = lib_dir, @@ -5973,55 +5973,6 @@ fn parseCodeModel(arg: []const u8) std.builtin.CodeModel { fatal("unsupported machine code model: '{s}'", .{arg}); } -/// Raise the open file descriptor limit. Ask and ye shall receive. -/// For one example of why this is handy, consider the case of building musl libc. -/// We keep a lock open for each of the object files in the form of a file descriptor -/// until they are finally put into an archive file. This is to allow a zig-cache -/// garbage collector to run concurrently to zig processes, and to allow multiple -/// zig processes to run concurrently with each other, without clobbering each other. -fn gimmeMoreOfThoseSweetSweetFileDescriptors() void { - const have_rlimit = switch (native_os) { - .windows, .wasi => false, - else => true, - }; - if (!have_rlimit) return; - const posix = std.posix; - - var lim = posix.getrlimit(.NOFILE) catch return; // Oh well; we tried. - if (native_os.isDarwin()) { - // On Darwin, `NOFILE` is bounded by a hardcoded value `OPEN_MAX`. - // According to the man pages for setrlimit(): - // setrlimit() now returns with errno set to EINVAL in places that historically succeeded. - // It no longer accepts "rlim_cur = RLIM.INFINITY" for RLIM.NOFILE. - // Use "rlim_cur = min(OPEN_MAX, rlim_max)". - lim.max = @min(std.c.OPEN_MAX, lim.max); - } - if (lim.cur == lim.max) return; - - // Do a binary search for the limit. - var min: posix.rlim_t = lim.cur; - var max: posix.rlim_t = 1 << 20; - // But if there's a defined upper bound, don't search, just set it. - if (lim.max != posix.RLIM.INFINITY) { - min = lim.max; - max = lim.max; - } - - while (true) { - lim.cur = min + @divTrunc(max - min, 2); // on freebsd rlim_t is signed - if (posix.setrlimit(.NOFILE, lim)) |_| { - min = lim.cur; - } else |_| { - max = lim.cur; - } - if (min + 1 >= max) break; - } -} - -test "fds" { - gimmeMoreOfThoseSweetSweetFileDescriptors(); -} - const usage_ast_check = \\Usage: zig ast-check [file] \\