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.
This commit is contained in:
parent
a86f5df428
commit
a56c9c57a2
1 changed files with 14 additions and 0 deletions
|
@ -11,6 +11,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <signal.h>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
@ -24,6 +25,8 @@ Visual* xVisual;
|
||||||
static XVisualInfo xvisinfo;
|
static XVisualInfo xvisinfo;
|
||||||
static unsigned long startTime;
|
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)) {
|
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
|
// we're ignoring the hell out of focus and drag & drop
|
||||||
xDisplay = XOpenDisplay(NULL);
|
xDisplay = XOpenDisplay(NULL);
|
||||||
|
@ -35,6 +38,17 @@ bool Backend_Init(void (*drag_and_drop_callback)(const char *path), void (*windo
|
||||||
gettimeofday(&time, NULL);
|
gettimeofday(&time, NULL);
|
||||||
startTime = (time.tv_sec * 1000) + (time.tv_usec / 1000);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue