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.c | 6 +- source4/lib/events/events.h | 4 +- source4/lib/events/events_internal.h | 4 +- source4/lib/events/events_signal.c | 84 ++++++++++++++++++++++--- source4/lib/replace/system/wait.h | 4 ++ source4/torture/local/event.c | 119 +++++++++++++++++++---------------- 6 files changed, 155 insertions(+), 66 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;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; 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 #endif +#ifndef SA_RESETHAND +#define SA_RESETHAND SA_ONESHOT +#endif + #endif diff --git a/source4/torture/local/event.c b/source4/torture/local/event.c index 5dab65b693..9d15f517eb 100644 --- a/source4/torture/local/event.c +++ b/source4/torture/local/event.c @@ -25,63 +25,50 @@ #include "system/filesys.h" #include "torture/torture.h" -static int write_fd, read_fd; -static struct fd_event *fde; -static int te_count; static int fde_count; -static struct torture_context *test; static void fde_handler(struct event_context *ev_ctx, struct fd_event *f, uint16_t flags, void *private) { int *fd = private; - - torture_comment(test, "event[%d] fd[%d] events[0x%08X]%s%s\n", - fde_count, *fd, flags, - (flags & EVENT_FD_READ)?" EVENT_FD_READ":"", - (flags & EVENT_FD_WRITE)?" EVENT_FD_WRITE":""); - - if (fde_count > 5) { - torture_result(test, TORTURE_FAIL, - __location__": got more than fde 5 events - bug!"); - talloc_free(fde); - fde = NULL; - return; - } - - event_set_fd_flags(fde, 0); + char c; +#ifdef SA_SIGINFO + kill(getpid(), SIGUSR1); +#endif + kill(getpid(), SIGALRM); + read(fd[0], &c, 1); + write(fd[1], &c, 1); fde_count++; } -static void timed_handler(struct event_context *ev_ctx, struct timed_event *te, - struct timeval tval, void *private) +static void finished_handler(struct event_context *ev_ctx, struct timed_event *te, + struct timeval tval, void *private) { - torture_comment(test, "timed_handler called[%d]\n", te_count); - if (te_count > 2) { - close(write_fd); - write_fd = -1; - } - if (te_count > 5) { - torture_comment(test, "remove fd event!\n"); - talloc_free(fde); - fde = NULL; - return; - } - te_count++; - event_add_timed(ev_ctx, ev_ctx, timeval_current_ofs(0,500), timed_handler, private); + int *finished = private; + (*finished) = 1; } -static bool test_event_context(struct torture_context *torture_ctx, - const void *test_data) +static void count_handler(struct event_context *ev_ctx, struct signal_event *te, + int signum, int count, void *info, void *private) +{ + int *countp = private; + (*countp) += count; +} + +static bool test_event_context(struct torture_context *test, + const void *test_data) { struct event_context *ev_ctx; int fd[2] = { -1, -1 }; const char *backend = (const char *)test_data; - TALLOC_CTX *mem_ctx = torture_ctx; - - test = torture_ctx; - - ev_ctx = event_context_init_byname(mem_ctx, backend); + int alarm_count=0, info_count=0; + struct fd_event *fde; + struct signal_event *se1, *se2, *se3; + int finished=0; + struct timeval t; + char c = 0; + + ev_ctx = event_context_init_byname(test, backend); if (ev_ctx == NULL) { torture_comment(test, "event backend '%s' not supported\n", backend); return true; @@ -90,29 +77,51 @@ static bool test_event_context(struct torture_context *torture_ctx, torture_comment(test, "Testing event backend '%s'\n", backend); /* reset globals */ - write_fd = -1; - read_fd = -1; - fde = NULL; - te_count = 0; fde_count = 0; /* create a pipe */ pipe(fd); - read_fd = fd[0]; - write_fd = fd[1]; - fde = event_add_fd(ev_ctx, ev_ctx, read_fd, EVENT_FD_READ, - fde_handler, &read_fd); + fde = event_add_fd(ev_ctx, ev_ctx, fd[0], EVENT_FD_READ, + fde_handler, fd); + + event_add_timed(ev_ctx, ev_ctx, timeval_current_ofs(2,0), + finished_handler, &finished); - event_add_timed(ev_ctx, ev_ctx, timeval_current_ofs(0,500), - timed_handler, fde); + se1 = event_add_signal(ev_ctx, ev_ctx, SIGALRM, SA_RESTART, count_handler, &alarm_count); + se2 = event_add_signal(ev_ctx, ev_ctx, SIGALRM, SA_RESETHAND, count_handler, &alarm_count); +#ifdef SA_SIGINFO + se3 = event_add_signal(ev_ctx, ev_ctx, SIGUSR1, SA_SIGINFO, count_handler, &info_count); +#endif - event_loop_wait(ev_ctx); + write(fd[1], &c, 1); + + t = timeval_current(); + while (!finished) { + event_loop_once(ev_ctx); + } + + talloc_free(fde); + close(fd[0]); + close(fd[1]); + + while (alarm_count < fde_count+1) { + event_loop_once(ev_ctx); + } + + torture_comment(test, "Got %.2f pipe events/sec\n", fde_count/timeval_elapsed(&t)); + + talloc_free(se1); + + torture_assert_int_equal(test, alarm_count, 1+fde_count, "alarm count mismatch"); + +#ifdef SA_SIGINFO + talloc_free(se3); + torture_assert_int_equal(test, info_count, fde_count, "info count mismatch"); +#endif - close(read_fd); - close(write_fd); - talloc_free(ev_ctx); + return true; } -- cgit