server: Kill temporary SIGCHLD handler.
authorAndre Noll <maan@systemlinux.org>
Wed, 12 Oct 2011 16:13:40 +0000 (18:13 +0200)
committerAndre Noll <maan@systemlinux.org>
Sat, 15 Oct 2011 19:22:53 +0000 (21:22 +0200)
During startup, para_server sets up a temporary signal handler for
SIGCHLD in order to notice if the afs child process terminates
immediately (doing the signal setup after the fork would be too
late). This patch makes it block this signal during this period
instead. This works equally well and it fixes a weird problem on Mac
OS where the temporary SIGCHLD handler was executed although it had
been replaced by the generic signal handler of signal.c.

server.c
signal.c
signal.h

index 6b1e11d6fb580b1edd8da144e3c47b2977fb1d2e..1e45eb3616a858091f98f42079d94251963a43ed 100644 (file)
--- a/server.c
+++ b/server.c
@@ -462,12 +462,6 @@ static int init_afs(void)
        return afs_server_socket[0];
 }
 
-__noreturn static void tmp_sigchld_handler(__a_unused int s)
-{
-       PARA_EMERG_LOG("caught early SIGCHLD\n");
-       exit(EXIT_FAILURE);
-}
-
 static void server_init(int argc, char **argv)
 {
        struct server_cmdline_parser_params params = {
@@ -509,14 +503,16 @@ static void server_init(int argc, char **argv)
         */
        para_sigaction(SIGUSR1, SIG_IGN);
        /*
-        * We have to install a SIGCHLD handler before the afs process is being
-        * forked off. Otherwise, para_server does not notice if afs dies before
-        * the SIGCHLD handler has been installed by init_signal_task() below.
+        * We have to block SIGCHLD before the afs process is being forked off.
+        * Otherwise, para_server does not notice if afs dies before the
+        * SIGCHLD handler has been installed for the parent process by
+        * init_signal_task() below.
         */
-       para_sigaction(SIGCHLD, tmp_sigchld_handler);
+       para_block_signal(SIGCHLD);
        PARA_NOTICE_LOG("initializing the audio file selector\n");
        afs_socket = init_afs();
        init_signal_task();
+       para_unblock_signal(SIGCHLD);
        PARA_NOTICE_LOG("initializing virtual streaming system\n");
        init_vss_task(afs_socket);
        PARA_NOTICE_LOG("server init complete\n");
index 2d5549d59817b151ae6780fa43e083f881c81ea9..aa63c8b5461a9627c021a514b83b7c8ee1067067 100644 (file)
--- a/signal.c
+++ b/signal.c
@@ -147,6 +147,46 @@ void para_install_sighandler(int sig)
        para_sigaction(sig, &generic_signal_handler);
 }
 
+/**
+ * Block a signal for the caller.
+ *
+ * \param sig The signal to block.
+ *
+ * This sets the given signal in the current signal mask of the calling process
+ * to prevent this signal from delivery.
+ *
+ * \sa \ref para_unblock_signal(), sigprocmask(2), sigaddset(3).
+ */
+void para_block_signal(int sig)
+{
+       sigset_t set;
+
+       PARA_DEBUG_LOG("blocking signal %d\n", sig);
+       sigemptyset(&set);
+       sigaddset(&set, sig);
+       sigprocmask(SIG_BLOCK, &set, NULL);
+}
+
+/**
+ * Unblock a signal.
+ *
+ * \param sig The signal to unblock.
+ *
+ * This function removes the given signal from the current set of blocked
+ * signals.
+ *
+ * \sa \ref para_block_signal(), sigprocmask(2), sigaddset(3).
+ */
+void para_unblock_signal(int sig)
+{
+       sigset_t set;
+
+       PARA_DEBUG_LOG("unblocking signal %d\n", sig);
+       sigemptyset(&set);
+       sigaddset(&set, sig);
+       sigprocmask(SIG_UNBLOCK, &set, NULL);
+}
+
 /**
  * Return the number of the next pending signal.
  *
index 799c317fd6114046334c8577fabbe767e20eea94..266b3aba4df97de8c4ecafbaaa03065840f99f01 100644 (file)
--- a/signal.h
+++ b/signal.h
@@ -22,3 +22,5 @@ void para_install_sighandler(int);
 int para_reap_child(pid_t *pid);
 int para_next_signal(fd_set *rfds);
 void para_signal_shutdown(void);
+void para_block_signal(int sig);
+void para_unblock_signal(int sig);