os: don't unconditionally unblock SIGIO in OsReleaseSignals()
Calling OsReleaseSignal() inside the signal handler releases SIGIO, causing
the signal handler to be called again from within the handler.
Practical use-case: when synaptics calls TimerSet in the signal handler,
this causes the signals to be released, eventually hanging the server.
Regression introduced in 08962951de
.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Jeremy Huddleston <jeremyhu@apple.com>
This commit is contained in:
parent
cb306a8f17
commit
7f09126e06
13
os/utils.c
13
os/utils.c
|
@ -1186,6 +1186,7 @@ OsBlockSignals(void)
|
||||||
|
|
||||||
#ifdef SIG_BLOCK
|
#ifdef SIG_BLOCK
|
||||||
static sig_atomic_t sigio_blocked;
|
static sig_atomic_t sigio_blocked;
|
||||||
|
static sigset_t PreviousSigIOMask;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1198,13 +1199,13 @@ OsBlockSIGIO(void)
|
||||||
#ifdef SIGIO
|
#ifdef SIGIO
|
||||||
#ifdef SIG_BLOCK
|
#ifdef SIG_BLOCK
|
||||||
if (sigio_blocked++ == 0) {
|
if (sigio_blocked++ == 0) {
|
||||||
sigset_t set, old;
|
sigset_t set;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
sigemptyset(&set);
|
sigemptyset(&set);
|
||||||
sigaddset(&set, SIGIO);
|
sigaddset(&set, SIGIO);
|
||||||
sigprocmask(SIG_BLOCK, &set, &old);
|
sigprocmask(SIG_BLOCK, &set, &PreviousSigIOMask);
|
||||||
ret = sigismember(&old, SIGIO);
|
ret = sigismember(&PreviousSigIOMask, SIGIO);
|
||||||
return ret;
|
return ret;
|
||||||
} else
|
} else
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -1218,11 +1219,7 @@ OsReleaseSIGIO(void)
|
||||||
#ifdef SIGIO
|
#ifdef SIGIO
|
||||||
#ifdef SIG_BLOCK
|
#ifdef SIG_BLOCK
|
||||||
if (--sigio_blocked == 0) {
|
if (--sigio_blocked == 0) {
|
||||||
sigset_t set;
|
sigprocmask(SIG_SETMASK, &PreviousSigIOMask, 0);
|
||||||
|
|
||||||
sigemptyset(&set);
|
|
||||||
sigaddset(&set, SIGIO);
|
|
||||||
sigprocmask(SIG_UNBLOCK, &set, NULL);
|
|
||||||
} else if (sigio_blocked < 0) {
|
} else if (sigio_blocked < 0) {
|
||||||
BUG_WARN(sigio_blocked < 0);
|
BUG_WARN(sigio_blocked < 0);
|
||||||
sigio_blocked = 0;
|
sigio_blocked = 0;
|
||||||
|
|
36
test/os.c
36
test/os.c
|
@ -28,6 +28,21 @@
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
|
|
||||||
|
static int last_signal = 0;
|
||||||
|
static int expect_signal = 0;
|
||||||
|
|
||||||
|
static void sighandler(int signal)
|
||||||
|
{
|
||||||
|
assert(expect_signal);
|
||||||
|
expect_signal = 0;
|
||||||
|
if (!last_signal)
|
||||||
|
raise(signal);
|
||||||
|
OsBlockSignals();
|
||||||
|
OsReleaseSignals();
|
||||||
|
last_signal = 1;
|
||||||
|
expect_signal = 1;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
sig_is_blocked(int sig)
|
sig_is_blocked(int sig)
|
||||||
{
|
{
|
||||||
|
@ -118,7 +133,27 @@ static void block_sigio_test(void)
|
||||||
assert(sig_is_blocked(SIGIO));
|
assert(sig_is_blocked(SIGIO));
|
||||||
OsReleaseSignals();
|
OsReleaseSignals();
|
||||||
assert(!sig_is_blocked(SIGIO));
|
assert(!sig_is_blocked(SIGIO));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void block_sigio_test_nested(void)
|
||||||
|
{
|
||||||
|
#ifdef SIG_BLOCK
|
||||||
|
/* Check for bug releasing SIGIO during SIGIO signal handling.
|
||||||
|
test case:
|
||||||
|
raise signal
|
||||||
|
→ in signal handler:
|
||||||
|
raise signal
|
||||||
|
OsBlockSignals()
|
||||||
|
OsReleaseSignals()
|
||||||
|
tail guard
|
||||||
|
tail guard must be hit.
|
||||||
|
*/
|
||||||
|
sighandler_t old_handler;
|
||||||
|
old_handler = signal(SIGIO, sighandler);
|
||||||
|
expect_signal = 1;
|
||||||
|
assert(raise(SIGIO) == 0);
|
||||||
|
assert(signal(SIGIO, old_handler) == sighandler);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,5 +161,6 @@ int
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
block_sigio_test();
|
block_sigio_test();
|
||||||
|
block_sigio_test_nested();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user