mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-01-20 20:50:44 +00:00
be8c736cca
AIX wants string.h in signal.c (and is right to do so) : gcc -Iinclude -Wall -O2 -g -DTPROXY -DENABLE_POLL -DCONFIG_HAPROXY_VERSION=\"1.3.18\" -DCONFIG_HAPROXY_DATE=\"2009/05/10\" -c -o src/signal.o src/signal.c src/signal.c: In function 'signal_init': src/signal.c:32: warning: implicit declaration of function 'memset' src/signal.c:32: warning: incompatible implicit declaration of built-in function 'memset'
115 lines
3.5 KiB
C
115 lines
3.5 KiB
C
/*
|
|
* 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 <string.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);
|
|
}
|