From b79a94c9f3c6b741a219decfeb004896cd978795 Mon Sep 17 00:00:00 2001 From: Christopher Faulet Date: Tue, 30 May 2017 15:34:30 +0200 Subject: [PATCH] MEDIUM: threads/signal: Add a lock to make signals thread-safe A global lock has been added to protect the signal processing. So when a signal it triggered, only one thread will catch it. --- include/common/hathreads.h | 4 +++- include/proto/signal.h | 6 ++++++ src/haproxy.c | 4 ++++ src/signal.c | 11 +++++++++++ 4 files changed, 24 insertions(+), 1 deletion(-) diff --git a/include/common/hathreads.h b/include/common/hathreads.h index 19cdf83..53b4e3d 100644 --- a/include/common/hathreads.h +++ b/include/common/hathreads.h @@ -145,6 +145,7 @@ enum lock_label { TASK_RQ_LOCK, TASK_WQ_LOCK, POOL_LOCK, + SIGNALS_LOCK, LOCK_LABELS }; struct lock_stat { @@ -228,7 +229,8 @@ struct ha_rwlock { static inline void show_lock_stats() { const char *labels[LOCK_LABELS] = {"THREAD_SYNC", "FDTAB", "FDCACHE", "FD", "POLL", - "TASK_RQ", "TASK_WQ", "POOL" }; + "TASK_RQ", "TASK_WQ", "POOL", + "SIGNALS" }; int lbl; for (lbl = 0; lbl < LOCK_LABELS; lbl++) { diff --git a/include/proto/signal.h b/include/proto/signal.h index 6556446..084fa7d 100644 --- a/include/proto/signal.h +++ b/include/proto/signal.h @@ -13,6 +13,8 @@ #include #include +#include + #include #include @@ -20,6 +22,10 @@ extern int signal_queue_len; extern struct signal_descriptor signal_state[]; extern struct pool_head *pool2_sig_handlers; +#ifdef USE_THREAD +extern HA_SPINLOCK_T signals_lock; +#endif + void signal_handler(int sig); void __signal_process_queue(); int signal_init(); diff --git a/src/haproxy.c b/src/haproxy.c index ff63844..81122c8 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -2819,6 +2819,10 @@ int main(int argc, char **argv) free(tids); free(threads); +#if defined(DEBUG_THREAD) || defined(DEBUG_FULL) + show_lock_stats(); +#endif + #endif /* USE_THREAD */ } else { diff --git a/src/signal.c b/src/signal.c index 201c93f..14e4f1e 100644 --- a/src/signal.c +++ b/src/signal.c @@ -31,6 +31,10 @@ struct pool_head *pool2_sig_handlers = NULL; sigset_t blocked_sig; int signal_pending = 0; /* non-zero if t least one signal remains unprocessed */ +#ifdef USE_THREAD +HA_SPINLOCK_T signals_lock; +#endif + /* Common signal handler, used by all signals. Received signals are queued. * Signal number zero has a specific status, as it cannot be delivered by the * system, any function may call it to perform asynchronous signal delivery. @@ -69,6 +73,9 @@ void __signal_process_queue() struct signal_descriptor *desc; sigset_t old_sig; + if (SPIN_TRYLOCK(SIGNALS_LOCK, &signals_lock)) + return; + /* block signal delivery during processing */ sigprocmask(SIG_SETMASK, &blocked_sig, &old_sig); @@ -95,6 +102,7 @@ void __signal_process_queue() /* restore signal delivery */ sigprocmask(SIG_SETMASK, &old_sig, NULL); + SPIN_UNLOCK(SIGNALS_LOCK, &signals_lock); } /* perform minimal intializations, report 0 in case of error, 1 if OK. */ @@ -106,6 +114,8 @@ int signal_init() memset(signal_queue, 0, sizeof(signal_queue)); memset(signal_state, 0, sizeof(signal_state)); + SPIN_INIT(&signals_lock); + /* Ensure signals are not blocked. Some shells or service managers may * accidently block all of our signals unfortunately, causing lots of * zombie processes to remain in the background during reloads. @@ -140,6 +150,7 @@ void deinit_signals() pool_free2(pool2_sig_handlers, sh); } } + SPIN_DESTROY(&signals_lock); } /* Register a function and an integer argument on a signal. A pointer to the -- 1.7.10.4