summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNiels Provos <provos@gmail.com>2007-11-25 06:57:59 +0000
committerNiels Provos <provos@gmail.com>2007-11-25 06:57:59 +0000
commit88897852fc72c2cd43c057f2fc550b5842d5b857 (patch)
tree3c60ef4af996cd1d1a02be96d003422626578b68
parent8c3396b0c60bd6c0dcc4f8baeb9174810247e557 (diff)
downloadlibevent-88897852fc72c2cd43c057f2fc550b5842d5b857.tar.gz
provide event_reinit() to reinitialized an event_base after fork - necessary for epoll/kqueue
svn:r539
-rw-r--r--ChangeLog1
-rw-r--r--epoll.c3
-rw-r--r--event-internal.h12
-rw-r--r--event.c25
-rw-r--r--event.h23
-rw-r--r--kqueue.c4
-rw-r--r--test/regress.c46
7 files changed, 101 insertions, 13 deletions
diff --git a/ChangeLog b/ChangeLog
index 086a1df4..22921dc0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -5,6 +5,7 @@ Changes in current version:
o bufferevent_write now uses a const source argument; report from Charles Kerr
o improve documentation on event_base_loopexit; patch from Scott Lamb
o New function, event_{base_}loopbreak. Like event_loopexit, it makes an event loop stop executing and return. Unlike event_loopexit, it keeps subsequent pending events from getting executed. Patch from Scott Lamb
+ o provide event_reinit() to reintialize an event_base after fork
Changes in 1.4.0:
o allow \r or \n individually to separate HTTP headers instead of the standard "\r\n"; from Charles Kerr.
diff --git a/epoll.c b/epoll.c
index 5afc8307..181dd894 100644
--- a/epoll.c
+++ b/epoll.c
@@ -83,7 +83,8 @@ struct eventop epollops = {
epoll_del,
epoll_recalc,
epoll_dispatch,
- epoll_dealloc
+ epoll_dealloc,
+ 1 /* need reinit */
};
#ifdef HAVE_SETFD
diff --git a/event-internal.h b/event-internal.h
index 56ef877b..16263a8f 100644
--- a/event-internal.h
+++ b/event-internal.h
@@ -35,6 +35,18 @@ extern "C" {
#include "min_heap.h"
#include "evsignal.h"
+struct eventop {
+ const char *name;
+ 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)(struct event_base *, void *);
+ /* set if we need to reinitialize the event base */
+ int need_reinit;
+};
+
struct event_base {
const struct eventop *evsel;
void *evbase;
diff --git a/event.c b/event.c
index d0e8d670..ebbb9015 100644
--- a/event.c
+++ b/event.c
@@ -250,6 +250,31 @@ event_base_free(struct event_base *base)
free(base);
}
+/* reinitialized the event base after a fork */
+int
+event_reinit(struct event_base *base)
+{
+ const struct eventop *evsel = base->evsel;
+ int res = 0;
+ struct event *ev;
+
+ /* check if this event mechanism requires reinit */
+ if (!evsel->need_reinit)
+ return (0);
+
+ base->evbase = evsel->init(base);
+ if (base->evbase == NULL)
+ event_errx(1, "%s: could not reinitialize event mechanism",
+ __func__);
+
+ TAILQ_FOREACH(ev, &base->eventqueue, ev_next) {
+ if (evsel->add(base, ev) == -1)
+ res = -1;
+ }
+
+ return (res);
+}
+
int
event_priority_init(int npriorities)
{
diff --git a/event.h b/event.h
index e2673086..b9d74976 100644
--- a/event.h
+++ b/event.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000-2004 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2000-2007 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -257,16 +257,6 @@ TAILQ_HEAD (event_list, event);
TAILQ_HEAD (evkeyvalq, evkeyval);
#endif /* _EVENT_DEFINED_TQENTRY */
-struct eventop {
- const char *name;
- 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)(struct event_base *, void *);
-};
-
/**
Initialize the event API.
@@ -289,6 +279,17 @@ struct event_base *event_base_new(void);
*/
struct event_base *event_init(void);
+/**
+ Reinitialized the event base after a fork
+
+ Some event mechanisms do not survive across fork. The event base needs
+ to be reinitialized with the event_reinit() function.
+
+ @param base the event base that needs to be re-initialized
+ @return 0 if successful, or -1 if some events could not be re-added.
+ @see event_base_new(), event_init()
+*/
+int event_reinit(struct event_base *base);
/**
Loop to process events.
diff --git a/kqueue.c b/kqueue.c
index c6dbf222..87c5fa7d 100644
--- a/kqueue.c
+++ b/kqueue.c
@@ -58,6 +58,7 @@
#endif
#include "event.h"
+#include "event-internal.h"
#include "log.h"
#define EVLIST_X_KQINKERNEL 0x1000
@@ -87,7 +88,8 @@ const struct eventop kqops = {
kq_del,
kq_recalc,
kq_dispatch,
- kq_dealloc
+ kq_dealloc,
+ 1 /* need reinit */
};
void *
diff --git a/test/regress.c b/test/regress.c
index ef5bdf5f..111d0628 100644
--- a/test/regress.c
+++ b/test/regress.c
@@ -42,6 +42,7 @@
#include <sys/queue.h>
#ifndef WIN32
#include <sys/socket.h>
+#include <sys/wait.h>
#include <sys/signal.h>
#include <unistd.h>
#include <netdb.h>
@@ -447,6 +448,47 @@ test_simpletimeout(void)
#ifndef WIN32
void
+test_fork(void)
+{
+ int status;
+ struct event ev;
+ pid_t pid;
+
+ setup_test("After fork: ");
+
+ write(pair[0], TEST1, strlen(TEST1)+1);
+ shutdown(pair[0], SHUT_WR);
+
+ event_set(&ev, pair[1], EV_READ, simple_read_cb, &ev);
+ if (event_add(&ev, NULL) == -1)
+ exit(1);
+
+ if ((pid = fork()) == 0) {
+ /* in the child */
+ extern struct event_base *current_base;
+ if (event_reinit(current_base) == -1) {
+ fprintf(stderr, "FAILED (reinit)\n");
+ exit(1);
+ }
+
+ event_dispatch();
+
+ exit(test_ok == 0);
+ }
+
+ event_del(&ev);
+
+ if (waitpid(pid, &status, 0) == -1) {
+ fprintf(stderr, "FAILED (fork)\n");
+ exit(1);
+ }
+
+ test_ok = WEXITSTATUS(status) == 0;
+
+ cleanup_test();
+}
+
+void
test_simplesignal(void)
{
struct event ev;
@@ -1227,6 +1269,10 @@ main (int argc, char **argv)
dns_suite();
+#ifndef WIN32
+ test_fork();
+#endif
+
test_simpleread();
test_simplewrite();