summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNiels Provos <provos@gmail.com>2007-03-10 06:37:53 +0000
committerNiels Provos <provos@gmail.com>2007-03-10 06:37:53 +0000
commit41b7cbc38105a540ade7d02bb6137898a94abc89 (patch)
tree5a6081df26cb1f269b72bee380e2c1190817c401
parenta968da742598e9e6720c883cb78b1f0f6e912ae2 (diff)
downloadlibevent-41b7cbc38105a540ade7d02bb6137898a94abc89.tar.gz
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
-rw-r--r--WIN32-Code/win32.c8
-rw-r--r--devpoll.c20
-rw-r--r--epoll.c22
-rw-r--r--event-internal.h5
-rw-r--r--event.33
-rw-r--r--event.c67
-rw-r--r--event.h5
-rw-r--r--evport.c14
-rw-r--r--evsignal.h13
-rw-r--r--kqueue.c8
-rw-r--r--poll.c20
-rw-r--r--rtsig.c4
-rw-r--r--select.c22
-rw-r--r--signal.c85
-rw-r--r--test/regress.c98
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 <stdint.h>
#include <sys/types.h>
+#include <sys/tree.h>
#include <sys/resource.h>
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
@@ -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(&current_base->event_tv);
+ gettime(&base->event_tv);
- RB_INIT(&current_base->timetree);
- TAILQ_INIT(&current_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,12 +464,19 @@ 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;
int res;
@@ -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 <sys/types.h>
+#include <sys/tree.h>
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#else
@@ -47,19 +48,14 @@
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
+#include <assert.h>
#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 <sys/types.h>
+#include <sys/tree.h>
#include <sys/stat.h>
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
@@ -53,6 +54,7 @@
#include <errno.h>
#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();