[MINOR] add basic signal handling functions
These functions will be used to deliver asynchronous signals in order to make the signal handling functions more robust. The goal is to keep the same interface to signal handlers.
This commit is contained in:
parent
36db02e6b1
commit
8f38bd0497
@ -166,4 +166,11 @@
|
||||
#define STATS_VERSION_STRING " version " HAPROXY_VERSION ", released " HAPROXY_DATE
|
||||
#endif
|
||||
|
||||
/* Maximum signal queue size, and also number of different signals we can
|
||||
* handle.
|
||||
*/
|
||||
#ifndef MAX_SIGNAL
|
||||
#define MAX_SIGNAL 256
|
||||
#endif
|
||||
|
||||
#endif /* _COMMON_DEFAULTS_H */
|
||||
|
29
include/proto/signal.h
Normal file
29
include/proto/signal.h
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
20
include/types/signal.h
Normal file
20
include/types/signal.h
Normal file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Asynchronous signal delivery functions descriptors.
|
||||
*
|
||||
* 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/config.h>
|
||||
#include <common/standard.h>
|
||||
|
||||
struct signal_descriptor {
|
||||
int count; /* number of times raised */
|
||||
void (*handler)(int sig);
|
||||
};
|
112
src/signal.c
Normal file
112
src/signal.c
Normal file
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user