summaryrefslogtreecommitdiff
path: root/common.c
diff options
context:
space:
mode:
authorBelbo <belbo@gmx.de>2017-08-15 22:00:57 +0200
committerBelbo <belbo@gmx.de>2017-11-01 20:46:05 +0100
commitb98e6a9ac0fa8f77d46a5cc656db388210f27659 (patch)
treeebdba3cd0912f8d78e26214a949ba5c7d085a999 /common.c
parent183c6f08e08688f11ced8f07ac10710275441af0 (diff)
Fixed race condition when stopping other threads with SIGUSR1
Many threads have a main loop that checks some exit variable in the loop condition. To stop a thread, another thread sets that exit variable, sends a SIGUSR1 to that thread to get it out of blocking calls like read(), write() or select(), and finally joins it. There was a race condition though: if the signal arrived after the loop condition was checked but before the blocking system function was entered, the target thread essentially ignored the signal, made the blocking call anyway, and could get stuck forever there. The only way around this race condition is to block SIGUSR1 in the destination thread during the critical time interval. This requires that the blocking system call and the call to unblock SIGUSR1 be an atomic unit. There is only one system call that makes this possible: pselect(), which takes a signal mask to replace the current signal mask with, but only while pselect() runs. Other functions like read(), recv(), write() and sendto() may only be called if we can be sure that they don't block. For this purpose, the file descriptors must be set to non-blocking mode and we must prepend the call to them with a call to pselect() to block until the socket becomes readable/writable.
Diffstat (limited to 'common.c')
-rw-r--r--common.c2
1 files changed, 2 insertions, 0 deletions
diff --git a/common.c b/common.c
index 36fa183..e8cc16a 100644
--- a/common.c
+++ b/common.c
@@ -92,6 +92,8 @@ shairport_cfg config;
int debuglev = 0;
+sigset_t pselect_sigset;
+
int get_requested_connection_state_to_output() { return requested_connection_state_to_output; }
void set_requested_connection_state_to_output(int v) { requested_connection_state_to_output = v; }