Include events_util.h in events_aio.c
[metze/samba/wip.git] / source / lib / events / events_aio.c
index cd3c32a9b8fef184588dfac62ab8b0c5062389bd..e30213acbc71d540ef162878c3438909f81a4fda 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 "replace.h"
+#include "events.h"
+#include "events_internal.h"
+#include "events_util.h"
 #include <sys/epoll.h>
 #include <libaio.h>
 
@@ -48,6 +47,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 +63,7 @@ struct aio_event_context {
 
        int epoll_fd;
        int is_epoll_set;
+       pid_t pid;
 };
 
 struct aio_event {
@@ -92,6 +95,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)
@@ -109,7 +139,7 @@ static void epoll_add_event(struct aio_event_context *aio_ev, struct fd_event *f
        /* if we don't want events yet, don't add an aio_event */
        if (fde->flags == 0) return;
 
-       ZERO_STRUCT(event);
+       memset(&event, 0, sizeof(event));
        event.events = epoll_map_flags(fde->flags);
        event.data.ptr = fde;
        epoll_ctl(aio_ev->epoll_fd, EPOLL_CTL_ADD, fde->fd, &event);
@@ -127,6 +157,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;
@@ -165,9 +198,9 @@ static void epoll_mod_event(struct aio_event_context *aio_ev, struct fd_event *f
 
 static void epoll_change_event(struct aio_event_context *aio_ev, struct fd_event *fde)
 {
-       BOOL got_error = (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR);
-       BOOL want_read = (fde->flags & EVENT_FD_READ);
-       BOOL want_write= (fde->flags & EVENT_FD_WRITE);
+       bool got_error = (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR);
+       bool want_read = (fde->flags & EVENT_FD_READ);
+       bool want_write= (fde->flags & EVENT_FD_WRITE);
 
        if (aio_ev->epoll_fd == -1) return;
 
@@ -185,6 +218,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;
        }
@@ -219,7 +253,7 @@ static int setup_epoll_wait(struct aio_event_context *aio_ev)
 static int aio_event_loop(struct aio_event_context *aio_ev, struct timeval *tvalp)
 {
        int ret, i;
-       uint32_t destruction_count = aio_ev->destruction_count;
+       uint32_t destruction_count = ++aio_ev->destruction_count;
        struct timespec timeout;
        struct io_event events[8];
 
@@ -250,7 +284,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;
        }
 
@@ -324,15 +359,26 @@ static int aio_event_context_init(struct event_context *ev)
        aio_ev->epoll_iocb = talloc(aio_ev, struct iocb);
 
        if (io_queue_init(MAX_AIO_QUEUE_DEPTH, &aio_ev->ioctx) != 0) {
+               talloc_free(aio_ev);
                return -1;
        }
 
        aio_ev->epoll_fd = epoll_create(MAX_AIO_QUEUE_DEPTH);
-       if (aio_ev->epoll_fd == -1) return -1;
+       if (aio_ev->epoll_fd == -1) {
+               talloc_free(aio_ev);
+               return -1;
+       }
+       aio_ev->pid = getpid();
 
        talloc_set_destructor(aio_ev, aio_ctx_destructor);
 
        ev->additional_data = aio_ev;
+
+       if (setup_epoll_wait(aio_ev) < 0) {
+               talloc_free(aio_ev);
+               return -1;
+       }
+
        return 0;
 }
 
@@ -345,11 +391,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;
 }
 
@@ -366,6 +419,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;
 
@@ -380,6 +435,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;
@@ -409,6 +465,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);
 }
 
@@ -421,13 +479,13 @@ static int aio_event_loop_once(struct event_context *ev)
                                                           struct aio_event_context);
        struct timeval tval;
 
-       tval = common_event_loop_delay(ev);
-
-       if (timeval_is_zero(&tval)) {
-               common_event_loop_timer(ev);
+       tval = common_event_loop_timer_delay(ev);
+       if (ev_timeval_is_zero(&tval)) {
                return 0;
        }
 
+       epoll_check_reopen(aio_ev);
+
        return aio_event_loop(aio_ev, &tval);
 }
 
@@ -502,7 +560,8 @@ static const struct event_ops aio_event_ops = {
        .loop_wait      = aio_event_loop_wait,
 };
 
-NTSTATUS events_aio_init(void)
+bool events_aio_init(void)
 {
        return event_register_backend("aio", &aio_event_ops);
 }
+