blob: 7de17abfc9eeb8a00ea89eee72c79a7320d3c223 [file] [log] [blame]
Willy Tarreau8f38bd02009-05-10 08:53:33 +02001/*
2 * Asynchronous signal delivery functions.
3 *
4 * Copyright 2000-2009 Willy Tarreau <w@1wt.eu>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 */
12
13#include <signal.h>
14#include <proto/signal.h>
15#include <proto/log.h>
16
17/* Principle : we keep an in-order list of the first occurrence of all received
18 * signals. All occurrences of a same signal are grouped though. The signal
19 * queue does not need to be deeper than the number of signals we can handle.
20 * The handlers will be called asynchronously with the signal number. They can
21 * check themselves the number of calls by checking the descriptor this signal.
22 */
23
24int signal_queue_len; /* length of signal queue, <= MAX_SIGNAL (1 entry per signal max) */
25int signal_queue[MAX_SIGNAL]; /* in-order queue of received signals */
26struct signal_descriptor signal_state[MAX_SIGNAL];
27sigset_t blocked_sig;
28
29void signal_init()
30{
31 signal_queue_len = 0;
32 memset(signal_queue, 0, sizeof(signal_queue));
33 memset(signal_state, 0, sizeof(signal_state));
34 sigfillset(&blocked_sig);
35}
36
37void signal_handler(int sig)
38{
39 if (sig < 0 || sig > MAX_SIGNAL || !signal_state[sig].handler) {
40 /* unhandled signal */
41 qfprintf(stderr, "Received unhandled signal %d. Signal has been disabled.\n", sig);
42 signal(sig, SIG_IGN);
43 return;
44 }
45
46 if (!signal_state[sig].count) {
47 /* signal was not queued yet */
48 if (signal_queue_len < MAX_SIGNAL)
49 signal_queue[signal_queue_len++] = sig;
50 else
51 qfprintf(stderr, "Signal %d : signal queue is unexpectedly full.\n", sig);
52 }
53 signal_state[sig].count++;
54 signal(sig, signal_handler); /* re-arm signal */
55}
56
57/* Register a handler for signal <sig>. Set it to NULL, SIG_DFL or SIG_IGN to
58 * remove the handler. The signal's queue is flushed and the signal is really
59 * registered (or unregistered) for the process. The interface is the same as
60 * for standard signal delivery, except that the handler does not need to rearm
61 * the signal itself (it can disable it however).
62 */
63void signal_register(int sig, void (*handler)(int))
64{
65 if (sig < 0 || sig > MAX_SIGNAL) {
66 qfprintf(stderr, "Failed to register signal %d : out of range [0..%d].\n", sig, MAX_SIGNAL);
67 return;
68 }
69
70 signal_state[sig].count = 0;
71 if (handler == NULL)
72 handler = SIG_IGN;
73
74 if (handler != SIG_IGN && handler != SIG_DFL) {
75 signal_state[sig].handler = handler;
76 signal(sig, signal_handler);
77 }
78 else {
79 signal_state[sig].handler = NULL;
80 signal(sig, handler);
81 }
82}
83
84/* Call handlers of all pending signals and clear counts and queue length. The
85 * handlers may unregister themselves by calling signal_register() while they
86 * are called, just like it is done with normal signal handlers.
87 * Note that it is more efficient to call the inline version which checks the
88 * queue length before getting here.
89 */
90void __signal_process_queue()
91{
92 int sig, cur_pos = 0;
93 struct signal_descriptor *desc;
94 sigset_t old_sig;
95
96 /* block signal delivery during processing */
97 sigprocmask(SIG_SETMASK, &blocked_sig, &old_sig);
98
99 for (cur_pos = 0; cur_pos < signal_queue_len; cur_pos++) {
100 sig = signal_queue[cur_pos];
101 desc = &signal_state[sig];
102 if (desc->count) {
103 if (desc->handler)
104 desc->handler(sig);
105 desc->count = 0;
106 }
107 }
108 signal_queue_len = 0;
109
110 /* restore signal delivery */
111 sigprocmask(SIG_SETMASK, &old_sig, NULL);
112}