~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to lib/tevent/tevent_signal.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 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 SA_INFO_QUEUE_COUNT 64
 
41
 
 
42
struct sigcounter {
 
43
        uint32_t count;
 
44
        uint32_t seen;
 
45
};
 
46
 
 
47
#define SIG_INCREMENT(s) (s).count++
 
48
#define SIG_SEEN(s, n) (s).seen += (n)
 
49
#define 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 sig_state {
 
60
        struct tevent_common_signal_list *sig_handlers[NUM_SIGNALS+1];
 
61
        struct sigaction *oldact[NUM_SIGNALS+1];
 
62
        struct sigcounter signal_count[NUM_SIGNALS+1];
 
63
        struct 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[NUM_SIGNALS+1];
 
67
        struct sigcounter sig_blocked[NUM_SIGNALS+1];
 
68
#endif
 
69
} *sig_state;
 
70
 
 
71
/*
 
72
  return number of sigcounter events not processed yet
 
73
*/
 
74
static uint32_t sig_count(struct 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
        ssize_t res;
 
86
        struct tevent_common_signal_list *sl;
 
87
        struct tevent_context *ev = NULL;
 
88
        int saved_errno = errno;
 
89
 
 
90
        SIG_INCREMENT(sig_state->signal_count[signum]);
 
91
        SIG_INCREMENT(sig_state->got_signal);
 
92
 
 
93
        /* Write to each unique event context. */
 
94
        for (sl = sig_state->sig_handlers[signum]; sl; sl = sl->next) {
 
95
                if (sl->se->event_ctx && sl->se->event_ctx != ev) {
 
96
                        ev = sl->se->event_ctx;
 
97
                        /* doesn't matter if this pipe overflows */
 
98
                        res = write(ev->pipe_fds[1], &c, 1);
 
99
                }
 
100
        }
 
101
 
 
102
        errno = saved_errno;
 
103
}
 
104
 
 
105
#ifdef SA_SIGINFO
 
106
/*
 
107
  signal handler with SA_SIGINFO - redirects to registered signals
 
108
*/
 
109
static void tevent_common_signal_handler_info(int signum, siginfo_t *info,
 
110
                                              void *uctx)
 
111
{
 
112
        uint32_t count = sig_count(sig_state->signal_count[signum]);
 
113
        /* sig_state->signal_count[signum].seen % SA_INFO_QUEUE_COUNT
 
114
         * is the base of the unprocessed signals in the ringbuffer. */
 
115
        uint32_t ofs = (sig_state->signal_count[signum].seen + count) %
 
116
                                SA_INFO_QUEUE_COUNT;
 
117
        sig_state->sig_info[signum][ofs] = *info;
 
118
 
 
119
        tevent_common_signal_handler(signum);
 
120
 
 
121
        /* handle SA_SIGINFO */
 
122
        if (count+1 == SA_INFO_QUEUE_COUNT) {
 
123
                /* we've filled the info array - block this signal until
 
124
                   these ones are delivered */
 
125
                sigset_t set;
 
126
                sigemptyset(&set);
 
127
                sigaddset(&set, signum);
 
128
                sigprocmask(SIG_BLOCK, &set, NULL);
 
129
                SIG_INCREMENT(sig_state->sig_blocked[signum]);
 
130
        }
 
131
}
 
132
#endif
 
133
 
 
134
static int tevent_common_signal_list_destructor(struct tevent_common_signal_list *sl)
 
135
{
 
136
        if (sig_state->sig_handlers[sl->se->signum]) {
 
137
                DLIST_REMOVE(sig_state->sig_handlers[sl->se->signum], sl);
 
138
        }
 
139
        return 0;
 
140
}
 
141
 
 
142
/*
 
143
  destroy a signal event
 
144
*/
 
145
static int tevent_signal_destructor(struct tevent_signal *se)
 
