From 41b7cbc38105a540ade7d02bb6137898a94abc89 Mon Sep 17 00:00:00 2001 From: Niels Provos Date: Sat, 10 Mar 2007 06:37:53 +0000 Subject: more the signal base into the event base; this removes global state and makes signals work better with threading; from Wouter Wijngaards small fixes for kqueue and style by me svn:r351 --- WIN32-Code/win32.c | 8 ++--- devpoll.c | 20 +++++------ epoll.c | 22 ++++++------ event-internal.h | 5 +++ event.3 | 3 ++ event.c | 67 ++++++++++++++++++++++--------------- event.h | 5 +-- evport.c | 14 ++++---- evsignal.h | 13 ++++++-- kqueue.c | 8 ++--- poll.c | 20 +++++------ rtsig.c | 4 +-- select.c | 22 ++++++------ signal.c | 85 +++++++++++++++++++++++++++------------------- test/regress.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 15 files changed, 270 insertions(+), 124 deletions(-) diff --git a/WIN32-Code/win32.c b/WIN32-Code/win32.c index 867d1f22..c051c943 100644 --- a/WIN32-Code/win32.c +++ b/WIN32-Code/win32.c @@ -81,12 +81,12 @@ struct win32op { struct event **events; }; -void *win32_init (void); +void *win32_init (struct event_base *); int win32_insert (void *, struct event *); int win32_del (void *, struct event *); int win32_recalc (struct event_base *base, void *, int); int win32_dispatch (struct event_base *base, void *, struct timeval *); -void win32_dealloc (void *); +void win32_dealloc (struct event_base *, void *); struct eventop win32ops = { "win32", @@ -167,7 +167,7 @@ do_fd_clear(struct win32op *op, SOCKET s, int read) #define NEVENT 64 void * -win32_init(void) +win32_init(struct event_base *) { struct win32op *winop; size_t size; @@ -376,7 +376,7 @@ win32_dispatch(struct event_base *base, void *op, } void -win32_dealloc(void *arg) +win32_dealloc(struct event_base *, void *arg) { struct win32op *win32op = arg; diff --git a/devpoll.c b/devpoll.c index db897a9d..63e1dc90 100644 --- a/devpoll.c +++ b/devpoll.c @@ -50,8 +50,6 @@ #include "evsignal.h" #include "log.h" -extern volatile sig_atomic_t evsignal_caught; - /* due to limitations in the devpoll interface, we need to keep track of * all file descriptors outself. */ @@ -70,12 +68,12 @@ struct devpollop { int nchanges; }; -void *devpoll_init (void); +void *devpoll_init (struct event_base *); int devpoll_add (void *, struct event *); int devpoll_del (void *, struct event *); int devpoll_recalc (struct event_base *, void *, int); int devpoll_dispatch (struct event_base *, void *, struct timeval *); -void devpoll_dealloc (void *); +void devpoll_dealloc (struct event_base *, void *); struct eventop devpollops = { "devpoll", @@ -126,7 +124,7 @@ devpoll_queue(struct devpollop *devpollop, int fd, int events) { } void * -devpoll_init(void) +devpoll_init(struct event_base *base) { int dpfd, nfiles = NEVENT; struct rlimit rl; @@ -179,7 +177,7 @@ devpoll_init(void) return (NULL); } - evsignal_init(); + evsignal_init(base); return (devpollop); } @@ -237,10 +235,11 @@ devpoll_dispatch(struct event_base *base, void *arg, struct timeval *tv) return (-1); } - evsignal_process(); + evsignal_process(base); return (0); - } else if (evsignal_caught) - evsignal_process(); + } else if (base->sig.evsignal_caught) { + evsignal_process(base); + } event_debug(("%s: devpoll_wait reports %d", __func__, res)); @@ -398,10 +397,11 @@ devpoll_del(void *arg, struct event *ev) } void -devpoll_dealloc(void *arg) +devpoll_dealloc(struct event_base *base, void *arg) { struct devpollop *devpollop = arg; + evsignal_dealloc(base); if (devpollop->fds) free(devpollop->fds); if (devpollop->events) diff --git a/epoll.c b/epoll.c index e089e23d..235977de 100644 --- a/epoll.c +++ b/epoll.c @@ -30,6 +30,7 @@ #include #include +#include #include #ifdef HAVE_SYS_TIME_H #include @@ -49,11 +50,10 @@ #endif #include "event.h" +#include "event-internal.h" #include "evsignal.h" #include "log.h" -extern volatile sig_atomic_t evsignal_caught; - /* due to limitations in the epoll interface, we need to keep track of * all file descriptors outself. */ @@ -70,12 +70,12 @@ struct epollop { int epfd; }; -void *epoll_init (void); +void *epoll_init (struct event_base *); int epoll_add (void *, struct event *); int epoll_del (void *, struct event *); int epoll_recalc (struct event_base *, void *, int); int epoll_dispatch (struct event_base *, void *, struct timeval *); -void epoll_dealloc (void *); +void epoll_dealloc (struct event_base *, void *); struct eventop epollops = { "epoll", @@ -99,7 +99,7 @@ struct eventop epollops = { #define NEVENT 32000 void * -epoll_init(void) +epoll_init(struct event_base *base) { int epfd, nfiles = NEVENT; struct rlimit rl; @@ -149,7 +149,7 @@ epoll_init(void) } epollop->nfds = nfiles; - evsignal_init(); + evsignal_init(base); return (epollop); } @@ -198,10 +198,11 @@ epoll_dispatch(struct event_base *base, void *arg, struct timeval *tv) return (-1); } - evsignal_process(); + evsignal_process(base); return (0); - } else if (evsignal_caught) - evsignal_process(); + } else if (base->sig.evsignal_caught) { + evsignal_process(base); + } event_debug(("%s: epoll_wait reports %d", __func__, res)); @@ -346,10 +347,11 @@ epoll_del(void *arg, struct event *ev) } void -epoll_dealloc(void *arg) +epoll_dealloc(struct event_base *base, void *arg) { struct epollop *epollop = arg; + evsignal_dealloc(base); if (epollop->fds) free(epollop->fds); if (epollop->events) diff --git a/event-internal.h b/event-internal.h index becb6691..7fd4b6c6 100644 --- a/event-internal.h +++ b/event-internal.h @@ -31,6 +31,8 @@ extern "C" { #endif +#include "evsignal.h" + struct event_base { const struct eventop *evsel; void *evbase; @@ -43,6 +45,9 @@ struct event_base { struct event_list **activequeues; int nactivequeues; + /* signal handling info */ + struct evsignal_info sig; + struct event_list eventqueue; struct timeval event_tv; diff --git a/event.3 b/event.3 index 132c30f0..fc71b7df 100644 --- a/event.3 +++ b/event.3 @@ -42,6 +42,7 @@ .Nm event_add , .Nm event_del , .Nm event_once , +.Nm event_base_once , .Nm event_pending , .Nm event_initialized , .Nm event_priority_init , @@ -107,6 +108,8 @@ .Ft int .Fn "event_once" "int fd" "short event" "void (*fn)(int, short, void *)" "void *arg" "struct timeval *tv" .Ft int +.Fn "event_base_once" "struct event_base *base" "int fd" "short event" "void (*fn)(int, short, void *)" "void *arg" "struct timeval *tv" +.Ft int .Fn "event_pending" "struct event *ev" "short event" "struct timeval *tv" .Ft int .Fn "event_initialized" "struct event *ev" diff --git a/event.c b/event.c index f6d2b1cc..2048157d 100644 --- a/event.c +++ b/event.c @@ -111,9 +111,8 @@ const struct eventop *eventops[] = { }; /* Global state */ -struct event_list signalqueue; - struct event_base *current_base = NULL; +extern struct event_base *evsignal_base; /* Handle signals - This is a deprecated interface */ int (*event_sigcb)(void); /* Signal callback when gotsig is set */ @@ -174,36 +173,40 @@ void * event_init(void) { int i; + struct event_base *base; - if ((current_base = calloc(1, sizeof(struct event_base))) == NULL) + if ((base = calloc(1, sizeof(struct event_base))) == NULL) event_err(1, "%s: calloc"); event_sigcb = NULL; event_gotsig = 0; - gettime(¤t_base->event_tv); + gettime(&base->event_tv); - RB_INIT(¤t_base->timetree); - TAILQ_INIT(¤t_base->eventqueue); - TAILQ_INIT(&signalqueue); + RB_INIT(&base->timetree); + TAILQ_INIT(&base->eventqueue); + TAILQ_INIT(&base->sig.signalqueue); + base->sig.ev_signal_pair[0] = -1; + base->sig.ev_signal_pair[1] = -1; - current_base->evbase = NULL; - for (i = 0; eventops[i] && !current_base->evbase; i++) { - current_base->evsel = eventops[i]; + base->evbase = NULL; + for (i = 0; eventops[i] && !base->evbase; i++) { + base->evsel = eventops[i]; - current_base->evbase = current_base->evsel->init(); + base->evbase = base->evsel->init(base); } - if (current_base->evbase == NULL) + if (base->evbase == NULL) event_errx(1, "%s: no event mechanism available", __func__); if (getenv("EVENT_SHOW_METHOD")) event_msgx("libevent using: %s\n", - current_base->evsel->name); + base->evsel->name); /* allocate a single active event queue */ - event_base_priority_init(current_base, 1); + event_base_priority_init(base, 1); - return (current_base); + current_base = base; + return (base); } void @@ -217,7 +220,8 @@ event_base_free(struct event_base *base) current_base = NULL; assert(base); - assert(TAILQ_EMPTY(&base->eventqueue)); + if (base->evsel->dealloc != NULL) + base->evsel->dealloc(base, base->evbase); for (i=0; i < base->nactivequeues; ++i) assert(TAILQ_EMPTY(base->activequeues[i])); @@ -227,8 +231,7 @@ event_base_free(struct event_base *base) free(base->activequeues[i]); free(base->activequeues); - if (base->evsel->dealloc != NULL) - base->evsel->dealloc(base->evbase); + assert(TAILQ_EMPTY(&base->eventqueue)); free(base); } @@ -343,7 +346,6 @@ event_loopexit_cb(int fd, short what, void *arg) } /* not thread safe */ - int event_loopexit(struct timeval *tv) { @@ -354,7 +356,7 @@ event_loopexit(struct timeval *tv) int event_base_loopexit(struct event_base *event_base, struct timeval *tv) { - return (event_once(-1, EV_TIMEOUT, event_loopexit_cb, + return (event_base_once(event_base, -1, EV_TIMEOUT, event_loopexit_cb, event_base, tv)); } @@ -374,6 +376,8 @@ event_base_loop(struct event_base *base, int flags) struct timeval tv; int res, done; + if(!TAILQ_EMPTY(&base->sig.signalqueue)) + evsignal_base = base; done = 0; while (!done) { /* Calculate the initial events that we are waiting for */ @@ -422,6 +426,7 @@ event_base_loop(struct event_base *base, int flags) res = evsel->dispatch(base, evbase, &tv); + if (res == -1) return (-1); @@ -459,11 +464,18 @@ event_once_cb(int fd, short events, void *arg) free(eonce); } -/* Schedules an event once */ - +/* not threadsafe, event scheduled once. */ int event_once(int fd, short events, void (*callback)(int, short, void *), void *arg, struct timeval *tv) +{ + return event_base_once(current_base, fd, events, callback, arg, tv); +} + +/* Schedules an event once */ +int +event_base_once(struct event_base *base, int fd, short events, + void (*callback)(int, short, void *), void *arg, struct timeval *tv) { struct event_once *eonce; struct timeval etv; @@ -496,7 +508,9 @@ event_once(int fd, short events, return (-1); } - res = event_add(&eonce->ev, tv); + res = event_base_set(base, &eonce->ev); + if (res == 0) + res = event_add(&eonce->ev, tv); if (res != 0) { free(eonce); return (res); @@ -521,7 +535,8 @@ event_set(struct event *ev, int fd, short events, ev->ev_pncalls = NULL; /* by default, we put new events into the middle priority */ - ev->ev_pri = current_base->nactivequeues/2; + if(current_base) + ev->ev_pri = current_base->nactivequeues/2; } int @@ -801,7 +816,7 @@ event_queue_remove(struct event_base *base, struct event *ev, int queue) ev, ev_active_next); break; case EVLIST_SIGNAL: - TAILQ_REMOVE(&signalqueue, ev, ev_signal_next); + TAILQ_REMOVE(&base->sig.signalqueue, ev, ev_signal_next); break; case EVLIST_TIMEOUT: RB_REMOVE(event_tree, &base->timetree, ev); @@ -843,7 +858,7 @@ event_queue_insert(struct event_base *base, struct event *ev, int queue) ev,ev_active_next); break; case EVLIST_SIGNAL: - TAILQ_INSERT_TAIL(&signalqueue, ev, ev_signal_next); + TAILQ_INSERT_TAIL(&base->sig.signalqueue, ev, ev_signal_next); break; case EVLIST_TIMEOUT: { struct event *tmp = RB_INSERT(event_tree, &base->timetree, ev); diff --git a/event.h b/event.h index 3f2032dd..8687f194 100644 --- a/event.h +++ b/event.h @@ -131,12 +131,12 @@ TAILQ_HEAD (evkeyvalq, evkeyval); struct eventop { char *name; - void *(*init)(void); + void *(*init)(struct event_base *); int (*add)(void *, struct event *); int (*del)(void *, struct event *); int (*recalc)(struct event_base *, void *, int); int (*dispatch)(struct event_base *, void *, struct timeval *); - void (*dealloc)(void *); + void (*dealloc)(struct event_base *, void *); }; #define TIMEOUT_DEFAULT {5, 0} @@ -184,6 +184,7 @@ int event_base_loopexit(struct event_base *, struct timeval *); void event_set(struct event *, int, short, void (*)(int, short, void *), void *); int event_once(int, short, void (*)(int, short, void *), void *, struct timeval *); +int event_base_once(struct event_base *, int, short, void (*)(int, short, void *), void *, struct timeval *); int event_add(struct event *, struct timeval *); int event_del(struct event *); diff --git a/evport.c b/evport.c index 89bbd1ed..677ae832 100644 --- a/evport.c +++ b/evport.c @@ -81,8 +81,6 @@ #include "log.h" #include "evsignal.h" -extern volatile sig_atomic_t evsignal_caught; - /* * Default value for ed_nevents, which is the maximum file descriptor number we @@ -123,7 +121,7 @@ struct evport_data { struct fd_info *ed_pending[EVENTS_PER_GETN]; }; -static void* evport_init (void); +static void* evport_init (struct event_base *); static int evport_add (void *, struct event *); static int evport_del (void *, struct event *); static int evport_recalc (struct event_base *, void *, int); @@ -143,7 +141,7 @@ const struct eventop evportops = { */ static void* -evport_init(void) +evport_init(struct event_base *base) { struct evport_data *evpd; /* @@ -172,7 +170,7 @@ evport_init(void) evpd->ed_nevents = DEFAULT_NFDS; memset(&evpd->ed_pending, 0, EVENTS_PER_GETN * sizeof(struct fd_info*)); - evsignal_init(); + evsignal_init(base); return (evpd); } @@ -332,7 +330,7 @@ evport_dispatch(struct event_base *base, void *arg, struct timeval *tv) if ((res = port_getn(epdp->ed_port, pevtlist, EVENTS_PER_GETN, &nevents, &ts)) == -1) { if (errno == EINTR) { - evsignal_process(); + evsignal_process(base); return (0); } else if (errno == ETIME) { if (nevents == 0) @@ -341,8 +339,8 @@ evport_dispatch(struct event_base *base, void *arg, struct timeval *tv) perror("port_getn"); return (-1); } - } else if (evsignal_caught) { - evsignal_process(); + } else if (base->sig.evsignal_caught) { + evsignal_process(base); } event_debug(("%s: port_getn reports %d events", __func__, nevents)); diff --git a/evsignal.h b/evsignal.h index 5b92bd6e..7efbcabe 100644 --- a/evsignal.h +++ b/evsignal.h @@ -27,9 +27,18 @@ #ifndef _EVSIGNAL_H_ #define _EVSIGNAL_H_ -void evsignal_init(void); -void evsignal_process(void); +struct evsignal_info { + struct event_list signalqueue; + struct event ev_signal; + int ev_signal_pair[2]; + int ev_signal_added; + volatile sig_atomic_t evsignal_caught; + sig_atomic_t evsigcaught[NSIG]; +}; +void evsignal_init(struct event_base *); +void evsignal_process(struct event_base *); int evsignal_add(struct event *); int evsignal_del(struct event *); +void evsignal_dealloc(struct event_base *); #endif /* _EVSIGNAL_H_ */ diff --git a/kqueue.c b/kqueue.c index 08369c6d..af2e0f16 100644 --- a/kqueue.c +++ b/kqueue.c @@ -69,13 +69,13 @@ struct kqop { int kq; }; -void *kq_init (void); +void *kq_init (struct event_base *); int kq_add (void *, struct event *); int kq_del (void *, struct event *); int kq_recalc (struct event_base *, void *, int); int kq_dispatch (struct event_base *, void *, struct timeval *); int kq_insert (struct kqop *, struct kevent *); -void kq_dealloc (void *); +void kq_dealloc (struct event_base *, void *); const struct eventop kqops = { "kqueue", @@ -88,7 +88,7 @@ const struct eventop kqops = { }; void * -kq_init(void) +kq_init(struct event_base *base) { int kq; struct kqop *kqueueop; @@ -398,7 +398,7 @@ kq_del(void *arg, struct event *ev) } void -kq_dealloc(void *arg) +kq_dealloc(struct event_base *base, void *arg) { struct kqop *kqop = arg; diff --git a/poll.c b/poll.c index 14ca8453..84885984 100644 --- a/poll.c +++ b/poll.c @@ -54,8 +54,6 @@ #include "evsignal.h" #include "log.h" -extern volatile sig_atomic_t evsignal_caught; - struct pollop { int event_count; /* Highest number alloc */ int nfds; /* Size of event_* */ @@ -68,12 +66,12 @@ struct pollop { * "no entry." */ }; -void *poll_init (void); +void *poll_init (struct event_base *); int poll_add (void *, struct event *); int poll_del (void *, struct event *); int poll_recalc (struct event_base *, void *, int); int poll_dispatch (struct event_base *, void *, struct timeval *); -void poll_dealloc (void *); +void poll_dealloc (struct event_base *, void *); const struct eventop pollops = { "poll", @@ -86,7 +84,7 @@ const struct eventop pollops = { }; void * -poll_init(void) +poll_init(struct event_base *base) { struct pollop *pollop; @@ -97,7 +95,7 @@ poll_init(void) if (!(pollop = calloc(1, sizeof(struct pollop)))) return (NULL); - evsignal_init(); + evsignal_init(base); return (pollop); } @@ -164,10 +162,11 @@ poll_dispatch(struct event_base *base, void *arg, struct timeval *tv) return (-1); } - evsignal_process(); + evsignal_process(base); return (0); - } else if (evsignal_caught) - evsignal_process(); + } else if (base->sig.evsignal_caught) { + evsignal_process(base); + } event_debug(("%s: poll reports %d", __func__, res)); @@ -370,10 +369,11 @@ poll_del(void *arg, struct event *ev) } void -poll_dealloc(void *arg) +poll_dealloc(struct event_base *base, void *arg) { struct pollop *pop = arg; + evsignal_dealloc(base); if (pop->event_set) free(pop->event_set); if (pop->event_r_back) diff --git a/rtsig.c b/rtsig.c index 29aade69..3267af94 100644 --- a/rtsig.c +++ b/rtsig.c @@ -223,7 +223,7 @@ struct rtdata { int poll_position; }; -void *rtsig_init(void); +void *rtsig_init(struct event_base *); int rtsig_add(void *, struct event *); int rtsig_del(void *, struct event *); int rtsig_recalc(struct event_base *, void *, int); @@ -544,7 +544,7 @@ activate(struct event *ev, int flags) } while (0) void * -rtsig_init(void) +rtsig_init(struct event_base *) { struct rtsigop *op; int sockets[2]; diff --git a/select.c b/select.c index 6ce81a23..3affa12d 100644 --- a/select.c +++ b/select.c @@ -57,8 +57,6 @@ #define howmany(x, y) (((x)+((y)-1))/(y)) #endif -extern volatile sig_atomic_t evsignal_caught; - struct selectop { int event_fds; /* Highest fd in fd set */ int event_fdsz; @@ -70,12 +68,12 @@ struct selectop { struct event **event_w_by_fd; }; -void *select_init (void); +void *select_init (struct event_base *); int select_add (void *, struct event *); int select_del (void *, struct event *); int select_recalc (struct event_base *, void *, int); int select_dispatch (struct event_base *, void *, struct timeval *); -void select_dealloc (void *); +void select_dealloc (struct event_base *, void *); const struct eventop selectops = { "select", @@ -90,7 +88,7 @@ const struct eventop selectops = { static int select_resize(struct selectop *sop, int fdsz); void * -select_init(void) +select_init(struct event_base *base) { struct selectop *sop; @@ -103,7 +101,7 @@ select_init(void) select_resize(sop, howmany(32 + 1, NFDBITS)*sizeof(fd_mask)); - evsignal_init(); + evsignal_init(base); return (sop); } @@ -113,7 +111,7 @@ static void check_selectop(struct selectop *sop) { int i; - for (i=0;i<=sop->event_fds;++i) { + for (i = 0; i <= sop->event_fds; ++i) { if (FD_ISSET(i, sop->event_readset_in)) { assert(sop->event_r_by_fd[i]); assert(sop->event_r_by_fd[i]->ev_events & EV_READ); @@ -174,10 +172,11 @@ select_dispatch(struct event_base *base, void *arg, struct timeval *tv) return (-1); } - evsignal_process(); + evsignal_process(base); return (0); - } else if (evsignal_caught) - evsignal_process(); + } else if (base->sig.evsignal_caught) { + evsignal_process(base); + } event_debug(("%s: select reports %d", __func__, res)); @@ -348,10 +347,11 @@ select_del(void *arg, struct event *ev) } void -select_dealloc(void *arg) +select_dealloc(struct event_base *base, void *arg) { struct selectop *sop = arg; + evsignal_dealloc(base); if (sop->event_readset_in) free(sop->event_readset_in); if (sop->event_writeset_in) diff --git a/signal.c b/signal.c index 71bcffcb..6c0953d9 100644 --- a/signal.c +++ b/signal.c @@ -31,6 +31,7 @@ #endif #include +#include #ifdef HAVE_SYS_TIME_H #include #else @@ -47,19 +48,14 @@ #ifdef HAVE_FCNTL_H #include #endif +#include #include "event.h" +#include "event-internal.h" #include "evsignal.h" #include "log.h" -extern struct event_list signalqueue; - -static sig_atomic_t evsigcaught[NSIG]; -volatile sig_atomic_t evsignal_caught = 0; - -static struct event ev_signal; -static int ev_signal_pair[2]; -static int ev_signal_added; +struct event_base *evsignal_base = NULL; static void evsignal_handler(int sig); @@ -87,24 +83,27 @@ evsignal_cb(int fd, short what, void *arg) #endif void -evsignal_init(void) +evsignal_init(struct event_base *base) { /* * Our signal handler is going to write to one end of the socket * pair to wake up our event loop. The event loop then scans for * signals that got delivered. */ - if (socketpair(AF_UNIX, SOCK_STREAM, 0, ev_signal_pair) == -1) + if (socketpair(AF_UNIX, SOCK_STREAM, 0, base->sig.ev_signal_pair) == -1) event_err(1, "%s: socketpair", __func__); - FD_CLOSEONEXEC(ev_signal_pair[0]); - FD_CLOSEONEXEC(ev_signal_pair[1]); + FD_CLOSEONEXEC(base->sig.ev_signal_pair[0]); + FD_CLOSEONEXEC(base->sig.ev_signal_pair[1]); + base->sig.evsignal_caught = 0; + memset(&base->sig.evsigcaught, 0, sizeof(sig_atomic_t)*NSIG); - fcntl(ev_signal_pair[0], F_SETFL, O_NONBLOCK); + fcntl(base->sig.ev_signal_pair[0], F_SETFL, O_NONBLOCK); - event_set(&ev_signal, ev_signal_pair[1], EV_READ, - evsignal_cb, &ev_signal); - ev_signal.ev_flags |= EVLIST_INTERNAL; + event_set(&base->sig.ev_signal, base->sig.ev_signal_pair[1], EV_READ, + evsignal_cb, &base->sig.ev_signal); + base->sig.ev_signal.ev_base = base; + base->sig.ev_signal.ev_flags |= EVLIST_INTERNAL; } int @@ -112,6 +111,7 @@ evsignal_add(struct event *ev) { int evsignal; struct sigaction sa; + struct event_base *base = ev->ev_base; if (ev->ev_events & (EV_READ|EV_WRITE)) event_errx(1, "%s: EV_SIGNAL incompatible use", __func__); @@ -121,29 +121,23 @@ evsignal_add(struct event *ev) sa.sa_handler = evsignal_handler; sigfillset(&sa.sa_mask); sa.sa_flags |= SA_RESTART; + /* catch signals if they happen quickly */ + evsignal_base = base; if (sigaction(evsignal, &sa, NULL) == -1) return (-1); - if (!ev_signal_added) { - ev_signal_added = 1; - event_add(&ev_signal, NULL); + if (!base->sig.ev_signal_added) { + base->sig.ev_signal_added = 1; + event_add(&base->sig.ev_signal, NULL); } return (0); } -/* - * Nothing to be done here. - */ - int evsignal_del(struct event *ev) { - int evsignal; - - evsignal = EVENT_SIGNAL(ev); - return (sigaction(EVENT_SIGNAL(ev),(struct sigaction *)SIG_DFL, NULL)); } @@ -152,29 +146,50 @@ evsignal_handler(int sig) { int save_errno = errno; - evsigcaught[sig]++; - evsignal_caught = 1; + if(evsignal_base == NULL) { + event_warn( + "%s: received signal %s, but have no base configured", + __func__, sig); + return; + } + + evsignal_base->sig.evsigcaught[sig]++; + evsignal_base->sig.evsignal_caught = 1; /* Wake up our notification mechanism */ - write(ev_signal_pair[0], "a", 1); + write(evsignal_base->sig.ev_signal_pair[0], "a", 1); errno = save_errno; } void -evsignal_process(void) +evsignal_process(struct event_base *base) { struct event *ev; sig_atomic_t ncalls; - evsignal_caught = 0; - TAILQ_FOREACH(ev, &signalqueue, ev_signal_next) { - ncalls = evsigcaught[EVENT_SIGNAL(ev)]; + base->sig.evsignal_caught = 0; + TAILQ_FOREACH(ev, &base->sig.signalqueue, ev_signal_next) { + ncalls = base->sig.evsigcaught[EVENT_SIGNAL(ev)]; if (ncalls) { if (!(ev->ev_events & EV_PERSIST)) event_del(ev); event_active(ev, EV_SIGNAL, ncalls); - evsigcaught[EVENT_SIGNAL(ev)] = 0; + base->sig.evsigcaught[EVENT_SIGNAL(ev)] = 0; } } } +void +evsignal_dealloc(struct event_base *base) +{ + if(base->sig.ev_signal_added) { + event_del(&base->sig.ev_signal); + base->sig.ev_signal_added = 0; + } + assert(TAILQ_EMPTY(&base->sig.signalqueue)); + + close(base->sig.ev_signal_pair[0]); + base->sig.ev_signal_pair[0] = -1; + close(base->sig.ev_signal_pair[1]); + base->sig.ev_signal_pair[1] = -1; +} diff --git a/test/regress.c b/test/regress.c index ff134dad..9cd739da 100644 --- a/test/regress.c +++ b/test/regress.c @@ -35,6 +35,7 @@ #endif #include +#include #include #ifdef HAVE_SYS_TIME_H #include @@ -53,6 +54,7 @@ #include #include "event.h" +#include "event-internal.h" #include "log.h" #include "regress.h" @@ -465,6 +467,96 @@ test_immediatesignal(void) signal_del(&ev); cleanup_test(); } + +void +test_signal_dealloc(void) +{ + /* make sure that signal_event is event_del'ed and pipe closed */ + struct event ev; + struct event_base *base = event_init(); + printf("Signal dealloc: "); + signal_set(&ev, SIGUSR1, signal_cb, &ev); + signal_add(&ev, NULL); + signal_del(&ev); + event_base_free(base); + errno = EINTR; + if (base->sig.ev_signal_added) { + printf("ev_signal not removed (evsignal_dealloc needed) "); + test_ok = 0; + } else if (close(base->sig.ev_signal_pair[0]) != -1 || + errno != EBADF) { + /* fd must be closed, so second close gives -1, EBADF */ + printf("signal pipe still open (evsignal_dealloc needed) "); + test_ok = 0; + } else { + test_ok = 1; + } + cleanup_test(); +} + +void +test_signal_pipeloss(void) +{ + /* make sure that the base1 pipe is closed correctly. */ + struct event_base *base1, *base2; + int pipe1; + printf("Signal pipeloss: "); + base1 = event_init(); + pipe1 = base1->sig.ev_signal_pair[0]; + base2 = event_init(); + event_base_free(base2); + event_base_free(base1); + if (close(pipe1) != -1 || errno!=EBADF) { + /* fd must be closed, so second close gives -1, EBADF */ + printf("signal pipe not closed. "); + test_ok = 0; + } else { + test_ok = 1; + } + cleanup_test(); +} + +/* + * make two bases to catch signals, use both of them. this only works + * for event mechanisms that use our signal pipe trick. kqueue handles + * signals internally, and it looks like the first kqueue always gets the + * signal. + */ +void +test_signal_switchbase(void) +{ + struct event ev1, ev2; + struct event_base *base1, *base2; + printf("Signal switchbase: "); + base1 = event_init(); + base2 = event_init(); + signal_set(&ev1, SIGUSR1, signal_cb, &ev1); + signal_set(&ev2, SIGUSR1, signal_cb, &ev2); + if (event_base_set(base1, &ev1) || + event_base_set(base2, &ev2) || + event_add(&ev1, NULL) || + event_add(&ev2, NULL)) { + fprintf(stderr, "%s: cannot set base, add\n", __func__); + exit(1); + } + + test_ok = 0; + /* can handle signal before loop is called */ + raise(SIGUSR1); + event_base_loop(base2, EVLOOP_NONBLOCK); + event_base_loop(base1, EVLOOP_NONBLOCK); + if (test_ok) { + test_ok = 0; + /* set base1 to handle signals */ + event_base_loop(base1, EVLOOP_NONBLOCK); + raise(SIGUSR1); + event_base_loop(base1, EVLOOP_NONBLOCK); + event_base_loop(base2, EVLOOP_NONBLOCK); + } + event_base_free(base1); + event_base_free(base2); + cleanup_test(); +} #endif void @@ -930,6 +1022,12 @@ main (int argc, char **argv) test_multiple_events_for_same_fd(); test_want_only_once(); + +#ifndef WIN32 + test_signal_dealloc(); + test_signal_pipeloss(); + test_signal_switchbase(); +#endif evtag_test(); -- cgit v1.2.1