From cf8eef4ad88af40d2cf147686c1877cd380b452c Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sun, 21 Jan 2007 10:32:39 +0000 Subject: r20930: use sigaction() instead of signal() add support for sa_flags argument to event_add_signal(). These are passed to sigaction(). Special handling is provided for SA_RESETHAND (which tells the event system to remove the handler after the signal) and SA_SIGINFO which allows the siginfo structure to be received per signal (This used to be commit 1bb10b6cf7d717ad21834e73a4ca4b22b5fb6f0a) --- source4/lib/events/events_signal.c | 84 ++++++++++++++++++++++++++++++++++---- 1 file changed, 77 insertions(+), 7 deletions(-) (limited to 'source4/lib/events/events_signal.c') diff --git a/source4/lib/events/events_signal.c b/source4/lib/events/events_signal.c index 85b42ae4ab..e1a50e058f 100644 --- a/source4/lib/events/events_signal.c +++ b/source4/lib/events/events_signal.c @@ -29,14 +29,22 @@ #define NUM_SIGNALS 64 +/* maximum number of SA_SIGINFO signals to hold in the queue */ +#define SA_INFO_QUEUE_COUNT 10 + /* the poor design of signals means that this table must be static global */ static struct { struct signal_event *sig_handlers[NUM_SIGNALS]; + struct sigaction oldact[NUM_SIGNALS]; uint32_t signal_count[NUM_SIGNALS]; uint32_t got_signal; int pipe_hack[2]; +#ifdef SA_SIGINFO + /* with SA_SIGINFO we get quite a lot of info per signal */ + siginfo_t sig_info[NUM_SIGNALS][SA_INFO_QUEUE_COUNT]; +#endif } sig_state; @@ -52,6 +60,27 @@ static void signal_handler(int signum) write(sig_state.pipe_hack[1], &c, 1); } +#ifdef SA_SIGINFO +/* + signal handler with SA_SIGINFO - redirects to registered signals +*/ +static void signal_handler_info(int signum, siginfo_t *info, void *uctx) +{ + sig_state.sig_info[signum][sig_state.signal_count[signum]] = *info; + + signal_handler(signum); + + /* handle SA_SIGINFO */ + if (sig_state.signal_count[signum] == SA_INFO_QUEUE_COUNT) { + /* we've filled the info array - block this signal until + these ones are delivered */ + sigset_t set; + sigemptyset(&set); + sigaddset(&set, signum); + sigprocmask(SIG_BLOCK, &set, NULL); + } +} +#endif /* destroy a signal event @@ -61,7 +90,8 @@ static int signal_event_destructor(struct signal_event *se) se->event_ctx->num_signal_handlers--; DLIST_REMOVE(sig_state.sig_handlers[se->signum], se); if (sig_state.sig_handlers[se->signum] == NULL) { - signal(se->signum, SIG_DFL); + /* restore old handler, if any */ + sigaction(se->signum, &sig_state.oldact[se->signum], NULL); } return 0; } @@ -82,10 +112,11 @@ static void signal_pipe_handler(struct event_context *ev, struct fd_event *fde, return NULL on failure (memory allocation error) */ struct signal_event *common_event_add_signal(struct event_context *ev, - TALLOC_CTX *mem_ctx, - int signum, - event_signal_handler_t handler, - void *private_data) + TALLOC_CTX *mem_ctx, + int signum, + int sa_flags, + event_signal_handler_t handler, + void *private_data) { struct signal_event *se; @@ -100,15 +131,32 @@ struct signal_event *common_event_add_signal(struct event_context *ev, se->handler = handler; se->private_data = private_data; se->signum = signum; + se->sa_flags = sa_flags; + /* only install a signal handler if not already installed */ if (sig_state.sig_handlers[signum] == NULL) { - signal(signum, signal_handler); + struct sigaction act; + ZERO_STRUCT(act); + act.sa_handler = signal_handler; + act.sa_flags = sa_flags; +#ifdef SA_SIGINFO + if (sa_flags & SA_SIGINFO) { + act.sa_handler = NULL; + act.sa_sigaction = signal_handler_info; + } +#endif + if (sigaction(signum, &act, &sig_state.oldact[signum]) == -1) { + talloc_free(se); + return NULL; + } } DLIST_ADD(sig_state.sig_handlers[signum], se); talloc_set_destructor(se, signal_event_destructor); + /* we need to setup the pipe hack handler if not already + setup */ if (ev->pipe_fde == NULL) { if (sig_state.pipe_hack[0] == 0 && sig_state.pipe_hack[1] == 0) { @@ -142,7 +190,29 @@ int common_event_check_signal(struct event_context *ev) struct signal_event *se, *next; for (se=sig_state.sig_handlers[i];se;se=next) { next = se->next; - se->handler(ev, se, i, count, se->private_data); +#ifdef SA_SIGINFO + if (se->sa_flags & SA_SIGINFO) { + int j; + for (j=0;jhandler(ev, se, i, 1, + (void*)&sig_state.sig_info[i][j], + se->private_data); + } + if (count == SA_INFO_QUEUE_COUNT) { + /* we'd filled the queue, unblock the + signal now */ + sigset_t set; + sigemptyset(&set); + sigaddset(&set, i); + sigprocmask(SIG_UNBLOCK, &set, NULL); + } + continue; + } +#endif + se->handler(ev, se, i, count, NULL, se->private_data); + if (se->sa_flags & SA_RESETHAND) { + talloc_free(se); + } } sig_state.signal_count[i] -= count; sig_state.got_signal -= count; -- cgit