146
{
 
147
        struct tevent_common_signal_list *sl;
 
148
        sl = talloc_get_type(se->additional_data,
 
149
                             struct tevent_common_signal_list);
 
150
 
 
151
        if (se->event_ctx) {
 
152
                DLIST_REMOVE(se->event_ctx->signal_events, se);
 
153
        }
 
154
 
 
155
        talloc_free(sl);
 
156
 
 
157
        if (sig_state->sig_handlers[se->signum] == NULL) {
 
158
                /* restore old handler, if any */
 
159
                if (sig_state->oldact[se->signum]) {
 
160
                        sigaction(se->signum, sig_state->oldact[se->signum], NULL);
 
161
                        sig_state->oldact[se->signum] = NULL;
 
162
                }
 
163
#ifdef SA_SIGINFO
 
164
                if (se->sa_flags & SA_SIGINFO) {
 
165
                        if (sig_state->sig_info[se->signum]) {
 
166
                                talloc_free(sig_state->sig_info[se->signum]);
 
167
                                sig_state->sig_info[se->signum] = NULL;
 
168
                        }
 
169
                }
 
170
#endif
 
171
        }
 
172
 
 
173
        return 0;
 
174
}
 
175
 
 
176
/*
 
177
  this is part of the pipe hack needed to avoid the signal race condition
 
178
*/
 
179
static void signal_pipe_handler(struct tevent_context *ev, struct tevent_fd *fde, 
 
180
                                uint16_t flags, void *_private)
 
181
{
 
182
        char c[16];
 
183
        ssize_t res;
 
184
        /* its non-blocking, doesn't matter if we read too much */
 
185
        res = read(fde->fd, c, sizeof(c));
 
186
}
 
187
 
 
188
/*
 
189
  add a signal event
 
190
  return NULL on failure (memory allocation error)
 
191
*/
 
192
struct tevent_signal *tevent_common_add_signal(struct tevent_context *ev,
 
193
                                               TALLOC_CTX *mem_ctx,
 
194
                                               int signum,
 
195
                                               int sa_flags,
 
196
                                               tevent_signal_handler_t handler,
 
197
                                               void *private_data,
 
198
                                               const char *handler_name,
 
199
                                               const char *location)
 
