From be4ac227842530d484659f2db683453366326d8b Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 28 Aug 2009 12:08:47 +0930 Subject: lib/tevent: handle tevent_common_add_signal on different event contexts. I don't know if this is a problem in real life. The code assumes there's only one tevent_context; all signals will notify the first event context. That's counter-intuitive if you ever use more than one, and there's nothing else in this code which prevents it AFAICT. Signed-off-by: Rusty Russell --- lib/tevent/tevent_internal.h | 1 + lib/tevent/tevent_signal.c | 44 ++++++++++++++++++++++++++++++-------------- 2 files changed, 31 insertions(+), 14 deletions(-) (limited to 'lib') diff --git a/lib/tevent/tevent_internal.h b/lib/tevent/tevent_internal.h index 513ca1c732..4e3b7b5718 100644 --- a/lib/tevent/tevent_internal.h +++ b/lib/tevent/tevent_internal.h @@ -240,6 +240,7 @@ struct tevent_context { /* pipe hack used with signal handlers */ struct tevent_fd *pipe_fde; + int pipe_fds[2]; /* debugging operations */ struct tevent_debug_ops debug_ops; diff --git a/lib/tevent/tevent_signal.c b/lib/tevent/tevent_signal.c index 5e4e81b73c..0333325ef0 100644 --- a/lib/tevent/tevent_signal.c +++ b/lib/tevent/tevent_signal.c @@ -57,7 +57,6 @@ static struct sig_state { struct sigaction *oldact[NUM_SIGNALS+1]; struct sigcounter signal_count[NUM_SIGNALS+1]; struct sigcounter 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+1]; @@ -80,10 +79,20 @@ static void tevent_common_signal_handler(int signum) { char c = 0; ssize_t res; + struct tevent_common_signal_list *sl; + struct tevent_context *ev = NULL; + SIG_INCREMENT(sig_state->signal_count[signum]); SIG_INCREMENT(sig_state->got_signal); - /* doesn't matter if this pipe overflows */ - res = write(sig_state->pipe_hack[1], &c, 1); + + /* Write to each unique event context. */ + for (sl = sig_state->sig_handlers[signum]; sl; sl = sl->next) { + if (sl->se->event_ctx != ev) { + /* doesn't matter if this pipe overflows */ + res = write(ev->pipe_fds[1], &c, 1); + ev = sl->se->event_ctx; + } + } } #ifdef SA_SIGINFO @@ -160,7 +169,7 @@ static void signal_pipe_handler(struct tevent_context *ev, struct tevent_fd *fde char c[16]; ssize_t res; /* its non-blocking, doesn't matter if we read too much */ - res = read(sig_state->pipe_hack[0], c, sizeof(c)); + res = read(fde->fd, c, sizeof(c)); } /* @@ -178,6 +187,7 @@ struct tevent_signal *tevent_common_add_signal(struct tevent_context *ev, { struct tevent_signal *se; struct tevent_common_signal_list *sl; + sigset_t set, oldset; if (signum >= NUM_SIGNALS) { errno = EINVAL; @@ -222,18 +232,18 @@ struct tevent_signal *tevent_common_add_signal(struct tevent_context *ev, /* 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) { - if (pipe(sig_state->pipe_hack) == -1) { - talloc_free(se); - return NULL; - } - ev_set_blocking(sig_state->pipe_hack[0], false); - ev_set_blocking(sig_state->pipe_hack[1], false); + if (pipe(ev->pipe_fds) == -1) { + talloc_free(se); + return NULL; } - ev->pipe_fde = tevent_add_fd(ev, ev, sig_state->pipe_hack[0], - TEVENT_FD_READ, signal_pipe_handler, NULL); + ev_set_blocking(ev->pipe_fds[0], false); + ev_set_blocking(ev->pipe_fds[1], false); + ev->pipe_fde = tevent_add_fd(ev, ev, ev->pipe_fds[0], + TEVENT_FD_READ, + signal_pipe_handler, NULL); if (!ev->pipe_fde) { + close(ev->pipe_fds[0]); + close(ev->pipe_fds[1]); talloc_free(se); return NULL; } @@ -270,7 +280,13 @@ struct tevent_signal *tevent_common_add_signal(struct tevent_context *ev, } DLIST_ADD(se->event_ctx->signal_events, se); + + /* Make sure the signal doesn't come in while we're mangling list. */ + sigemptyset(&set); + sigaddset(&set, signum); + sigprocmask(SIG_BLOCK, &set, &oldset); DLIST_ADD(sig_state->sig_handlers[signum], sl); + sigprocmask(SIG_SETMASK, &oldset, NULL); talloc_set_destructor(se, tevent_signal_destructor); talloc_set_destructor(sl, tevent_common_signal_list_destructor); -- cgit