diff options
Diffstat (limited to 'source4/lib')
-rw-r--r-- | source4/lib/events/events.c | 6 | ||||
-rw-r--r-- | source4/lib/events/events.h | 4 | ||||
-rw-r--r-- | source4/lib/events/events_internal.h | 4 | ||||
-rw-r--r-- | source4/lib/events/events_signal.c | 84 | ||||
-rw-r--r-- | source4/lib/replace/system/wait.h | 4 |
5 files changed, 91 insertions, 11 deletions
diff --git a/source4/lib/events/events.c b/source4/lib/events/events.c index 2a6da1370f..e2d5b4c397 100644 --- a/source4/lib/events/events.c +++ b/source4/lib/events/events.c @@ -241,14 +241,18 @@ struct timed_event *event_add_timed(struct event_context *ev, TALLOC_CTX *mem_ct /* add a signal event + + sa_flags are flags to sigaction(2) + return NULL on failure */ struct signal_event *event_add_signal(struct event_context *ev, TALLOC_CTX *mem_ctx, int signum, + int sa_flags, event_signal_handler_t handler, void *private_data) { - return ev->ops->add_signal(ev, mem_ctx, signum, handler, private_data); + return ev->ops->add_signal(ev, mem_ctx, signum, sa_flags, handler, private_data); } /* diff --git a/source4/lib/events/events.h b/source4/lib/events/events.h index eee7a5e470..4177087fb7 100644 --- a/source4/lib/events/events.h +++ b/source4/lib/events/events.h @@ -36,7 +36,7 @@ typedef void (*event_fd_handler_t)(struct event_context *, struct fd_event *, typedef void (*event_timed_handler_t)(struct event_context *, struct timed_event *, struct timeval , void *); typedef void (*event_signal_handler_t)(struct event_context *, struct signal_event *, - int , int, void *); + int , int, void *, void *); typedef void (*event_aio_handler_t)(struct event_context *, struct aio_event *, int, void *); @@ -54,7 +54,7 @@ struct timed_event *event_add_timed(struct event_context *ev, TALLOC_CTX *mem_ct void *private); struct signal_event *event_add_signal(struct event_context *ev, TALLOC_CTX *mem_ctx, - int signum, + int signum, int sa_flags, event_signal_handler_t handler, void *private); diff --git a/source4/lib/events/events_internal.h b/source4/lib/events/events_internal.h index 0b8de12a35..39fade2fdb 100644 --- a/source4/lib/events/events_internal.h +++ b/source4/lib/events/events_internal.h @@ -50,7 +50,7 @@ struct event_ops { /* signal functions */ struct signal_event *(*add_signal)(struct event_context *ev, TALLOC_CTX *mem_ctx, - int signum, + int signum, int sa_flags, event_signal_handler_t handler, void *private_data); @@ -89,6 +89,7 @@ struct signal_event { event_signal_handler_t handler; void *private_data; int signum; + int sa_flags; }; /* aio event is private to the aio backend */ @@ -122,6 +123,7 @@ struct timeval common_event_loop_delay(struct event_context *); struct signal_event *common_event_add_signal(struct event_context *ev, TALLOC_CTX *mem_ctx, int signum, + int sa_flags, event_signal_handler_t handler, void *private_data); int common_event_check_signal(struct event_context *ev); 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;j<count;j++) { + se->handler(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; diff --git a/source4/lib/replace/system/wait.h b/source4/lib/replace/system/wait.h index 3855f7ae72..179ef0774e 100644 --- a/source4/lib/replace/system/wait.h +++ b/source4/lib/replace/system/wait.h @@ -40,4 +40,8 @@ #include <setjmp.h> #endif +#ifndef SA_RESETHAND +#define SA_RESETHAND SA_ONESHOT +#endif + #endif |