diff options
author | Niels Provos <provos@gmail.com> | 2007-11-25 06:57:59 +0000 |
---|---|---|
committer | Niels Provos <provos@gmail.com> | 2007-11-25 06:57:59 +0000 |
commit | 88897852fc72c2cd43c057f2fc550b5842d5b857 (patch) | |
tree | 3c60ef4af996cd1d1a02be96d003422626578b68 | |
parent | 8c3396b0c60bd6c0dcc4f8baeb9174810247e557 (diff) | |
download | libevent-88897852fc72c2cd43c057f2fc550b5842d5b857.tar.gz |
provide event_reinit() to reinitialized an event_base after fork - necessary for epoll/kqueue
svn:r539
-rw-r--r-- | ChangeLog | 1 | ||||
-rw-r--r-- | epoll.c | 3 | ||||
-rw-r--r-- | event-internal.h | 12 | ||||
-rw-r--r-- | event.c | 25 | ||||
-rw-r--r-- | event.h | 23 | ||||
-rw-r--r-- | kqueue.c | 4 | ||||
-rw-r--r-- | test/regress.c | 46 |
7 files changed, 101 insertions, 13 deletions
@@ -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. @@ -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; @@ -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) { @@ -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. @@ -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(); |