diff options
author | DongHun Kwak <dh0128.kwak@samsung.com> | 2021-03-05 10:08:27 +0900 |
---|---|---|
committer | DongHun Kwak <dh0128.kwak@samsung.com> | 2021-03-05 10:08:27 +0900 |
commit | a2c7c975f0813d307b31d06da2c015916a6bb16d (patch) | |
tree | 985a31e8c860c690d9f20e6621ce5fcc05ccd244 /lib/fatal-signal.c | |
parent | dc6b8fd841f8acf37e6d3f7642e71cae175505bd (diff) | |
download | wget-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.c | 93 |
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; +} |