200
{
 
201
        struct tevent_signal *se;
 
202
        struct tevent_common_signal_list *sl;
 
203
        sigset_t set, oldset;
 
204
 
 
205
        if (signum >= NUM_SIGNALS) {
 
206
                errno = EINVAL;
 
207
                return NULL;
 
208
        }
 
209
 
 
210
        /* the sig_state needs to be on a global context as it can last across
 
211
           multiple event contexts */
 
212
        if (sig_state == NULL) {
 
213
                sig_state = talloc_zero(talloc_autofree_context(), struct sig_state);
 
214
                if (sig_state == NULL) {
 
215
                        return NULL;
 
216
                }
 
217
        }
 
218
 
 
219
        se = talloc(mem_ctx?mem_ctx:ev, struct tevent_signal);
 
220
        if (se == NULL) return NULL;
 
221
 
 
222
        se->event_ctx           = ev;
 
223
        se->signum              = signum;
 
224
        se->sa_flags            = sa_flags;
 
225
        se->handler             = handler;
 
226
        se->private_data        = private_data;
 
227
        se->handler_name        = handler_name;
 
228
        se->location            = location;
 
229
        se->additional_data     = NULL;
 
230
 
 
231
        sl = talloc(se, struct tevent_common_signal_list);
 
232
        if (!sl) {
 
233
                talloc_free(se);
 
234
                return NULL;
 
235
        }
 
236
        sl->se = se;
 
237
        se->additional_data     = sl;
 
238
 
 
239
        /* Ensure, no matter the destruction order, that we always have a handle on the global sig_state */
 
240
        if (!talloc_reference(se, sig_state)) {
 
241
                talloc_free(se);
 
242
                return NULL;
 
243
        }
 
244
 
 
245
        /* we need to setup the pipe hack handler if not already
 
246
           setup */
 
247
        if (ev->pipe_fde == NULL) {
 
248
                if (pipe(ev->pipe_fds) == -1) {
 
249
                        talloc_free(se);
 
250
                        return NULL;
 
251
                }
 
252
                ev_set_blocking(ev->pipe_fds[0], false);
 
253
                ev_set_blocking(ev->pipe_fds[1], false);
 
254
                ev->pipe_fde = tevent_add_fd(ev, ev, ev->pipe_fds[0],
 
255
                                             TEVENT_FD_READ,
 
256
                                             signal_pipe_handler, NULL);
 
257
                if (!ev->pipe_fde) {
 
258
                        close(ev->pipe_fds[0]);
 
259
                        close(ev->pipe_fds[1]);
 
260
                        talloc_free(se);
 
261
                        return NULL;
 
262
                }
 
263
        }
 
264
 
 
265
        /* only install a signal handler if not already installed */
 
266
        if (sig_state->sig_handlers[signum] == NULL) {
 
267
                struct sigaction act;
 
268
                ZERO_STRUCT(act);
 
269
                act.sa_handler = tevent_common_signal_handler;
 
270
                act.sa_flags = sa_flags;
 
271
#ifdef SA_SIGINFO
 
272
                if (sa_flags & SA_SIGINFO) {
 
273
                        act.sa_handler   = NULL;
 
274
                        act.sa_sigaction = tevent_common_signal_handler_info;
 
275
                        if (sig_state->sig_info[signum] == NULL) {
 
276
                                sig_state->sig_info[signum] = talloc_zero_array(sig_state, siginfo_t, SA_INFO_QUEUE_COUNT);
 
277
                                if (sig_state->sig_info[signum] == NULL) {
 
278
                                        talloc_free(se);
 
279
                                        return NULL;
 
280
                                }
 
281
                        }
 
282
                }
 
283
#endif
 
284
                sig_state->oldact[signum] = talloc(sig_state, struct sigaction);
 
285
                if (sig_state->oldact[signum] == NULL) {
 
286
                        talloc_free(se);
 
287
                        return NULL;                    
 
288
                }
 
289
                if (sigaction(signum, &act, sig_state->oldact[signum]) == -1) {
 
290
                        talloc_free(se);
 
291
                        return NULL;
 
292
                }
 
293
        }
 
294
 
 
295
        DLIST_ADD(se->event_ctx->signal_events, se);
 
296
 
 
297
        /* Make sure the signal doesn't come in while we're mangling list. */
 
298
        sigemptyset(&set);
 
299
        sigaddset(&set, signum);
 
300
        sigprocmask(SIG_BLOCK, &set, &oldset);
 
301
        DLIST_ADD(sig_state->sig_handlers[signum], sl);
 
302
        sigprocmask(SIG_SETMASK, &oldset, NULL);
 
303
 
 
304
        talloc_set_destructor(se, tevent_signal_destructor);
 
305
        talloc_set_destructor(sl, tevent_common_signal_list_destructor);
 
306
 
 
307
        return se;
 
308
}
 
309
 
 
310
 
 
311
/*
 
312
  check if a signal is pending
 
313
  return != 0 if a signal was pending
 
314
*/
 
315
int tevent_common_check_signal(struct tevent_context *ev)
 
