From cdec2bcbcefbcba008ce7cc01475075c7a86b77c Mon Sep 17 00:00:00 2001 From: themuffinator Date: Fri, 21 Nov 2025 16:42:51 +0000 Subject: [PATCH] Use sigaction for reliable handlers --- src/unix/system.cpp | 72 ++++++++++++++++++++++++++++++++++----------- src/unix/tty.cpp | 30 +++++++++++++++++-- 2 files changed, 83 insertions(+), 19 deletions(-) diff --git a/src/unix/system.cpp b/src/unix/system.cpp index ce44c68..4deb6f9 100644 --- a/src/unix/system.cpp +++ b/src/unix/system.cpp @@ -38,6 +38,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include #include +#include #if USE_MEMORY_TRACES && HAVE_BACKTRACE #include @@ -151,24 +152,61 @@ bool Sys_GetAntiCheatAPI(void) } #endif +/* +============= +Sys_SetNonBlock + +Set or clear non-blocking flag for the given descriptor. +============= +*/ bool Sys_SetNonBlock(int fd, bool nb) { - int ret = fcntl(fd, F_GETFL, 0); - if (ret == -1) - return false; - if ((bool)(ret & O_NONBLOCK) == nb) - return true; - return fcntl(fd, F_SETFL, ret ^ O_NONBLOCK) == 0; + int ret = fcntl(fd, F_GETFL, 0); + if (ret == -1) + return false; + if ((bool)(ret & O_NONBLOCK) == nb) + return true; + return fcntl(fd, F_SETFL, ret ^ O_NONBLOCK) == 0; } +/* +============= +Sys_SetSignalHandler + +Install a signal handler with given flags and mask. +============= +*/ +static void Sys_SetSignalHandler(int signum, void (*handler)(int), int flags) +{ + struct sigaction sa; + + memset(&sa, 0, sizeof(sa)); + sigemptyset(&sa.sa_mask); + sa.sa_handler = handler; + sa.sa_flags = flags; + + if (sigaction(signum, &sa, NULL) == -1) + Sys_Error("Failed to install handler for signal %d: %s", signum, strerror(errno)); +} + +/* +============= +usr1_handler +============= +*/ static void usr1_handler(int signum) { - flush_logs = true; + flush_logs = true; } +/* +============= +term_handler +============= +*/ static void term_handler(int signum) { - terminate = signum; + terminate = signum; } /* @@ -178,15 +216,15 @@ Sys_Init */ void Sys_Init(void) { - const char *homedir; - - signal(SIGTERM, term_handler); - signal(SIGINT, term_handler); - signal(SIGTTIN, SIG_IGN); - signal(SIGTTOU, SIG_IGN); - signal(SIGPIPE, SIG_IGN); - signal(SIGHUP, term_handler); - signal(SIGUSR1, usr1_handler); + const char *homedir; + + Sys_SetSignalHandler(SIGTERM, term_handler, 0); + Sys_SetSignalHandler(SIGINT, term_handler, 0); + Sys_SetSignalHandler(SIGTTIN, SIG_IGN, 0); + Sys_SetSignalHandler(SIGTTOU, SIG_IGN, 0); + Sys_SetSignalHandler(SIGPIPE, SIG_IGN, 0); + Sys_SetSignalHandler(SIGHUP, term_handler, SA_RESTART); + Sys_SetSignalHandler(SIGUSR1, usr1_handler, SA_RESTART); // basedir // allows the game to run from outside the data tree diff --git a/src/unix/tty.cpp b/src/unix/tty.cpp index e3c2311..4f96139 100644 --- a/src/unix/tty.cpp +++ b/src/unix/tty.cpp @@ -34,6 +34,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include #include +#include #include #include @@ -519,9 +520,33 @@ static void tty_parse_input(const char *text) } #ifdef TIOCGWINSZ +/* +============= +winch_handler +============= +*/ static void winch_handler(int signum) { - tty_prompt.inputLine.visibleChars = 0; // force refresh + tty_prompt.inputLine.visibleChars = 0; // force refresh +} + +/* +============= +tty_install_winch_handler + +Install SIGWINCH handler with restart semantics for TTY refresh. +============= +*/ +static bool tty_install_winch_handler(void) +{ + struct sigaction sa; + + memset(&sa, 0, sizeof(sa)); + sigemptyset(&sa.sa_mask); + sa.sa_handler = winch_handler; + sa.sa_flags = SA_RESTART; + + return sigaction(SIGWINCH, &sa, NULL) == 0; } #endif @@ -567,7 +592,8 @@ void tty_init_input(void) goto no_tty; #ifdef TIOCGWINSZ - signal(SIGWINCH, winch_handler); + if (!tty_install_winch_handler()) + goto no_tty; #endif // determine terminal width