summaryrefslogtreecommitdiff
path: root/lib/fatal-signal.c
diff options
context:
space:
mode:
authorDongHun Kwak <dh0128.kwak@samsung.com>2021-03-05 10:08:27 +0900
committerDongHun Kwak <dh0128.kwak@samsung.com>2021-03-05 10:08:27 +0900
commita2c7c975f0813d307b31d06da2c015916a6bb16d (patch)
tree985a31e8c860c690d9f20e6621ce5fcc05ccd244 /lib/fatal-signal.c
parentdc6b8fd841f8acf37e6d3f7642e71cae175505bd (diff)
downloadwget-a2c7c975f0813d307b31d06da2c015916a6bb16d.tar.gz
wget-a2c7c975f0813d307b31d06da2c015916a6bb16d.tar.bz2
wget-a2c7c975f0813d307b31d06da2c015916a6bb16d.zip
Imported Upstream version 1.21upstream/1.21
Diffstat (limited to 'lib/fatal-signal.c')
-rw-r--r--lib/fatal-signal.c93
1 files changed, 76 insertions, 17 deletions
diff --git a/lib/fatal-signal.c b/lib/fatal-signal.c
index c9153f1..14ecfe7 100644
--- a/lib/fatal-signal.c
+++ b/lib/fatal-signal.c
@@ -1,5 +1,5 @@
/* Emergency actions in case of a fatal signal.
- Copyright (C) 2003-2004, 2006-2019 Free Software Foundation, Inc.
+ Copyright (C) 2003-2004, 2006-2020 Free Software Foundation, Inc.
Written by Bruno Haible <bruno@clisp.org>, 2003.
This program is free software: you can redistribute it and/or modify
@@ -26,6 +26,8 @@
#include <signal.h>
#include <unistd.h>
+#include "glthread/lock.h"
+#include "thread-optim.h"
#include "sig-handler.h"
#include "xalloc.h"
@@ -85,6 +87,10 @@ static int fatal_signals[] =
static void
init_fatal_signals (void)
{
+ /* This function is multithread-safe even without synchronization, because
+ if two threads execute it simultaneously, the fatal_signals[] array will
+ not change any more after the first of the threads has completed this
+ function. */
static bool fatal_signals_initialized = false;
if (!fatal_signals_initialized)
{
@@ -200,11 +206,18 @@ install_handlers (void)
}
+/* Lock that makes at_fatal_signal multi-thread safe. */
+gl_lock_define_initialized (static, at_fatal_signal_lock)
+
/* Register a cleanup function to be executed when a catchable fatal signal
occurs. */
void
at_fatal_signal (action_t action)
{
+ bool mt = gl_multithreaded ();
+
+ if (mt) gl_lock_lock (at_fatal_signal_lock);
+
static bool cleanup_initialized = false;
if (!cleanup_initialized)
{
@@ -233,8 +246,15 @@ at_fatal_signal (action_t action)
actions = new_actions;
actions_allocated = new_actions_allocated;
/* Now we can free the old actions array. */
+ /* No, we can't do that. If fatal_signal_handler is running in a
+ different thread and has already fetched the actions pointer (getting
+ old_actions) but not yet accessed its n-th element, that thread may
+ crash when accessing an element of the already freed old_actions
+ array. */
+ #if 0
if (old_actions != static_actions)
free (old_actions);
+ #endif
}
/* The two uses of 'volatile' in the types above (and ISO C 99 section
5.1.2.3.(5)) ensure that we increment the actions_count only after
@@ -242,6 +262,8 @@ at_fatal_signal (action_t action)
actions[actions_count]. */
actions[actions_count].action = action;
actions_count++;
+
+ if (mt) gl_lock_unlock (at_fatal_signal_lock);
}
@@ -251,38 +273,68 @@ at_fatal_signal (action_t action)
static sigset_t fatal_signal_set;
static void
-init_fatal_signal_set (void)
+do_init_fatal_signal_set (void)
{
- static bool fatal_signal_set_initialized = false;
- if (!fatal_signal_set_initialized)
- {
- size_t i;
+ size_t i;
- init_fatal_signals ();
+ init_fatal_signals ();
- sigemptyset (&fatal_signal_set);
- for (i = 0; i < num_fatal_signals; i++)
- if (fatal_signals[i] >= 0)
- sigaddset (&fatal_signal_set, fatal_signals[i]);
+ sigemptyset (&fatal_signal_set);
+ for (i = 0; i < num_fatal_signals; i++)
+ if (fatal_signals[i] >= 0)
+ sigaddset (&fatal_signal_set, fatal_signals[i]);
+}
- fatal_signal_set_initialized = true;
- }
+/* Ensure that do_init_fatal_signal_set is called once only. */
+gl_once_define(static, fatal_signal_set_once)
+
+static void
+init_fatal_signal_set (void)
+{
+ gl_once (fatal_signal_set_once, do_init_fatal_signal_set);
}
+/* Lock and counter that allow block_fatal_signals/unblock_fatal_signals pairs
+ 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;
+
/* Temporarily delay the catchable fatal signals. */
void
block_fatal_signals (void)
{
- init_fatal_signal_set ();
- sigprocmask (SIG_BLOCK, &fatal_signal_set, NULL);
+ bool mt = gl_multithreaded ();
+
+ if (mt) gl_lock_lock (fatal_signals_block_lock);
+
+ if (fatal_signals_block_counter++ == 0)
+ {
+ init_fatal_signal_set ();
+ sigprocmask (SIG_BLOCK, &fatal_signal_set, NULL);
+ }
+
+ if (mt) gl_lock_unlock (fatal_signals_block_lock);
}
/* Stop delaying the catchable fatal signals. */
void
unblock_fatal_signals (void)
{
- init_fatal_signal_set ();
- sigprocmask (SIG_UNBLOCK, &fatal_signal_set, NULL);
+ bool mt = gl_multithreaded ();
+
+ if (mt) gl_lock_lock (fatal_signals_block_lock);
+
+ if (fatal_signals_block_counter == 0)
+ /* There are more calls to unblock_fatal_signals() than to
+ block_fatal_signals(). */
+ abort ();
+ if (--fatal_signals_block_counter == 0)
+ {
+ init_fatal_signal_set ();
+ sigprocmask (SIG_UNBLOCK, &fatal_signal_set, NULL);
+ }
+
+ if (mt) gl_lock_unlock (fatal_signals_block_lock);
}
@@ -301,3 +353,10 @@ get_fatal_signals (int signals[64])
return p - signals;
}
}
+
+const sigset_t *
+get_fatal_signal_set (void)
+{
+ init_fatal_signal_set ();
+ return &fatal_signal_set;
+}