This patch make it possible to build the events library completely
[metze/samba/wip.git] / source / lib / events / events_aio.c
index 9f4e9c561240d561af10233f2a605863dd542ab1..9d13ea96fdda7fc9b0b40807b8669e946f0477bd 100644 (file)
@@ -9,7 +9,7 @@
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
@@ -18,8 +18,7 @@
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 /*
   this is a very strange beast. The Linux AIO implementation doesn't
   this is _very_ experimental code
 */
 
-#include "includes.h"
 #include "system/filesys.h"
-#include "lib/util/dlinklist.h"
-#include "lib/events/events.h"
-#include "lib/events/events_internal.h"
+#include "system/network.h"
+#include "events.h"
+#include "events_internal.h"
 #include <sys/epoll.h>
 #include <libaio.h>
 
@@ -48,6 +46,9 @@ struct aio_event_context {
        /* a pointer back to the generic event_context */
        struct event_context *ev;
 
+       /* list of filedescriptor events */
+       struct fd_event *fd_events;
+
        /* number of registered fd event handlers */
        int num_fd_events;
 
@@ -61,6 +62,7 @@ struct aio_event_context {
 
        int epoll_fd;
        int is_epoll_set;
+       pid_t pid;
 };
 
 struct aio_event {
@@ -92,6 +94,33 @@ static int aio_ctx_destructor(struct aio_event_context *aio_ev)
        return 0;
 }
 
+static void epoll_add_event(struct aio_event_context *aio_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_check_reopen(struct aio_event_context *aio_ev)
+{
+       struct fd_event *fde;
+
+       if (aio_ev->pid == getpid()) {
+               return;
+       }
+
+       close(aio_ev->epoll_fd);
+       aio_ev->epoll_fd = epoll_create(MAX_AIO_QUEUE_DEPTH);
+       if (aio_ev->epoll_fd == -1) {
+               ev_debug(aio_ev->ev, EV_DEBUG_FATAL, "Failed to recreate epoll handle after fork\n");
+               return;
+       }
+       aio_ev->pid = getpid();
+       for (fde=aio_ev->fd_events;fde;fde=fde->next) {
+               epoll_add_event(aio_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)
@@ -127,6 +156,9 @@ static void epoll_add_event(struct aio_event_context *aio_ev, struct fd_event *f
 static void epoll_del_event(struct aio_event_context *aio_ev, struct fd_event *fde)
 {
        struct epoll_event event;
+
+       DLIST_REMOVE(aio_ev->fd_events, fde);
+
        if (aio_ev->epoll_fd == -1) return;
 
        fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
@@ -185,6 +217,7 @@ static void epoll_change_event(struct aio_event_context *aio_ev, struct fd_event
 
        /* there's no aio_event attached to the fde */
        if (want_read || (want_write && !got_error)) {
+               DLIST_ADD(aio_ev->fd_events, fde);
                epoll_add_event(aio_ev, fde);
                return;
        }
@@ -250,7 +283,8 @@ static int aio_event_loop(struct aio_event_context *aio_ev, struct timeval *tval
        }
 
        if (ret == 0 && tvalp) {
-               common_event_loop_timer(aio_ev->ev);
+               /* we don't care about a possible delay here */
+               common_event_loop_timer_delay(aio_ev->ev);
                return 0;
        }
 
@@ -333,6 +367,7 @@ static int aio_event_context_init(struct event_context *ev)
                talloc_free(aio_ev);
                return -1;
        }
+       aio_ev->pid = getpid();
 
        talloc_set_destructor(aio_ev, aio_ctx_destructor);
 
@@ -355,11 +390,18 @@ static int aio_event_fd_destructor(struct fd_event *fde)
        struct aio_event_context *aio_ev = talloc_get_type(ev->additional_data,
                                                           struct aio_event_context);
 
+       epoll_check_reopen(aio_ev);
+
        aio_ev->num_fd_events--;
        aio_ev->destruction_count++;
 
        epoll_del_event(aio_ev, fde);
 
+       if (fde->flags & EVENT_FD_AUTOCLOSE) {
+               close(fde->fd);
+               fde->fd = -1;
+       }
+
        return 0;
 }
 
@@ -376,6 +418,8 @@ static struct fd_event *aio_event_add_fd(struct event_context *ev, TALLOC_CTX *m
                                                           struct aio_event_context);
        struct fd_event *fde;
 
+       epoll_check_reopen(aio_ev);
+
        fde = talloc(mem_ctx?mem_ctx:ev, struct fd_event);
        if (!fde) return NULL;
 
@@ -390,6 +434,7 @@ static struct fd_event *aio_event_add_fd(struct event_context *ev, TALLOC_CTX *m
        aio_ev->num_fd_events++;
        talloc_set_destructor(fde, aio_event_fd_destructor);
 
+       DLIST_ADD(aio_ev->fd_events, fde);
        epoll_add_event(aio_ev, fde);
 
        return fde;
@@ -419,6 +464,8 @@ static void aio_event_set_fd_flags(struct fd_event *fde, uint16_t flags)
 
        fde->flags = flags;
 
+       epoll_check_reopen(aio_ev);
+
        epoll_change_event(aio_ev, fde);
 }
 
@@ -431,13 +478,13 @@ static int aio_event_loop_once(struct event_context *ev)
                                                           struct aio_event_context);
        struct timeval tval;
 
-       tval = common_event_loop_delay(ev);
-
+       tval = common_event_loop_timer_delay(ev);
        if (timeval_is_zero(&tval)) {
-               common_event_loop_timer(ev);
                return 0;
        }
 
+       epoll_check_reopen(aio_ev);
+
        return aio_event_loop(aio_ev, &tval);
 }
 
@@ -517,12 +564,3 @@ bool events_aio_init(void)
        return event_register_backend("aio", &aio_event_ops);
 }
 
-#if _SAMBA_BUILD_
-NTSTATUS s4_events_aio_init(void)
-{
-       if (!events_aio_init()) {
-               return NT_STATUS_INTERNAL_ERROR;
-       }
-       return NT_STATUS_OK;
-}
-#endif