tevent: Fix bug 9550 - sigprocmask does not work on FreeBSD to stop further signals...
[metze/samba/wip.git] / lib / tevent / tevent_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      ** NOTE! The following LGPL license applies to the tevent
9      ** library. This does NOT imply that all of Samba is released
10      ** under the LGPL
11
12    This library is free software; you can redistribute it and/or
13    modify it under the terms of the GNU Lesser General Public
14    License as published by the Free Software Foundation; either
15    version 3 of the License, or (at your option) any later version.
16
17    This library is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20    Lesser General Public License for more details.
21
22    You should have received a copy of the GNU Lesser General Public
23    License along with this library; if not, see <http://www.gnu.org/licenses/>.
24 */
25
26 #include "replace.h"
27 #include "system/filesys.h"
28 #include "system/wait.h"
29 #include "tevent.h"
30 #include "tevent_internal.h"
31 #include "tevent_util.h"
32
33 #define TEVENT_NUM_SIGNALS 64
34
35 /* maximum number of SA_SIGINFO signals to hold in the queue.
36   NB. This *MUST* be a power of 2, in order for the ring buffer
37   wrap to work correctly. Thanks to Petr Vandrovec <petr@vandrovec.name>
38   for this. */
39
40 #define TEVENT_SA_INFO_QUEUE_COUNT 64
41
42 struct tevent_sigcounter {
43         uint32_t count;
44         uint32_t seen;
45 };
46
47 #define TEVENT_SIG_INCREMENT(s) (s).count++
48 #define TEVENT_SIG_SEEN(s, n) (s).seen += (n)
49 #define TEVENT_SIG_PENDING(s) ((s).seen != (s).count)
50
51 struct tevent_common_signal_list {
52         struct tevent_common_signal_list *prev, *next;
53         struct tevent_signal *se;
54 };
55
56 /*
57   the poor design of signals means that this table must be static global
58 */
59 static struct tevent_sig_state {
60         struct tevent_common_signal_list *sig_handlers[TEVENT_NUM_SIGNALS+1];
61         struct sigaction *oldact[TEVENT_NUM_SIGNALS+1];
62         struct tevent_sigcounter signal_count[TEVENT_NUM_SIGNALS+1];
63         struct tevent_sigcounter got_signal;
64 #ifdef SA_SIGINFO
65         /* with SA_SIGINFO we get quite a lot of info per signal */
66         siginfo_t *sig_info[TEVENT_NUM_SIGNALS+1];
67         struct tevent_sigcounter sig_blocked[TEVENT_NUM_SIGNALS+1];
68 #endif
69 } *sig_state;
70
71 /*
72   return number of sigcounter events not processed yet
73 */
74 static uint32_t tevent_sig_count(struct tevent_sigcounter s)
75 {
76         return s.count - s.seen;
77 }
78
79 /*
80   signal handler - redirects to registered signals
81 */
82 static void tevent_common_signal_handler(int signum)
83 {
84         char c = 0;
85         struct tevent_common_signal_list *sl;
86         struct tevent_context *ev = NULL;
87         int saved_errno = errno;
88
89         TEVENT_SIG_INCREMENT(sig_state->signal_count[signum]);
90         TEVENT_SIG_INCREMENT(sig_state->got_signal);
91
92         /* Write to each unique event context. */
93         for (sl = sig_state->sig_handlers[signum]; sl; sl = sl->next) {
94                 if (sl->se->event_ctx && sl->se->event_ctx != ev) {
95                         ev = sl->se->event_ctx;
96                         /* doesn't matter if this pipe overflows */
97                         (void) write(ev->pipe_fds[1], &c, 1);
98                 }
99         }
100
101         errno = saved_errno;
102 }
103
104 #ifdef SA_SIGINFO
105 /*
106   signal handler with SA_SIGINFO - redirects to registered signals
107 */
108 static void tevent_common_signal_handler_info(int signum, siginfo_t *info,
109                                               void *uctx)
110 {
111         uint32_t count = tevent_sig_count(sig_state->signal_count[signum]);
112         /* sig_state->signal_count[signum].seen % TEVENT_SA_INFO_QUEUE_COUNT
113          * is the base of the unprocessed signals in the ringbuffer. */
114         uint32_t ofs = (sig_state->signal_count[signum].seen + count) %
115                                 TEVENT_SA_INFO_QUEUE_COUNT;
116         sig_state->sig_info[signum][ofs] = *info;
117
118         tevent_common_signal_handler(signum);
119
120         /* handle SA_SIGINFO */
121         if (count+1 == TEVENT_SA_INFO_QUEUE_COUNT) {
122                 /* we've filled the info array - block this signal until
123                    these ones are delivered */
124 #ifdef HAVE_UCONTEXT_T
125                 /*
126                  * This is the only way for this to work.
127                  * By default signum is blocked inside this
128                  * signal handler using a temporary mask,
129                  * but what we really need to do now is
130                  * block it in the callers mask, so it
131                  * stays blocked when the temporary signal
132                  * handler mask is replaced when we return
133                  * from here. The callers mask can be found
134                  * in the ucontext_t passed in as the
135                  * void *uctx argument.
136                  */
137                 ucontext_t *ucp = (ucontext_t *)uctx;
138                 sigaddset(&ucp->uc_sigmask, signum);
139 #else
140                 /*
141                  * WARNING !!! WARNING !!!!
142                  *
143                  * This code doesn't work.
144                  * By default signum is blocked inside this
145                  * signal handler, but calling sigprocmask
146                  * modifies the temporary signal mask being
147                  * used *inside* this handler, which will be
148                  * replaced by the callers signal mask once
149                  * we return from here. See Samba
150                  * bug #9550 for details.
151                  */
152                 sigset_t set;
153                 sigemptyset(&set);
154                 sigaddset(&set, signum);
155                 sigprocmask(SIG_BLOCK, &set, NULL);
156 #endif
157                 TEVENT_SIG_INCREMENT(sig_state->sig_blocked[signum]);
158         }
159 }
160 #endif
161
162 static int tevent_common_signal_list_destructor(struct tevent_common_signal_list *sl)
163 {
164         if (sig_state->sig_handlers[sl->se->signum]) {
165                 DLIST_REMOVE(sig_state->sig_handlers[sl->se->signum], sl);
166         }
167         return 0;
168 }
169
170 /*
171   destroy a signal event
172 */
173 static int tevent_signal_destructor(struct tevent_signal *se)
174 {
175         struct tevent_common_signal_list *sl;
176         sl = talloc_get_type(se->additional_data,
177                              struct tevent_common_signal_list);
178
179         if (se->event_ctx) {
180                 DLIST_REMOVE(se->event_ctx->signal_events, se);
181         }
182
183         talloc_free(sl);
184
185         if (sig_state->sig_handlers[se->signum] == NULL) {
186                 /* restore old handler, if any */
187                 if (sig_state->oldact[se->signum]) {
188                         sigaction(se->signum, sig_state->oldact[se->signum], NULL);
189                         sig_state->oldact[se->signum] = NULL;
190                 }
191 #ifdef SA_SIGINFO
192                 if (se->sa_flags & SA_SIGINFO) {
193                         if (sig_state->sig_info[se->signum]) {
194                                 talloc_free(sig_state->sig_info[se->signum]);
195                                 sig_state->sig_info[se->signum] = NULL;
196                         }
197                 }
198 #endif
199         }
200
201         return 0;
202 }
203
204 /*
205   this is part of the pipe hack needed to avoid the signal race condition
206 */
207 static void signal_pipe_handler(struct tevent_context *ev, struct tevent_fd *fde, 
208                                 uint16_t flags, void *_private)
209 {
210         char c[16];
211         /* its non-blocking, doesn't matter if we read too much */
212         (void) read(fde->fd, c, sizeof(c));
213 }
214
215 /*
216   add a signal event
217   return NULL on failure (memory allocation error)
218 */
219 struct tevent_signal *tevent_common_add_signal(struct tevent_context *ev,
220                                                TALLOC_CTX *mem_ctx,
221                                                int signum,
222                                                int sa_flags,
223                                                tevent_signal_handler_t handler,
224                                                void *private_data,
225                                                const char *handler_name,
226                                                const char *location)
227 {
228         struct tevent_signal *se;
229         struct tevent_common_signal_list *sl;
230         sigset_t set, oldset;
231
232         if (signum >= TEVENT_NUM_SIGNALS) {
233                 errno = EINVAL;
234                 return NULL;
235         }
236
237         /* the sig_state needs to be on a global context as it can last across
238            multiple event contexts */
239         if (sig_state == NULL) {
240                 sig_state = talloc_zero(NULL, struct tevent_sig_state);
241                 if (sig_state == NULL) {
242                         return NULL;
243                 }
244         }
245
246         se = talloc(mem_ctx?mem_ctx:ev, struct tevent_signal);
247         if (se == NULL) return NULL;
248
249         se->event_ctx           = ev;
250         se->signum              = signum;
251         se->sa_flags            = sa_flags;
252         se->handler             = handler;
253         se->private_data        = private_data;
254         se->handler_name        = handler_name;
255         se->location            = location;
256         se->additional_data     = NULL;
257
258         sl = talloc(se, struct tevent_common_signal_list);
259         if (!sl) {
260                 talloc_free(se);
261                 return NULL;
262         }
263         sl->se = se;
264         se->additional_data     = sl;
265
266         /* Ensure, no matter the destruction order, that we always have a handle on the global sig_state */
267         if (!talloc_reference(se, sig_state)) {
268                 talloc_free(se);
269                 return NULL;
270         }
271
272         /* we need to setup the pipe hack handler if not already
273            setup */
274         if (ev->pipe_fde == NULL) {
275                 if (pipe(ev->pipe_fds) == -1) {
276                         talloc_free(se);
277                         return NULL;
278                 }
279                 ev_set_blocking(ev->pipe_fds[0], false);
280                 ev_set_blocking(ev->pipe_fds[1], false);
281                 ev->pipe_fde = tevent_add_fd(ev, ev, ev->pipe_fds[0],
282                                              TEVENT_FD_READ,
283                                              signal_pipe_handler, NULL);
284                 if (!ev->pipe_fde) {
285                         close(ev->pipe_fds[0]);
286                         close(ev->pipe_fds[1]);
287                         talloc_free(se);
288                         return NULL;
289                 }
290         }
291
292         /* only install a signal handler if not already installed */
293         if (sig_state->sig_handlers[signum] == NULL) {
294                 struct sigaction act;
295                 ZERO_STRUCT(act);
296                 act.sa_handler = tevent_common_signal_handler;
297                 act.sa_flags = sa_flags;
298 #ifdef SA_SIGINFO
299                 if (sa_flags & SA_SIGINFO) {
300                         act.sa_handler   = NULL;
301                         act.sa_sigaction = tevent_common_signal_handler_info;
302                         if (sig_state->sig_info[signum] == NULL) {
303                                 sig_state->sig_info[signum] =
304                                         talloc_zero_array(sig_state, siginfo_t,
305                                                           TEVENT_SA_INFO_QUEUE_COUNT);
306                                 if (sig_state->sig_info[signum] == NULL) {
307                                         talloc_free(se);
308                                         return NULL;
309                                 }
310                         }
311                 }
312 #endif
313                 sig_state->oldact[signum] = talloc(sig_state, struct sigaction);
314                 if (sig_state->oldact[signum] == NULL) {
315                         talloc_free(se);
316                         return NULL;                    
317                 }
318                 if (sigaction(signum, &act, sig_state->oldact[signum]) == -1) {
319                         talloc_free(se);
320                         return NULL;
321                 }
322         }
323
324         DLIST_ADD(se->event_ctx->signal_events, se);
325
326         /* Make sure the signal doesn't come in while we're mangling list. */
327         sigemptyset(&set);
328         sigaddset(&set, signum);
329         sigprocmask(SIG_BLOCK, &set, &oldset);
330         DLIST_ADD(sig_state->sig_handlers[signum], sl);
331         sigprocmask(SIG_SETMASK, &oldset, NULL);
332
333         talloc_set_destructor(se, tevent_signal_destructor);
334         talloc_set_destructor(sl, tevent_common_signal_list_destructor);
335
336         return se;
337 }
338
339 struct tevent_se_exists {
340         struct tevent_se_exists **myself;
341 };
342
343 static int tevent_se_exists_destructor(struct tevent_se_exists *s)
344 {
345         *s->myself = NULL;
346         return 0;
347 }
348
349 /*
350   check if a signal is pending
351   return != 0 if a signal was pending
352 */
353 int tevent_common_check_signal(struct tevent_context *ev)
354 {
355         int i;
356
357         if (!sig_state || !TEVENT_SIG_PENDING(sig_state->got_signal)) {
358                 return 0;
359         }
360         
361         for (i=0;i<TEVENT_NUM_SIGNALS+1;i++) {
362                 struct tevent_common_signal_list *sl, *next;
363                 struct tevent_sigcounter counter = sig_state->signal_count[i];
364                 uint32_t count = tevent_sig_count(counter);
365 #ifdef SA_SIGINFO
366                 /* Ensure we null out any stored siginfo_t entries
367                  * after processing for debugging purposes. */
368                 bool clear_processed_siginfo = false;
369 #endif
370
371                 if (count == 0) {
372                         continue;
373                 }
374                 for (sl=sig_state->sig_handlers[i];sl;sl=next) {
375                         struct tevent_signal *se = sl->se;
376                         struct tevent_se_exists *exists;
377
378                         next = sl->next;
379
380                         /*
381                          * We have to be careful to not touch "se"
382                          * after it was deleted in its handler. Thus
383                          * we allocate a child whose destructor will
384                          * tell by nulling out itself that its parent
385                          * is gone.
386                          */
387                         exists = talloc(se, struct tevent_se_exists);
388                         if (exists == NULL) {
389                                 continue;
390                         }
391                         exists->myself = &exists;
392                         talloc_set_destructor(
393                                 exists, tevent_se_exists_destructor);
394
395 #ifdef SA_SIGINFO
396                         if (se->sa_flags & SA_SIGINFO) {
397                                 uint32_t j;
398
399                                 clear_processed_siginfo = true;
400
401                                 for (j=0;j<count;j++) {
402                                         /* sig_state->signal_count[i].seen
403                                          * % TEVENT_SA_INFO_QUEUE_COUNT is
404                                          * the base position of the unprocessed
405                                          * signals in the ringbuffer. */
406                                         uint32_t ofs = (counter.seen + j)
407                                                 % TEVENT_SA_INFO_QUEUE_COUNT;
408                                         se->handler(ev, se, i, 1,
409                                                     (void*)&sig_state->sig_info[i][ofs], 
410                                                     se->private_data);
411                                         if (!exists) {
412                                                 break;
413                                         }
414                                 }
415 #ifdef SA_RESETHAND
416                                 if (exists && (se->sa_flags & SA_RESETHAND)) {
417                                         talloc_free(se);
418                                 }
419 #endif
420                                 talloc_free(exists);
421                                 continue;
422                         }
423 #endif
424                         se->handler(ev, se, i, count, NULL, se->private_data);
425 #ifdef SA_RESETHAND
426                         if (exists && (se->sa_flags & SA_RESETHAND)) {
427                                 talloc_free(se);
428                         }
429 #endif
430                         talloc_free(exists);
431                 }
432
433 #ifdef SA_SIGINFO
434                 if (clear_processed_siginfo) {
435                         uint32_t j;
436                         for (j=0;j<count;j++) {
437                                 uint32_t ofs = (counter.seen + j)
438                                         % TEVENT_SA_INFO_QUEUE_COUNT;
439                                 memset((void*)&sig_state->sig_info[i][ofs],
440                                         '\0',
441                                         sizeof(siginfo_t));
442                         }
443                 }
444 #endif
445
446                 TEVENT_SIG_SEEN(sig_state->signal_count[i], count);
447                 TEVENT_SIG_SEEN(sig_state->got_signal, count);
448
449 #ifdef SA_SIGINFO
450                 if (TEVENT_SIG_PENDING(sig_state->sig_blocked[i])) {
451                         /* We'd filled the queue, unblock the
452                            signal now the queue is empty again.
453                            Note we MUST do this after the
454                            TEVENT_SIG_SEEN(sig_state->signal_count[i], count)
455                            call to prevent a new signal running
456                            out of room in the sig_state->sig_info[i][]
457                            ring buffer. */
458                         sigset_t set;
459                         sigemptyset(&set);
460                         sigaddset(&set, i);
461                         TEVENT_SIG_SEEN(sig_state->sig_blocked[i],
462                                  tevent_sig_count(sig_state->sig_blocked[i]));
463                         sigprocmask(SIG_UNBLOCK, &set, NULL);
464                 }
465 #endif
466         }
467
468         return 1;
469 }
470
471 void tevent_cleanup_pending_signal_handlers(struct tevent_signal *se)
472 {
473         struct tevent_common_signal_list *sl;
474         sl = talloc_get_type(se->additional_data,
475                              struct tevent_common_signal_list);
476
477         tevent_common_signal_list_destructor(sl);
478
479         if (sig_state->sig_handlers[se->signum] == NULL) {
480                 if (sig_state->oldact[se->signum]) {
481                         sigaction(se->signum, sig_state->oldact[se->signum], NULL);
482                         sig_state->oldact[se->signum] = NULL;
483                 }
484         }
485         return;
486 }