Author: tridge
Date: 2007-05-17 02:18:29 +0000 (Thu, 17 May 2007)
New Revision: 22959

WebSVN: 
http://websvn.samba.org/cgi-bin/viewcvs.cgi?view=rev&root=samba&rev=22959

Log:

cope with a rather interesting interaction between epoll() and
fork(). See
http://junkcode.samba.org/ftp/unpacked/junkcode/epoll_fork.c for why
this is needed

Modified:
   branches/SAMBA_4_0/source/lib/events/events_standard.c


Changeset:
Modified: branches/SAMBA_4_0/source/lib/events/events_standard.c
===================================================================
--- branches/SAMBA_4_0/source/lib/events/events_standard.c      2007-05-17 
01:17:43 UTC (rev 22958)
+++ branches/SAMBA_4_0/source/lib/events/events_standard.c      2007-05-17 
02:18:29 UTC (rev 22959)
@@ -58,6 +58,9 @@
 
        /* when using epoll this is the handle from epoll_create */
        int epoll_fd;
+
+       /* our pid at the time the epoll_fd was created */
+       pid_t pid;
 };
 
 /* use epoll if it is available */
@@ -68,7 +71,9 @@
 */
 static void epoll_fallback_to_select(struct std_event_context *std_ev, const 
char *reason)
 {
+       const char *cmd = talloc_asprintf(std_ev, "xterm -e gdb --pid %u", 
getpid());
        DEBUG(0,("%s (%s) - falling back to select()\n", reason, 
strerror(errno)));
+       system(cmd);
        close(std_ev->epoll_fd);
        std_ev->epoll_fd = -1;
        talloc_set_destructor(std_ev, NULL);
@@ -90,7 +95,9 @@
 */
 static int epoll_ctx_destructor(struct std_event_context *std_ev)
 {
-       close(std_ev->epoll_fd);
+       if (std_ev->epoll_fd != -1) {
+               close(std_ev->epoll_fd);
+       }
        std_ev->epoll_fd = -1;
        return 0;
 }
@@ -101,9 +108,32 @@
 static void epoll_init_ctx(struct std_event_context *std_ev)
 {
        std_ev->epoll_fd = epoll_create(64);
+       std_ev->pid = getpid();
        talloc_set_destructor(std_ev, epoll_ctx_destructor);
 }
 
+static void epoll_add_event(struct std_event_context *std_ev, struct fd_event 
*fde);
+
+/*
+  reopen the epoll handle when our pid changes
+  see http://junkcode.samba.org/ftp/unpacked/junkcode/epoll_fork.c for an 
+  demonstration of why this is needed
+ */
+static void epoll_reopen(struct std_event_context *std_ev)
+{
+       struct fd_event *fde;
+
+       close(std_ev->epoll_fd);
+       std_ev->epoll_fd = epoll_create(64);
+       if (std_ev->epoll_fd == -1) {
+               return;
+       }
+       std_ev->pid = getpid();
+       for (fde=std_ev->fd_events;fde;fde=fde->next) {
+               epoll_add_event(std_ev, fde);
+       }
+}
+
 #define EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT     (1<<0)
 #define EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR  (1<<1)
 #define EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR     (1<<2)
@@ -116,6 +146,16 @@
        struct epoll_event event;
        if (std_ev->epoll_fd == -1) return;
 
+       /* during an add event we need to check if our pid has changed
+          and re-open the epoll socket. Note that we don't need to do this 
+          for other epoll changes */
+       if (std_ev->pid != getpid()) {
+               epoll_reopen(std_ev);
+               /* the current event gets added in epoll_reopen(), so
+                  we can return here */
+               return;
+       }
+
        fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
 
        /* if we don't want events yet, don't add an epoll_event */

Reply via email to