]> git.ipfire.org Git - thirdparty/gnulib.git/commitdiff
fatal-signal: Make really multithread-safe.
authorBruno Haible <bruno@clisp.org>
Sat, 16 May 2026 21:36:09 +0000 (23:36 +0200)
committerBruno Haible <bruno@clisp.org>
Sat, 16 May 2026 21:46:35 +0000 (23:46 +0200)
* lib/fatal-signal.h (block_fatal_signals): Document a constraint
regarding thread creation.
* lib/fatal-signal.c: Include sigdelay.h.
(fatal_signals_block_initially_mt): New variable.
(block_fatal_signals, unblock_fatal_signals): In a multithreaded
process, use sigdelay instead of pthread_sigmask.
* modules/fatal-signal (Depends-on): Add sigdelay.

ChangeLog
lib/fatal-signal.c
lib/fatal-signal.h
modules/fatal-signal

index c51d480e87d19d4ecd3b7ac216211b898eccca30..e6c9333e7455467b744b6289d1f0b9a72f2a33a0 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2026-05-16  Bruno Haible  <bruno@clisp.org>
+
+       fatal-signal: Make really multithread-safe.
+       * lib/fatal-signal.h (block_fatal_signals): Document a constraint
+       regarding thread creation.
+       * lib/fatal-signal.c: Include sigdelay.h.
+       (fatal_signals_block_initially_mt): New variable.
+       (block_fatal_signals, unblock_fatal_signals): In a multithreaded
+       process, use sigdelay instead of pthread_sigmask.
+       * modules/fatal-signal (Depends-on): Add sigdelay.
+
 2026-05-16  Bruno Haible  <bruno@clisp.org>
 
        thread-optim: Add tests.
index 33c99d5b8c5fd83a868fedd0c44c4233b655586b..c8fb328bbb7606defd704bb2e530a8ecfbfdcdb3 100644 (file)
@@ -29,6 +29,7 @@
 #include "glthread/lock.h"
 #include "glthread/once.h"
 #include "thread-optim.h"
+#include "sigdelay.h"
 #include "sig-handler.h"
 
 /* ========================================================================= */
@@ -299,6 +300,8 @@ init_fatal_signal_set (void)
    to occur in different threads and even overlap in time.  */
 gl_lock_define_initialized (static, fatal_signals_block_lock)
 static unsigned int fatal_signals_block_counter = 0;
+/* For correct operation in the face of thread-optim.h.  */
+static bool fatal_signals_block_initially_mt;
 
 /* Temporarily delay the catchable fatal signals.  */
 void
@@ -310,8 +313,22 @@ block_fatal_signals (void)
 
   if (fatal_signals_block_counter++ == 0)
     {
+      fatal_signals_block_initially_mt = mt;
       init_fatal_signal_set ();
-      pthread_sigmask (SIG_BLOCK, &fatal_signal_set, NULL);
+      if (mt)
+        sigdelay (SIG_BLOCK, &fatal_signal_set, NULL);
+      else
+        pthread_sigmask (SIG_BLOCK, &fatal_signal_set, NULL);
+    }
+  else
+    {
+      if (!fatal_signals_block_initially_mt && mt)
+        {
+          /* The process was single-threaded and has become multithreaded
+             before the matching unblock_fatal_signals() call.  This is
+             a constraint violation.  */
+          abort ();
+        }
     }
 
   if (mt) gl_lock_unlock (fatal_signals_block_lock);
@@ -331,8 +348,18 @@ unblock_fatal_signals (void)
     abort ();
   if (--fatal_signals_block_counter == 0)
     {
+      if (!fatal_signals_block_initially_mt && mt)
+        {
+          /* The process was single-threaded and has become multithreaded
+             at the matching unblock_fatal_signals() call.  This is a
+             constraint violation.  */
+          abort ();
+        }
       init_fatal_signal_set ();
-      pthread_sigmask (SIG_UNBLOCK, &fatal_signal_set, NULL);
+      if (fatal_signals_block_initially_mt)
+        sigdelay (SIG_UNBLOCK, &fatal_signal_set, NULL);
+      else
+        pthread_sigmask (SIG_UNBLOCK, &fatal_signal_set, NULL);
     }
 
   if (mt) gl_lock_unlock (fatal_signals_block_lock);
index 5cc3c25152819ce584ca5f4f26e9159d373113a3..fa21308a1d8ed8f4d78ace318c682eaf3c2a84a9 100644 (file)
@@ -77,7 +77,11 @@ extern int at_fatal_signal (_GL_ASYNC_SAFE void (*function) (int sig));
 /* Temporarily delay the catchable fatal signals.
    The signals will be blocked (= delayed) until the next call to
    unblock_fatal_signals().  If the signals are already blocked, a further
-   call to block_fatal_signals() has no effect.  */
+   call to block_fatal_signals() has no effect.
+   The program must obey the following constraint: If at the moment of a
+   block_fatal_signals() call the process is single-threaded, it MUST NOT
+   create additional threads until the matching unblock_fatal_signals()
+   call.  */
 extern void block_fatal_signals (void);
 
 /* Stop delaying the catchable fatal signals.  */
index 8741641bf54ab8e7ad31b57d507a84b8a6a3fba7..1561b17433214efc0347e6d1a727d80772dc370a 100644 (file)
@@ -15,6 +15,7 @@ sigaction
 lock
 once
 thread-optim
+sigdelay
 pthread_sigmask
 raise
 stdcountof-h