river: raise the file descriptor limit
This commit is contained in:
parent
94828474b0
commit
3e306ecfbf
@ -19,6 +19,7 @@ const os = std.os;
|
||||
|
||||
const c = @import("../c.zig");
|
||||
const util = @import("../util.zig");
|
||||
const process = @import("../process.zig");
|
||||
|
||||
const Error = @import("../command.zig").Error;
|
||||
const Seat = @import("../Seat.zig");
|
||||
@ -40,7 +41,7 @@ pub fn spawn(
|
||||
};
|
||||
|
||||
if (pid == 0) {
|
||||
util.post_fork_pre_execve();
|
||||
process.cleanupChild();
|
||||
const pid2 = os.fork() catch c._exit(1);
|
||||
if (pid2 == 0) os.execveZ("/bin/sh", &child_args, std.c.environ) catch c._exit(1);
|
||||
|
||||
|
@ -27,6 +27,7 @@ const flags = @import("flags");
|
||||
|
||||
const c = @import("c.zig");
|
||||
const util = @import("util.zig");
|
||||
const process = @import("process.zig");
|
||||
|
||||
const Server = @import("Server.zig");
|
||||
|
||||
@ -98,22 +99,16 @@ pub fn main() anyerror!void {
|
||||
}
|
||||
};
|
||||
|
||||
log.info("river version {s}, initializing server", .{build_options.version});
|
||||
|
||||
process.setup();
|
||||
|
||||
river_init_wlroots_log(switch (runtime_log_level) {
|
||||
.debug => .debug,
|
||||
.info => .info,
|
||||
.warn, .err => .err,
|
||||
});
|
||||
|
||||
// Ignore SIGPIPE so we don't get killed when writing to a socket that
|
||||
// has had its read end closed by another process.
|
||||
const sig_ign = os.Sigaction{
|
||||
.handler = .{ .handler = os.SIG.IGN },
|
||||
.mask = os.empty_sigset,
|
||||
.flags = 0,
|
||||
};
|
||||
try os.sigaction(os.SIG.PIPE, &sig_ign, null);
|
||||
|
||||
log.info("river version {s}, initializing server", .{build_options.version});
|
||||
try server.init(enable_xwayland);
|
||||
defer server.deinit();
|
||||
|
||||
@ -126,7 +121,7 @@ pub fn main() anyerror!void {
|
||||
const child_args = [_:null]?[*:0]const u8{ "/bin/sh", "-c", cmd, null };
|
||||
const pid = try os.fork();
|
||||
if (pid == 0) {
|
||||
util.post_fork_pre_execve();
|
||||
process.cleanupChild();
|
||||
os.execveZ("/bin/sh", &child_args, std.c.environ) catch c._exit(1);
|
||||
}
|
||||
util.gpa.free(cmd);
|
||||
|
79
river/process.zig
Normal file
79
river/process.zig
Normal file
@ -0,0 +1,79 @@
|
||||
// This file is part of river, a dynamic tiling wayland compositor.
|
||||
//
|
||||
// Copyright 2022-2024 The River Developers
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 3.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
const std = @import("std");
|
||||
const os = std.os;
|
||||
|
||||
const c = @import("c.zig");
|
||||
|
||||
var original_rlimit: ?os.rlimit = null;
|
||||
|
||||
pub fn setup() void {
|
||||
// Ignore SIGPIPE so we don't get killed when writing to a socket that
|
||||
// has had its read end closed by another process.
|
||||
const sig_ign = os.Sigaction{
|
||||
.handler = .{ .handler = os.SIG.IGN },
|
||||
.mask = os.empty_sigset,
|
||||
.flags = 0,
|
||||
};
|
||||
os.sigaction(os.SIG.PIPE, &sig_ign, null) catch unreachable;
|
||||
|
||||
// Most unix systems have a default limit of 1024 file descriptors and it
|
||||
// seems unlikely for this default to be universally raised due to the
|
||||
// broken behavior of select() on fds with value >1024. However, it is
|
||||
// unreasonable to use such a low limit for a process such as river which
|
||||
// uses many fds in its communication with wayland clients and the kernel.
|
||||
//
|
||||
// There is however an advantage to having a relatively low limit: it helps
|
||||
// to catch any fd leaks. Therefore, don't use some crazy high limit that
|
||||
// can never be reached before the system runs out of memory. This can be
|
||||
// raised further if anyone reaches it in practice.
|
||||
if (os.getrlimit(.NOFILE)) |original| {
|
||||
original_rlimit = original;
|
||||
const new: os.rlimit = .{
|
||||
.cur = @min(4096, original.max),
|
||||
.max = original.max,
|
||||
};
|
||||
if (os.setrlimit(.NOFILE, new)) {
|
||||
std.log.info("raised file descriptor limit of the river process to {d}", .{new.cur});
|
||||
} else |_| {
|
||||
std.log.err("setrlimit failed, using system default file descriptor limit of {d}", .{
|
||||
original.cur,
|
||||
});
|
||||
}
|
||||
} else |_| {
|
||||
std.log.err("getrlimit failed, using system default file descriptor limit ", .{});
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cleanupChild() void {
|
||||
if (c.setsid() < 0) unreachable;
|
||||
if (os.system.sigprocmask(os.SIG.SETMASK, &os.empty_sigset, null) < 0) unreachable;
|
||||
|
||||
const sig_dfl = os.Sigaction{
|
||||
.handler = .{ .handler = os.SIG.DFL },
|
||||
.mask = os.empty_sigset,
|
||||
.flags = 0,
|
||||
};
|
||||
os.sigaction(os.SIG.PIPE, &sig_dfl, null) catch unreachable;
|
||||
|
||||
if (original_rlimit) |original| {
|
||||
os.setrlimit(.NOFILE, original) catch {
|
||||
std.log.err("failed to restore original file descriptor limit for " ++
|
||||
"child process, setrlimit failed", .{});
|
||||
};
|
||||
}
|
||||
}
|
@ -15,22 +15,6 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
const std = @import("std");
|
||||
const os = std.os;
|
||||
|
||||
const xkb = @import("xkbcommon");
|
||||
|
||||
const c = @import("c.zig");
|
||||
|
||||
/// The global general-purpose allocator used throughout river's code
|
||||
pub const gpa = std.heap.c_allocator;
|
||||
|
||||
pub fn post_fork_pre_execve() void {
|
||||
if (c.setsid() < 0) unreachable;
|
||||
if (os.system.sigprocmask(os.SIG.SETMASK, &os.empty_sigset, null) < 0) unreachable;
|
||||
const sig_dfl = os.Sigaction{
|
||||
.handler = .{ .handler = os.SIG.DFL },
|
||||
.mask = os.empty_sigset,
|
||||
.flags = 0,
|
||||
};
|
||||
os.sigaction(os.SIG.PIPE, &sig_dfl, null) catch @panic("sigaction before fork failed");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user