Skip to content

Commit

Permalink
core: if we change RLIMIT_NOFILE, reset it when executing commands
Browse files Browse the repository at this point in the history
  • Loading branch information
jcollie committed Jan 1, 2025
1 parent 60611b8 commit 9ea0aa4
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 8 deletions.
5 changes: 5 additions & 0 deletions src/Command.zig
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const Command = @This();

const std = @import("std");
const builtin = @import("builtin");
const global_state = &@import("global.zig").state;
const internal_os = @import("os/main.zig");
const windows = internal_os.windows;
const TempDir = internal_os.TempDir;
Expand Down Expand Up @@ -178,6 +179,10 @@ fn startPosix(self: *Command, arena: Allocator) !void {
// If the user requested a pre exec callback, call it now.
if (self.pre_exec) |f| f(self);

if (global_state.rlimits.nofile) |lim| {
internal_os.restoreMaxFiles(lim);
}

// Finally, replace our process.
_ = posix.execveZ(pathZ, argsZ, envp) catch null;

Expand Down
9 changes: 8 additions & 1 deletion src/global.zig
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ pub const GlobalState = struct {
alloc: std.mem.Allocator,
action: ?cli.Action,
logging: Logging,
/// If we change any resource limits for our own purposes, we save the
/// old limits so that they can be restored before we execute any child
/// processes.
rlimits: struct {
nofile: ?internal_os.rlimit = null,
} = .{},

/// The app resources directory, equivalent to zig-out/share when we build
/// from source. This is null if we can't detect it.
Expand Down Expand Up @@ -56,6 +62,7 @@ pub const GlobalState = struct {
.alloc = undefined,
.action = null,
.logging = .{ .stderr = {} },
.rlimits = .{},
.resources_dir = null,
};
errdefer self.deinit();
Expand Down Expand Up @@ -124,7 +131,7 @@ pub const GlobalState = struct {
std.log.info("libxev backend={}", .{xev.backend});

// First things first, we fix our file descriptors
internal_os.fixMaxFiles();
self.rlimits.nofile = internal_os.fixMaxFiles();

// Initialize our crash reporting.
crash.init(self.alloc) catch |err| {
Expand Down
24 changes: 17 additions & 7 deletions src/os/file.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,27 @@ const posix = std.posix;

const log = std.log.scoped(.os);

pub const rlimit = if (@hasDecl(posix.system, "rlimit")) posix.rlimit else struct {};

/// This maximizes the number of file descriptors we can have open. We
/// need to do this because each window consumes at least a handful of fds.
/// This is extracted from the Zig compiler source code.
pub fn fixMaxFiles() void {
if (!@hasDecl(posix.system, "rlimit")) return;
pub fn fixMaxFiles() ?rlimit {
if (!@hasDecl(posix.system, "rlimit")) return null;

var lim = posix.getrlimit(.NOFILE) catch {
const old = posix.getrlimit(.NOFILE) catch {
log.warn("failed to query file handle limit, may limit max windows", .{});
return; // Oh well; we tried.
return null; // Oh well; we tried.
};

// If we're already at the max, we're done.
if (lim.cur >= lim.max) {
log.debug("file handle limit already maximized value={}", .{lim.cur});
return;
if (old.cur >= old.max) {
log.debug("file handle limit already maximized value={}", .{old.cur});
return old;
}

var lim = old;

// Do a binary search for the limit.
var min: posix.rlim_t = lim.cur;
var max: posix.rlim_t = 1 << 20;
Expand All @@ -41,6 +45,12 @@ pub fn fixMaxFiles() void {
}

log.debug("file handle limit raised value={}", .{lim.cur});
return old;
}

pub fn restoreMaxFiles(lim: rlimit) void {
if (!@hasDecl(posix.system, "rlimit")) return;
posix.setrlimit(.NOFILE, lim) catch {};
}

/// Return the recommended path for temporary files.
Expand Down
2 changes: 2 additions & 0 deletions src/os/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ pub const getenv = env.getenv;
pub const setenv = env.setenv;
pub const unsetenv = env.unsetenv;
pub const launchedFromDesktop = desktop.launchedFromDesktop;
pub const rlimit = file.rlimit;
pub const fixMaxFiles = file.fixMaxFiles;
pub const restoreMaxFiles = file.restoreMaxFiles;
pub const allocTmpDir = file.allocTmpDir;
pub const freeTmpDir = file.freeTmpDir;
pub const isFlatpak = flatpak.isFlatpak;
Expand Down

0 comments on commit 9ea0aa4

Please sign in to comment.