From: Niels Provos Date: Sun, 25 Nov 2007 06:57:59 +0000 (+0000) Subject: provide event_reinit() to reinitialized an event_base after fork - necessary for... X-Git-Tag: release-2.0.1-alpha~494 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=88897852fc72c2cd43c057f2fc550b5842d5b857;p=libevent provide event_reinit() to reinitialized an event_base after fork - necessary for epoll/kqueue svn:r539 --- 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 + * Copyright (c) 2000-2007 Niels Provos * 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 #ifndef WIN32 #include +#include #include #include #include @@ -446,6 +447,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) { @@ -1227,6 +1269,10 @@ main (int argc, char **argv) dns_suite(); +#ifndef WIN32 + test_fork(); +#endif + test_simpleread(); test_simplewrite();