[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:
Willy Tarreau 2009-05-10 08:53:33 +02:00
parent 36db02e6b1
commit 8f38bd0497
4 changed files with 168 additions and 0 deletions

View File

@ -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
View 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
View 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
View 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);
}