mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-04-25 12:28:01 +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 signal_descriptor signal_state[];
|
||||||
extern struct pool_head *pool2_sig_handlers;
|
extern struct pool_head *pool2_sig_handlers;
|
||||||
|
|
||||||
|
void signal_handler(int sig);
|
||||||
void __signal_process_queue();
|
void __signal_process_queue();
|
||||||
int signal_init();
|
int signal_init();
|
||||||
void deinit_signals();
|
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)
|
void sig_soft_stop(struct sig_handler *sh)
|
||||||
{
|
{
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
#include <proto/proto_tcp.h>
|
#include <proto/proto_tcp.h>
|
||||||
#include <proto/proto_http.h>
|
#include <proto/proto_http.h>
|
||||||
#include <proto/proxy.h>
|
#include <proto/proxy.h>
|
||||||
|
#include <proto/signal.h>
|
||||||
|
|
||||||
|
|
||||||
int listeners; /* # of proxy listeners, set by cfgparse, unset by maintain_proxies */
|
int listeners; /* # of proxy listeners, set by cfgparse, unset by maintain_proxies */
|
||||||
@ -568,6 +569,8 @@ void soft_stop(void)
|
|||||||
}
|
}
|
||||||
p = p->next;
|
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 signal_descriptor signal_state[MAX_SIGNAL];
|
||||||
struct pool_head *pool2_sig_handlers = NULL;
|
struct pool_head *pool2_sig_handlers = NULL;
|
||||||
sigset_t blocked_sig;
|
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. */
|
/* Common signal handler, used by all signals. Received signals are queued.
|
||||||
static void signal_handler(int sig)
|
* 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) {
|
if (sig < 0 || sig > MAX_SIGNAL) {
|
||||||
/* unhandled signal */
|
/* unhandled signal */
|
||||||
@ -47,8 +51,10 @@ static void signal_handler(int sig)
|
|||||||
else
|
else
|
||||||
qfprintf(stderr, "Signal %d : signal queue is unexpectedly full.\n", sig);
|
qfprintf(stderr, "Signal %d : signal queue is unexpectedly full.\n", sig);
|
||||||
}
|
}
|
||||||
|
|
||||||
signal_state[sig].count++;
|
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
|
/* 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 */
|
/* block signal delivery during processing */
|
||||||
sigprocmask(SIG_SETMASK, &blocked_sig, &old_sig);
|
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++) {
|
for (cur_pos = 0; cur_pos < signal_queue_len; cur_pos++) {
|
||||||
sig = signal_queue[cur_pos];
|
sig = signal_queue[cur_pos];
|
||||||
desc = &signal_state[sig];
|
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
|
* 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.
|
* caller is responsible for unregistering the function when not used anymore.
|
||||||
* Note that passing a NULL as the function pointer enables interception of the
|
* 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)
|
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)
|
if (sig < 0 || sig > MAX_SIGNAL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
signal(sig, signal_handler);
|
if (sig)
|
||||||
|
signal(sig, signal_handler);
|
||||||
|
|
||||||
if (!fct)
|
if (!fct)
|
||||||
return NULL;
|
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
|
* 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
|
* is responsible for unregistering the task when not used anymore. Note that
|
||||||
* passing a NULL as the task pointer enables interception of the signal
|
* 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)
|
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)
|
if (sig < 0 || sig > MAX_SIGNAL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
signal(sig, signal_handler);
|
if (sig)
|
||||||
|
signal(sig, signal_handler);
|
||||||
|
|
||||||
if (!task)
|
if (!task)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
Loading…
Reference in New Issue
Block a user