commit 0e19d85d37e556721f982c3f63d4e2927f306b18
parent 86ff19fadeaa45f7f6398d62be1ee6149a0889a8
Author: Simon Ser <contact@emersion.fr>
Date: Sun, 20 Apr 2025 21:09:57 +0200
Use pthread_atfork() to restore signals and NOFILE limit
This ensures these functions are always called (even when a library
such as wlroots or libc perform the fork) and removes the need to
manually call them.
Diffstat:
7 files changed, 23 insertions(+), 28 deletions(-)
diff --git a/include/sway/server.h b/include/sway/server.h
@@ -164,9 +164,6 @@ void server_fini(struct sway_server *server);
bool server_start(struct sway_server *server);
void server_run(struct sway_server *server);
-void restore_nofile_limit(void);
-void restore_signals(void);
-
void handle_new_output(struct wl_listener *listener, void *data);
void handle_idle_inhibitor_v1(struct wl_listener *listener, void *data);
diff --git a/meson.build b/meson.build
@@ -79,7 +79,7 @@ libudev = wlroots_features['libinput_backend'] ? dependency('libudev') : null_de
math = cc.find_library('m')
rt = cc.find_library('rt')
xcb_icccm = wlroots_features['xwayland'] ? dependency('xcb-icccm') : null_dep
-threads = dependency('threads') # for pthread_setschedparam
+threads = dependency('threads') # for pthread_setschedparam and pthread_atfork
if get_option('sd-bus-provider') == 'auto'
if not get_option('tray').disabled()
diff --git a/sway/commands/exec_always.c b/sway/commands/exec_always.c
@@ -51,8 +51,6 @@ struct cmd_results *cmd_exec_process(int argc, char **argv) {
// Fork process
pid_t child = fork();
if (child == 0) {
- restore_nofile_limit();
- restore_signals();
setsid();
if (ctx) {
diff --git a/sway/config/bar.c b/sway/config/bar.c
@@ -213,8 +213,6 @@ static void invoke_swaybar(struct bar_config *bar) {
sway_log(SWAY_ERROR, "Failed to create fork for swaybar");
return;
} else if (pid == 0) {
- restore_nofile_limit();
- restore_signals();
if (!sway_set_cloexec(sockets[1], false)) {
_exit(EXIT_FAILURE);
}
diff --git a/sway/config/output.c b/sway/config/output.c
@@ -1060,8 +1060,6 @@ static bool _spawn_swaybg(char **command) {
sway_log_errno(SWAY_ERROR, "fork failed");
return false;
} else if (pid == 0) {
- restore_nofile_limit();
- restore_signals();
if (!sway_set_cloexec(sockets[1], false)) {
_exit(EXIT_FAILURE);
}
diff --git a/sway/main.c b/sway/main.c
@@ -1,5 +1,6 @@
#include <getopt.h>
#include <pango/pangocairo.h>
+#include <pthread.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
@@ -121,6 +122,16 @@ static bool detect_suid(void) {
return true;
}
+static void restore_nofile_limit(void) {
+ if (original_nofile_rlimit.rlim_cur == 0) {
+ return;
+ }
+ if (setrlimit(RLIMIT_NOFILE, &original_nofile_rlimit) != 0) {
+ sway_log_errno(SWAY_ERROR, "Failed to restore max open files limit: "
+ "setrlimit(NOFILE) failed");
+ }
+}
+
static void increase_nofile_limit(void) {
if (getrlimit(RLIMIT_NOFILE, &original_nofile_rlimit) != 0) {
sway_log_errno(SWAY_ERROR, "Failed to bump max open files limit: "
@@ -135,17 +146,10 @@ static void increase_nofile_limit(void) {
"setrlimit(NOFILE) failed");
sway_log(SWAY_INFO, "Running with %d max open files",
(int)original_nofile_rlimit.rlim_cur);
- }
-}
-
-void restore_nofile_limit(void) {
- if (original_nofile_rlimit.rlim_cur == 0) {
return;
}
- if (setrlimit(RLIMIT_NOFILE, &original_nofile_rlimit) != 0) {
- sway_log_errno(SWAY_ERROR, "Failed to restore max open files limit: "
- "setrlimit(NOFILE) failed");
- }
+
+ pthread_atfork(NULL, NULL, restore_nofile_limit);
}
static int term_signal(int signal, void *data) {
@@ -153,6 +157,14 @@ static int term_signal(int signal, void *data) {
return 0;
}
+static void restore_signals(void) {
+ sigset_t set;
+ sigemptyset(&set);
+ sigprocmask(SIG_SETMASK, &set, NULL);
+ signal(SIGCHLD, SIG_DFL);
+ signal(SIGPIPE, SIG_DFL);
+}
+
static void init_signals(void) {
wl_event_loop_add_signal(server.wl_event_loop, SIGTERM, term_signal, NULL);
wl_event_loop_add_signal(server.wl_event_loop, SIGINT, term_signal, NULL);
@@ -162,14 +174,8 @@ static void init_signals(void) {
// prevent ipc write errors from crashing sway
signal(SIGPIPE, SIG_IGN);
-}
-void restore_signals(void) {
- sigset_t set;
- sigemptyset(&set);
- sigprocmask(SIG_SETMASK, &set, NULL);
- signal(SIGCHLD, SIG_DFL);
- signal(SIGPIPE, SIG_DFL);
+ pthread_atfork(NULL, NULL, restore_signals);
}
void enable_debug_flag(const char *flag) {
diff --git a/sway/swaynag.c b/sway/swaynag.c
@@ -63,7 +63,6 @@ bool swaynag_spawn(const char *swaynag_command,
sway_log(SWAY_ERROR, "Failed to create fork for swaynag");
goto failed;
} else if (pid == 0) {
- restore_nofile_limit();
if (!sway_set_cloexec(sockets[1], false)) {
_exit(EXIT_FAILURE);
}
@@ -148,4 +147,3 @@ void swaynag_show(struct swaynag_instance *swaynag) {
close(swaynag->fd[1]);
}
}
-