From a56c9c57a22c99f80807f280586099d89ba0fe82 Mon Sep 17 00:00:00 2001 From: John Lorentzson Date: Thu, 24 Apr 2025 20:32:22 +0200 Subject: [PATCH] Add workaround for usleep throwing SIGALRM signals On Solaris, usleep is not thread-safe and will introduce a race condition when used in a multithreaded environment. This manifests as SIGALRM signals escaping from its internal call to sigsuspend. If a signal is missing a handler, the process dies upon receiving it, crashing. The Solaris libc code does something rougly equivalent to this: PreserveSignalHandlers(...); /* Effectively NOPs out SIGALRM */ DisableSIGALRM(...); SetTimer(...); /* Suspends the thread until it receives a SIGALRM signal. When it receives this signal, it both wakes up *and* receives the signal. In this case we don't want to do anything but wake up, so the SIGALRM handler is a NOP. */ sigsuspend(...); RestoreSignalHandlers(...); return; The consequences of this code in a multithreaded context is that if two sleeps are in progress at the same time, one will necessarily finish before the other, *restore the non-existant handlers*, and go on doing its thing. When the other sleep finishes, it won't have a NOP handler to call when waking up, a handler is searched for, none is found, and thus we crash. --- src/Backends/Platform/X11.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/Backends/Platform/X11.cpp b/src/Backends/Platform/X11.cpp index 1f0cafcf..435e99e3 100644 --- a/src/Backends/Platform/X11.cpp +++ b/src/Backends/Platform/X11.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -24,6 +25,8 @@ Visual* xVisual; static XVisualInfo xvisinfo; static unsigned long startTime; +static void nophandler(int signo) {} + bool Backend_Init(void (*drag_and_drop_callback)(const char *path), void (*window_focus_callback)(bool focus)) { // we're ignoring the hell out of focus and drag & drop xDisplay = XOpenDisplay(NULL); @@ -35,6 +38,17 @@ bool Backend_Init(void (*drag_and_drop_callback)(const char *path), void (*windo gettimeofday(&time, NULL); startTime = (time.tv_sec * 1000) + (time.tv_usec / 1000); + // Disable SIGALRM to compensate for thread-unsafe usleep in Solaris + sigset_t mask; + struct sigaction act; + struct sigaction oldact; + act.sa_handler = nophandler; + act.sa_flags = 0; + sigaction(SIGALRM, &act, &oldact); + sigemptyset(&mask); + sigaddset(&mask, SIGALRM); + sigprocmask(SIG_BLOCK, &mask, 0); + return true; }