316
{
 
317
        int i;
 
318
 
 
319
        if (!sig_state || !SIG_PENDING(sig_state->got_signal)) {
 
320
                return 0;
 
321
        }
 
322
        
 
323
        for (i=0;i<NUM_SIGNALS+1;i++) {
 
324
                struct tevent_common_signal_list *sl, *next;
 
325
                struct sigcounter counter = sig_state->signal_count[i];
 
326
                uint32_t count = sig_count(counter);
 
327
#ifdef SA_SIGINFO
 
328
                /* Ensure we null out any stored siginfo_t entries
 
329
                 * after processing for debugging purposes. */
 
330
                bool clear_processed_siginfo = false;
 
331
#endif
 
332
 
 
333
                if (count == 0) {
 
334
                        continue;
 
335
                }
 
336
                for (sl=sig_state->sig_handlers[i];sl;sl=next) {
 
337
                        struct tevent_signal *se = sl->se;
 
338
                        next = sl->next;
 
339
#ifdef SA_SIGINFO
 
340
                        if (se->sa_flags & SA_SIGINFO) {
 
341
                                uint32_t j;
 
342
 
 
343
                                clear_processed_siginfo = true;
 
344
 
 
345
                                for (j=0;j<count;j++) {
 
346
                                        /* sig_state->signal_count[i].seen
 
347
                                         * % SA_INFO_QUEUE_COUNT is
 
348
                                         * the base position of the unprocessed
 
349
                                         * signals in the ringbuffer. */
 
350
                                        uint32_t ofs = (counter.seen + j)
 
351
                                                % SA_INFO_QUEUE_COUNT;
 
352
                                        se->handler(ev, se, i, 1,
 
353
                                                    (void*)&sig_state->sig_info[i][ofs], 
 
354
                                                    se->private_data);
 
355
                                }
 
356
                                if (se->sa_flags & SA_RESETHAND) {
 
357
                                        talloc_free(se);
 
358
                                }
 
359
                                continue;
 
360
                        }
 
361
#endif
 
362
                        se->handler(ev, se, i, count, NULL, se->private_data);
 
363
                        if (se->sa_flags & SA_RESETHAND) {
 
364
                                talloc_free(se);
 
365
                        }
 
366
                }
 
367
 
 
368
#ifdef SA_SIGINFO
 
369
                if (clear_processed_siginfo) {
 
370
                        uint32_t j;
 
371
                        for (j=0;j<count;j++) {
 
372
                                uint32_t ofs = (counter.seen + j)
 
373
                                        % SA_INFO_QUEUE_COUNT;
 
374
                                memset((void*)&sig_state->sig_info[i][ofs],
 
375
                                        '\0',
 
376
                                        sizeof(siginfo_t));
 
377
                        }
 
378
                }
 
379
#endif
 
380
 
 
381
                SIG_SEEN(sig_state->signal_count[i], count);
 
382
                SIG_SEEN(sig_state->got_signal, count);
 
383
 
 
384
#ifdef SA_SIGINFO
 
385
                if (SIG_PENDING(sig_state->sig_blocked[i])) {
 
386
                        /* We'd filled the queue, unblock the
 
387
                           signal now the queue is empty again.
 
388
                           Note we MUST do this after the
 
389
                           SIG_SEEN(sig_state->signal_count[i], count)
 
390
                           call to prevent a new signal running
 
391
                           out of room in the sig_state->sig_info[i][]
 
392
                           ring buffer. */
 
393
                        sigset_t set;
 
394
                        sigemptyset(&set);
 
395
                        sigaddset(&set, i);
 
396
                        SIG_SEEN(sig_state->sig_blocked[i],
 
397
                                 sig_count(sig_state->sig_blocked[i]));
 
398
                        sigprocmask(SIG_UNBLOCK, &set, NULL);
 
399
                }
 
400
#endif
 
401
        }
 
402
 
 
403
        return 1;
 
404
}
 
405
 
 
406
void tevent_cleanup_pending_signal_handlers(struct tevent_signal *se)
 
407
{
 
408
        struct tevent_common_signal_list *sl;
 
409
        sl = talloc_get_type(se->additional_data,
 
410
                             struct tevent_common_signal_list);
 
411
 
 
412
        tevent_common_signal_list_destructor(sl);
 
413
 
 
414
        if (sig_state->sig_handlers[se->signum] == NULL) {
 
415
                if (sig_state->oldact[se->signum]) {
 
416
                        sigaction(se->signum, sig_state->oldact[se->signum], NULL);
 
417
                        sig_state->oldact[se->signum] = NULL;
 
418
                }
 
419
        }
 
420
        return;
 
421
}