r20930: use sigaction() instead of signal()
[metze/samba/wip.git] / source / lib / events / events_signal.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    common events code for signal events
5
6    Copyright (C) Andrew Tridgell        2007
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24 #include "system/filesys.h"
25 #include "system/select.h"
26 #include "lib/util/dlinklist.h"
27 #include "lib/events/events.h"
28 #include "lib/events/events_internal.h"
29
30 #define NUM_SIGNALS 64
31
32 /* maximum number of SA_SIGINFO signals to hold in the queue */
33 #define SA_INFO_QUEUE_COUNT 10
34
35 /*
36   the poor design of signals means that this table must be static global
37 */
38 static struct {
39         struct signal_event *sig_handlers[NUM_SIGNALS];
40         struct sigaction oldact[NUM_SIGNALS];
41         uint32_t signal_count[NUM_SIGNALS];
42         uint32_t got_signal;
43         int pipe_hack[2];
44 #ifdef SA_SIGINFO
45         /* with SA_SIGINFO we get quite a lot of info per signal */
46         siginfo_t sig_info[NUM_SIGNALS][SA_INFO_QUEUE_COUNT];
47 #endif
48 } sig_state;
49
50
51 /*
52   signal handler - redirects to registered signals
53 */
54 static void signal_handler(int signum)
55 {
56         char c = 0;
57         sig_state.signal_count[signum]++;
58         sig_state.got_signal++;
59         /* doesn't matter if this pipe overflows */
60         write(sig_state.pipe_hack[1], &c, 1);
61 }
62
63 #ifdef SA_SIGINFO
64 /*
65   signal handler with SA_SIGINFO - redirects to registered signals
66 */
67 static void signal_handler_info(int signum, siginfo_t *info, void *uctx)
68 {
69         sig_state.sig_info[signum][sig_state.signal_count[signum]] = *info;
70
71         signal_handler(signum);
72
73         /* handle SA_SIGINFO */
74         if (sig_state.signal_count[signum] == SA_INFO_QUEUE_COUNT) {
75                 /* we've filled the info array - block this signal until
76                    these ones are delivered */
77                 sigset_t set;
78                 sigemptyset(&set);
79                 sigaddset(&set, signum);
80                 sigprocmask(SIG_BLOCK, &set, NULL);
81         }
82 }
83 #endif
84
85 /*
86   destroy a signal event
87 */
88 static int signal_event_destructor(struct signal_event *se)
89 {
90         se->event_ctx->num_signal_handlers--;
91         DLIST_REMOVE(sig_state.sig_handlers[se->signum], se);
92         if (sig_state.sig_handlers[se->signum] == NULL) {
93                 /* restore old handler, if any */
94                 sigaction(se->signum, &sig_state.oldact[se->signum], NULL);
95         }
96         return 0;
97 }
98
99 /*
100   this is part of the pipe hack needed to avoid the signal race condition
101 */
102 static void signal_pipe_handler(struct event_context *ev, struct fd_event *fde, 
103                                 uint16_t flags, void *private)
104 {
105         char c[16];
106         /* its non-blocking, doesn't matter if we read too much */
107         read(sig_state.pipe_hack[0], c, sizeof(c));
108 }
109
110 /*
111   add a signal event
112   return NULL on failure (memory allocation error)
113 */
114 struct signal_event *common_event_add_signal(struct event_context *ev, 
115                                              TALLOC_CTX *mem_ctx,
116                                              int signum,
117                                              int sa_flags,
118                                              event_signal_handler_t handler, 
119                                              void *private_data) 
120 {
121         struct signal_event *se;
122
123         if (signum >= NUM_SIGNALS) {
124                 return NULL;
125         }
126
127         se = talloc(mem_ctx?mem_ctx:ev, struct signal_event);
128         if (se == NULL) return NULL;
129
130         se->event_ctx           = ev;
131         se->handler             = handler;
132         se->private_data        = private_data;
133         se->signum              = signum;
134         se->sa_flags            = sa_flags;
135
136         /* only install a signal handler if not already installed */
137         if (sig_state.sig_handlers[signum] == NULL) {
138                 struct sigaction act;
139                 ZERO_STRUCT(act);
140                 act.sa_handler   = signal_handler;
141                 act.sa_flags = sa_flags;
142 #ifdef SA_SIGINFO
143                 if (sa_flags & SA_SIGINFO) {
144                         act.sa_handler   = NULL;
145                         act.sa_sigaction = signal_handler_info;
146                 }
147 #endif
148                 if (sigaction(signum, &act, &sig_state.oldact[signum]) == -1) {
149                         talloc_free(se);
150                         return NULL;
151                 }
152         }
153
154         DLIST_ADD(sig_state.sig_handlers[signum], se);
155
156         talloc_set_destructor(se, signal_event_destructor);
157
158         /* we need to setup the pipe hack handler if not already
159            setup */
160         if (ev->pipe_fde == NULL) {
161                 if (sig_state.pipe_hack[0] == 0 && 
162                     sig_state.pipe_hack[1] == 0) {
163                         pipe(sig_state.pipe_hack);
164                         set_blocking(sig_state.pipe_hack[0], False);
165                         set_blocking(sig_state.pipe_hack[1], False);
166                 }
167                 ev->pipe_fde = event_add_fd(ev, ev, sig_state.pipe_hack[0],
168                                             EVENT_FD_READ, signal_pipe_handler, NULL);
169         }
170         ev->num_signal_handlers++;
171
172         return se;
173 }
174
175
176 /*
177   check if a signal is pending
178   return != 0 if a signal was pending
179 */
180 int common_event_check_signal(struct event_context *ev)
181 {
182         int i;
183         if (sig_state.got_signal == 0) {
184                 return 0;
185         }
186         
187         for (i=0;i<NUM_SIGNALS+1;i++) {
188                 uint32_t count = sig_state.signal_count[i];
189                 if (count != 0) {
190                         struct signal_event *se, *next;
191                         for (se=sig_state.sig_handlers[i];se;se=next) {
192                                 next = se->next;
193 #ifdef SA_SIGINFO
194                                 if (se->sa_flags & SA_SIGINFO) {
195                                         int j;
196                                         for (j=0;j<count;j++) {
197                                                 se->handler(ev, se, i, 1, 
198                                                             (void*)&sig_state.sig_info[i][j], 
199                                                             se->private_data);
200                                         }
201                                         if (count == SA_INFO_QUEUE_COUNT) {
202                                                 /* we'd filled the queue, unblock the
203                                                    signal now */
204                                                 sigset_t set;
205                                                 sigemptyset(&set);
206                                                 sigaddset(&set, i);
207                                                 sigprocmask(SIG_UNBLOCK, &set, NULL);
208                                         }
209                                         continue;
210                                 }
211 #endif
212                                 se->handler(ev, se, i, count, NULL, se->private_data);
213                                 if (se->sa_flags & SA_RESETHAND) {
214                                         talloc_free(se);
215                                 }
216                         }
217                         sig_state.signal_count[i] -= count;
218                         sig_state.got_signal -= count;
219                 }
220         }
221
222         return 1;
223 }