Add a mutex around stg_sig_install
authorSimon Marlow <marlowsd@gmail.com>
Mon, 12 Dec 2011 09:29:56 +0000 (09:29 +0000)
committerSimon Marlow <marlowsd@gmail.com>
Mon, 12 Dec 2011 09:33:22 +0000 (09:33 +0000)
Protects against a race when two threads call installHandler
simultaneously.  This was causing occasional failure of the test
libraries/process/tests/3231(threaded2).

rts/posix/Signals.c

index 7b25d7c..95d5822 100644 (file)
@@ -65,6 +65,39 @@ static StgInt nHandlers = 0;    /* Size of handlers array */
 
 static nat n_haskell_handlers = 0;
 
+static sigset_t userSignals;
+static sigset_t savedSignals;
+
+#ifdef THREADED_RTS
+static Mutex sig_mutex; // protects signal_handlers, nHandlers
+#endif
+
+/* -----------------------------------------------------------------------------
+ * Initialisation / deinitialisation
+ * -------------------------------------------------------------------------- */
+
+void
+initUserSignals(void)
+{
+    sigemptyset(&userSignals);
+#ifdef THREADED_RTS
+    initMutex(&sig_mutex);
+#endif
+}
+
+void
+freeSignalHandlers(void) {
+    if (signal_handlers != NULL) {
+        stgFree(signal_handlers);
+        signal_handlers = NULL;
+        nHandlers = 0;
+        n_haskell_handlers = 0;
+    }
+#ifdef THREADED_RTS
+    closeMutex(&sig_mutex);
+#endif
+}
+
 /* -----------------------------------------------------------------------------
  * Allocate/resize the table of signal handlers.
  * -------------------------------------------------------------------------- */
@@ -260,15 +293,6 @@ generic_handler(int sig USED_IF_THREADS,
  * Blocking/Unblocking of the user signals
  * -------------------------------------------------------------------------- */
 
-static sigset_t userSignals;
-static sigset_t savedSignals;
-
-void
-initUserSignals(void)
-{
-    sigemptyset(&userSignals);
-}
-
 void
 blockUserSignals(void)
 {
@@ -312,11 +336,14 @@ stg_sig_install(int sig, int spi, void *mask)
     struct sigaction action;
     StgInt previous_spi;
 
+    ACQUIRE_LOCK(&sig_mutex);
+
     // Block the signal until we figure out what to do
     // Count on this to fail if the signal number is invalid
     if (sig < 0 || sigemptyset(&signals) ||
        sigaddset(&signals, sig) || sigprocmask(SIG_BLOCK, &signals, &osignals)) {
-       return STG_SIG_ERR;
+        RELEASE_LOCK(&sig_mutex);
+        return STG_SIG_ERR;
     }
     
     more_handlers(sig);
@@ -356,7 +383,8 @@ stg_sig_install(int sig, int spi, void *mask)
     if (sigaction(sig, &action, NULL))
     {
         errorBelch("sigaction");
-       return STG_SIG_ERR;
+        RELEASE_LOCK(&sig_mutex);
+        return STG_SIG_ERR;
     }
 
     signal_handlers[sig] = spi;
@@ -381,9 +409,11 @@ stg_sig_install(int sig, int spi, void *mask)
     if (sigprocmask(SIG_SETMASK, &osignals, NULL))
     {
         errorBelch("sigprocmask");
-       return STG_SIG_ERR;
+        RELEASE_LOCK(&sig_mutex);
+        return STG_SIG_ERR;
     }
 
+    RELEASE_LOCK(&sig_mutex);
     return previous_spi;
 }
 
@@ -636,11 +666,4 @@ resetDefaultHandlers(void)
     set_sigtstp_action(rtsFalse);
 }
 
-void
-freeSignalHandlers(void) {
-    if (signal_handlers != NULL) {
-        stgFree(signal_handlers);
-    }
-}
-
 #endif /* RTS_USER_SIGNALS */