mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-04-11 03:31:36 +00:00
[MEDIUM] signals: support redistribution of signal zero when stopping
Signal zero is never delivered by the system. However having a signal to which functions and tasks can subscribe to be notified of a stopping event is useful. So this patch does two things : 1) allow signal zero to be delivered from any function of signal handler 2) make soft_stop() deliver this signal so that tasks can be notified of a stopping condition.
This commit is contained in:
parent
24f4efa670
commit
d0807c3c60
@ -19,6 +19,7 @@ extern int signal_queue_len;
|
||||
extern struct signal_descriptor signal_state[];
|
||||
extern struct pool_head *pool2_sig_handlers;
|
||||
|
||||
void signal_handler(int sig);
|
||||
void __signal_process_queue();
|
||||
int signal_init();
|
||||
void deinit_signals();
|
||||
|
@ -244,7 +244,9 @@ void usage(char *name)
|
||||
/*********************************************************************/
|
||||
|
||||
/*
|
||||
* upon SIGUSR1, let's have a soft stop.
|
||||
* upon SIGUSR1, let's have a soft stop. Note that soft_stop() broadcasts
|
||||
* a signal zero to all subscribers. This means that it's as easy as
|
||||
* subscribing to signal 0 to get informed about an imminent shutdown.
|
||||
*/
|
||||
void sig_soft_stop(struct sig_handler *sh)
|
||||
{
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include <proto/proto_tcp.h>
|
||||
#include <proto/proto_http.h>
|
||||
#include <proto/proxy.h>
|
||||
#include <proto/signal.h>
|
||||
|
||||
|
||||
int listeners; /* # of proxy listeners, set by cfgparse, unset by maintain_proxies */
|
||||
@ -568,6 +569,8 @@ void soft_stop(void)
|
||||
}
|
||||
p = p->next;
|
||||
}
|
||||
/* signal zero is used to broadcast the "stopping" event */
|
||||
signal_handler(0);
|
||||
}
|
||||
|
||||
|
||||
|
31
src/signal.c
31
src/signal.c
@ -29,9 +29,13 @@ int signal_queue[MAX_SIGNAL]; /* in-order queue of received
|
||||
struct signal_descriptor signal_state[MAX_SIGNAL];
|
||||
struct pool_head *pool2_sig_handlers = NULL;
|
||||
sigset_t blocked_sig;
|
||||
int signal_pending = 0; /* non-zero if t least one signal remains unprocessed */
|
||||
|
||||
/* Common signal handler, used by all signals. Received signals are queued. */
|
||||
static void signal_handler(int sig)
|
||||
/* 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.
|
||||
*/
|
||||
void signal_handler(int sig)
|
||||
{
|
||||
if (sig < 0 || sig > MAX_SIGNAL) {
|
||||
/* unhandled signal */
|
||||
@ -47,8 +51,10 @@ static void signal_handler(int sig)
|
||||
else
|
||||
qfprintf(stderr, "Signal %d : signal queue is unexpectedly full.\n", sig);
|
||||
}
|
||||
|
||||
signal_state[sig].count++;
|
||||
signal(sig, signal_handler); /* re-arm signal */
|
||||
if (sig)
|
||||
signal(sig, signal_handler); /* re-arm signal */
|
||||
}
|
||||
|
||||
/* Call handlers of all pending signals and clear counts and queue length. The
|
||||
@ -66,6 +72,11 @@ void __signal_process_queue()
|
||||
/* block signal delivery during processing */
|
||||
sigprocmask(SIG_SETMASK, &blocked_sig, &old_sig);
|
||||
|
||||
/* It is important that we scan the queue forwards so that we can
|
||||
* catch any signal that would have been queued by another signal
|
||||
* handler. That allows real signal handlers to redistribute signals
|
||||
* to tasks subscribed to signal zero.
|
||||
*/
|
||||
for (cur_pos = 0; cur_pos < signal_queue_len; cur_pos++) {
|
||||
sig = signal_queue[cur_pos];
|
||||
desc = &signal_state[sig];
|
||||
@ -121,7 +132,9 @@ void deinit_signals()
|
||||
* newly allocated sig_handler is returned, or NULL in case of any error. The
|
||||
* caller is responsible for unregistering the function when not used anymore.
|
||||
* Note that passing a NULL as the function pointer enables interception of the
|
||||
* signal without processing, which is identical to SIG_IGN.
|
||||
* signal without processing, which is identical to SIG_IGN. If the signal is
|
||||
* zero (which the system cannot deliver), only internal functions will be able
|
||||
* to notify the registered functions.
|
||||
*/
|
||||
struct sig_handler *signal_register_fct(int sig, void (*fct)(struct sig_handler *), int arg)
|
||||
{
|
||||
@ -130,7 +143,8 @@ struct sig_handler *signal_register_fct(int sig, void (*fct)(struct sig_handler
|
||||
if (sig < 0 || sig > MAX_SIGNAL)
|
||||
return NULL;
|
||||
|
||||
signal(sig, signal_handler);
|
||||
if (sig)
|
||||
signal(sig, signal_handler);
|
||||
|
||||
if (!fct)
|
||||
return NULL;
|
||||
@ -150,7 +164,9 @@ struct sig_handler *signal_register_fct(int sig, void (*fct)(struct sig_handler
|
||||
* allocated sig_handler is returned, or NULL in case of any error. The caller
|
||||
* is responsible for unregistering the task when not used anymore. Note that
|
||||
* passing a NULL as the task pointer enables interception of the signal
|
||||
* without processing, which is identical to SIG_IGN.
|
||||
* without processing, which is identical to SIG_IGN. If the signal is zero
|
||||
* (which the system cannot deliver), only internal functions will be able to
|
||||
* notify the registered functions.
|
||||
*/
|
||||
struct sig_handler *signal_register_task(int sig, struct task *task, int reason)
|
||||
{
|
||||
@ -159,7 +175,8 @@ struct sig_handler *signal_register_task(int sig, struct task *task, int reason)
|
||||
if (sig < 0 || sig > MAX_SIGNAL)
|
||||
return NULL;
|
||||
|
||||
signal(sig, signal_handler);
|
||||
if (sig)
|
||||
signal(sig, signal_handler);
|
||||
|
||||
if (!task)
|
||||
return NULL;
|
||||
|
Loading…
Reference in New Issue
Block a user