]> granicus.if.org Git - libevent/commitdiff
provide event_reinit() to reinitialized an event_base after fork - necessary for...
authorNiels Provos <provos@gmail.com>
Sun, 25 Nov 2007 06:57:59 +0000 (06:57 +0000)
committerNiels Provos <provos@gmail.com>
Sun, 25 Nov 2007 06:57:59 +0000 (06:57 +0000)
svn:r539

ChangeLog
epoll.c
event-internal.h
event.c
event.h
kqueue.c
test/regress.c

index 086a1df4e082beb072a0c39443cd2ec3f2161b4e..22921dc011a83b87c89e3acbb9a25a3936ae02d4 100644 (file)
--- 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 5afc83071e8562fcd22a084eba189beb1050c3b7..181dd8948ccfc86a5ce30661b9786526e3793e29 100644 (file)
--- 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
index 56ef877be414c20a1ca5e7251dec4d676986e4f8..16263a8f802a58dbf422ce93adf5b48ccdd18f43 100644 (file)
@@ -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 d0e8d6701c0708cf75e4214f37de6afc87077bcd..ebbb901563955f28f3a683a8dc498fafad5c9720 100644 (file)
--- 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 e267308684d67151512544dc0c08a30afd51af12..b9d7497678459d60bdee0991b47c6ba1b88b9e75 100644 (file)
--- 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.
index c6dbf222731880961fab36313294e810f5b2a996..87c5fa7dcc5d72eb9ae287b6f93c6453d89db787 100644 (file)
--- 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 *
index ef5bdf5f1440b71abeba3b41acbf00cfead6b833..111d06283c13454c8f5ad354bd851bffe4517a7a 100644 (file)
@@ -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>
@@ -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();