--- /dev/null
+/*
+ * Asynchronous signal delivery functions.
+ *
+ * Copyright 2000-2009 Willy Tarreau <w@1wt.eu>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <signal.h>
+#include <common/standard.h>
+#include <types/signal.h>
+
+extern int signal_queue_len;
+extern struct signal_descriptor signal_state[];
+
+void signal_init();
+void signal_handler(int sig);
+void signal_register(int sig, void (*handler)(int));
+void __signal_process_queue();
+
+static inline void signal_process_queue()
+{
+ if (unlikely(signal_queue_len > 0))
+ __signal_process_queue();
+}
--- /dev/null
+/*
+ * Asynchronous signal delivery functions.
+ *
+ * Copyright 2000-2009 Willy Tarreau <w@1wt.eu>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <signal.h>
+#include <proto/signal.h>
+#include <proto/log.h>
+
+/* Principle : we keep an in-order list of the first occurrence of all received
+ * signals. All occurrences of a same signal are grouped though. The signal
+ * queue does not need to be deeper than the number of signals we can handle.
+ * The handlers will be called asynchronously with the signal number. They can
+ * check themselves the number of calls by checking the descriptor this signal.
+ */
+
+int signal_queue_len; /* length of signal queue, <= MAX_SIGNAL (1 entry per signal max) */
+int signal_queue[MAX_SIGNAL]; /* in-order queue of received signals */
+struct signal_descriptor signal_state[MAX_SIGNAL];
+sigset_t blocked_sig;
+
+void signal_init()
+{
+ signal_queue_len = 0;
+ memset(signal_queue, 0, sizeof(signal_queue));
+ memset(signal_state, 0, sizeof(signal_state));
+ sigfillset(&blocked_sig);
+}
+
+void signal_handler(int sig)
+{
+ if (sig < 0 || sig > MAX_SIGNAL || !signal_state[sig].handler) {
+ /* unhandled signal */
+ qfprintf(stderr, "Received unhandled signal %d. Signal has been disabled.\n", sig);
+ signal(sig, SIG_IGN);
+ return;
+ }
+
+ if (!signal_state[sig].count) {
+ /* signal was not queued yet */
+ if (signal_queue_len < MAX_SIGNAL)
+ signal_queue[signal_queue_len++] = sig;
+ else
+ qfprintf(stderr, "Signal %d : signal queue is unexpectedly full.\n", sig);
+ }
+ signal_state[sig].count++;
+ signal(sig, signal_handler); /* re-arm signal */
+}
+
+/* Register a handler for signal <sig>. Set it to NULL, SIG_DFL or SIG_IGN to
+ * remove the handler. The signal's queue is flushed and the signal is really
+ * registered (or unregistered) for the process. The interface is the same as
+ * for standard signal delivery, except that the handler does not need to rearm
+ * the signal itself (it can disable it however).
+ */
+void signal_register(int sig, void (*handler)(int))
+{
+ if (sig < 0 || sig > MAX_SIGNAL) {
+ qfprintf(stderr, "Failed to register signal %d : out of range [0..%d].\n", sig, MAX_SIGNAL);
+ return;
+ }
+
+ signal_state[sig].count = 0;
+ if (handler == NULL)
+ handler = SIG_IGN;
+
+ if (handler != SIG_IGN && handler != SIG_DFL) {
+ signal_state[sig].handler = handler;
+ signal(sig, signal_handler);
+ }
+ else {
+ signal_state[sig].handler = NULL;
+ signal(sig, handler);
+ }
+}
+
+/* Call handlers of all pending signals and clear counts and queue length. The
+ * handlers may unregister themselves by calling signal_register() while they
+ * are called, just like it is done with normal signal handlers.
+ * Note that it is more efficient to call the inline version which checks the
+ * queue length before getting here.
+ */
+void __signal_process_queue()
+{
+ int sig, cur_pos = 0;
+ struct signal_descriptor *desc;
+ sigset_t old_sig;
+
+ /* block signal delivery during processing */
+ sigprocmask(SIG_SETMASK, &blocked_sig, &old_sig);
+
+ for (cur_pos = 0; cur_pos < signal_queue_len; cur_pos++) {
+ sig = signal_queue[cur_pos];
+ desc = &signal_state[sig];
+ if (desc->count) {
+ if (desc->handler)
+ desc->handler(sig);
+ desc->count = 0;
+ }
+ }
+ signal_queue_len = 0;
+
+ /* restore signal delivery */
+ sigprocmask(SIG_SETMASK, &old_sig, NULL);
+}