s3:events: pass __location__ to event_loop_*()
[ira/wip.git] / source3 / lib / events.c
index 0e3fecfaa225dc0bd83560bdc32acc4ba9200224..8c56941829002030cbb654beb1fcc7d030c1e37b 100644 (file)
 */
 
 #include "includes.h"
+#include <tevent_internal.h>
 
-struct timed_event {
-       struct timed_event *next, *prev;
-       struct event_context *event_ctx;
-       struct timeval when;
-       const char *event_name;
-       void (*handler)(struct event_context *event_ctx,
-                       struct timed_event *te,
-                       const struct timeval *now,
-                       void *private_data);
-       void *private_data;
-};
-
-struct fd_event {
-       struct fd_event *prev, *next;
-       struct event_context *event_ctx;
-       int fd;
-       uint16_t flags; /* see EVENT_FD_* flags */
-       void (*handler)(struct event_context *event_ctx,
-                       struct fd_event *event,
-                       uint16 flags,
-                       void *private_data);
-       void *private_data;
-};
-
-struct event_context {
-       struct timed_event *timed_events;
-       struct fd_event *fd_events;
-};
-
-static int timed_event_destructor(struct timed_event *te)
+void event_fd_set_writeable(struct tevent_fd *fde)
 {
-       DEBUG(10, ("Destroying timed event %lx \"%s\"\n", (unsigned long)te,
-               te->event_name));
-       if (te->event_ctx != NULL) {
-               DLIST_REMOVE(te->event_ctx->timed_events, te);
-       }
-       return 0;
+       TEVENT_FD_WRITEABLE(fde);
 }
 
-/****************************************************************************
- Add te by time.
-****************************************************************************/
-
-static void add_event_by_time(struct timed_event *te)
+void event_fd_set_not_writeable(struct tevent_fd *fde)
 {
-       struct event_context *ctx = te->event_ctx;
-       struct timed_event *last_te, *cur_te;
-
-       /* Keep the list ordered by time. We must preserve this. */
-       last_te = NULL;
-       for (cur_te = ctx->timed_events; cur_te; cur_te = cur_te->next) {
-               /* if the new event comes before the current one break */
-               if (!timeval_is_zero(&cur_te->when) &&
-                               timeval_compare(&te->when, &cur_te->when) < 0) {
-                       break;
-               }
-               last_te = cur_te;
-       }
-
-       DLIST_ADD_AFTER(ctx->timed_events, te, last_te);
+       TEVENT_FD_NOT_WRITEABLE(fde);
 }
 
-/****************************************************************************
- Schedule a function for future calling, cancel with TALLOC_FREE().
- It's the responsibility of the handler to call TALLOC_FREE() on the event
- handed to it.
-****************************************************************************/
-
-struct timed_event *event_add_timed(struct event_context *event_ctx,
-                               TALLOC_CTX *mem_ctx,
-                               struct timeval when,
-                               const char *event_name,
-                               void (*handler)(struct event_context *event_ctx,
-                                               struct timed_event *te,
-                                               const struct timeval *now,
-                                               void *private_data),
-                               void *private_data)
+void event_fd_set_readable(struct tevent_fd *fde)
 {
-       struct timed_event *te;
-
-       te = TALLOC_P(mem_ctx, struct timed_event);
-       if (te == NULL) {
-               DEBUG(0, ("talloc failed\n"));
-               return NULL;
-       }
-
-       te->event_ctx = event_ctx;
-       te->when = when;
-       te->event_name = event_name;
-       te->handler = handler;
-       te->private_data = private_data;
-
-       add_event_by_time(te);
-
-       talloc_set_destructor(te, timed_event_destructor);
-
-       DEBUG(10, ("Added timed event \"%s\": %lx\n", event_name,
-                       (unsigned long)te));
-       return te;
+       TEVENT_FD_READABLE(fde);
 }
 
-static int fd_event_destructor(struct fd_event *fde)
+void event_fd_set_not_readable(struct tevent_fd *fde)
 {
-       if (fde->event_ctx != NULL) {
-               DLIST_REMOVE(fde->event_ctx->fd_events, fde);
-       }
-       return 0;
-}
-
-struct fd_event *event_add_fd(struct event_context *event_ctx,
-                             TALLOC_CTX *mem_ctx,
-                             int fd, uint16_t flags,
-                             void (*handler)(struct event_context *event_ctx,
-                                             struct fd_event *event,
-                                             uint16 flags,
-                                             void *private_data),
-                             void *private_data)
-{
-       struct fd_event *fde;
-
-       if (!(fde = TALLOC_P(mem_ctx, struct fd_event))) {
-               return NULL;
-       }
-
-       fde->event_ctx = event_ctx;
-       fde->fd = fd;
-       fde->flags = flags;
-       fde->handler = handler;
-       fde->private_data = private_data;
-
-       DLIST_ADD(event_ctx->fd_events, fde);
-
-       talloc_set_destructor(fde, fd_event_destructor);
-       return fde;
-}
-
-void event_fd_set_writeable(struct fd_event *fde)
-{
-       fde->flags |= EVENT_FD_WRITE;
-}
-
-void event_fd_set_not_writeable(struct fd_event *fde)
-{
-       fde->flags &= ~EVENT_FD_WRITE;
-}
-
-void event_fd_set_readable(struct fd_event *fde)
-{
-       fde->flags |= EVENT_FD_READ;
-}
-
-void event_fd_set_not_readable(struct fd_event *fde)
-{
-       fde->flags &= ~EVENT_FD_READ;
+       TEVENT_FD_NOT_READABLE(fde);
 }
 
 /*
  * Return if there's something in the queue
  */
 
-bool event_add_to_select_args(struct event_context *event_ctx,
+bool event_add_to_select_args(struct tevent_context *ev,
                              const struct timeval *now,
                              fd_set *read_fds, fd_set *write_fds,
                              struct timeval *timeout, int *maxfd)
 {
-       struct fd_event *fde;
+       struct tevent_fd *fde;
        struct timeval diff;
-       bool ret = False;
+       bool ret = false;
 
-       for (fde = event_ctx->fd_events; fde; fde = fde->next) {
+       for (fde = ev->fd_events; fde; fde = fde->next) {
                if (fde->flags & EVENT_FD_READ) {
                        FD_SET(fde->fd, read_fds);
-                       ret = True;
+                       ret = true;
                }
                if (fde->flags & EVENT_FD_WRITE) {
                        FD_SET(fde->fd, write_fds);
-                       ret = True;
+                       ret = true;
                }
 
                if ((fde->flags & (EVENT_FD_READ|EVENT_FD_WRITE))
@@ -205,91 +70,74 @@ bool event_add_to_select_args(struct event_context *event_ctx,
                }
        }
 
-       if (event_ctx->timed_events == NULL) {
+       if (ev->timer_events == NULL) {
                return ret;
        }
 
-       diff = timeval_until(now, &event_ctx->timed_events->when);
+       diff = timeval_until(now, &ev->timer_events->next_event);
        *timeout = timeval_min(timeout, &diff);
 
-       return True;
+       return true;
 }
 
-bool run_events(struct event_context *event_ctx,
+bool run_events(struct tevent_context *ev,
                int selrtn, fd_set *read_fds, fd_set *write_fds)
 {
-       bool fired = False;
-       struct fd_event *fde, *next;
-
-       /* Run all events that are pending, not just one (as we
-          did previously. */
-
-       while (event_ctx->timed_events) {
-               struct timeval now;
-               GetTimeOfDay(&now);
+       struct tevent_fd *fde;
+       struct timeval now;
 
-               if (timeval_compare(
-                           &now, &event_ctx->timed_events->when) < 0) {
-                       /* Nothing to do yet */
-                       DEBUG(11, ("run_events: Nothing to do\n"));
-                       break;
-               }
+       if (ev->signal_events &&
+           tevent_common_check_signal(ev)) {
+               return true;
+       }
 
-               DEBUG(10, ("Running event \"%s\" %lx\n",
-                          event_ctx->timed_events->event_name,
-                          (unsigned long)event_ctx->timed_events));
+       GetTimeOfDay(&now);
 
-               event_ctx->timed_events->handler(
-                       event_ctx,
-                       event_ctx->timed_events, &now,
-                       event_ctx->timed_events->private_data);
+       if ((ev->timer_events != NULL)
+           && (timeval_compare(&now, &ev->timer_events->next_event) >= 0)) {
 
-               fired = True;
-       }
+               DEBUG(10, ("Running timed event \"%s\" %p\n",
+                          ev->timer_events->handler_name, ev->timer_events));
 
-       if (fired) {
-               /*
-                * We might have changed the socket status during the timed
-                * events, return to run select again.
-                */
-               return True;
+               ev->timer_events->handler(ev, ev->timer_events, now,
+                                         ev->timer_events->private_data);
+               return true;
        }
 
        if (selrtn == 0) {
                /*
                 * No fd ready
                 */
-               return fired;
+               return false;
        }
 
-       for (fde = event_ctx->fd_events; fde; fde = next) {
+       for (fde = ev->fd_events; fde; fde = fde->next) {
                uint16 flags = 0;
 
-               next = fde->next;
                if (FD_ISSET(fde->fd, read_fds)) flags |= EVENT_FD_READ;
                if (FD_ISSET(fde->fd, write_fds)) flags |= EVENT_FD_WRITE;
 
                if (flags & fde->flags) {
-                       fde->handler(event_ctx, fde, flags, fde->private_data);
-                       fired = True;
+                       fde->handler(ev, fde, flags, fde->private_data);
+                       return true;
                }
        }
 
-       return fired;
+       return false;
 }
 
 
-struct timeval *get_timed_events_timeout(struct event_context *event_ctx,
+struct timeval *get_timed_events_timeout(struct tevent_context *ev,
                                         struct timeval *to_ret)
 {
        struct timeval now;
 
-       if (event_ctx->timed_events == NULL) {
+       if (ev->timer_events == NULL) {
                return NULL;
        }
 
        now = timeval_current();
-       *to_ret = timeval_until(&now, &event_ctx->timed_events->when);
+       *to_ret = timeval_until(&now, &ev->timer_events->next_event);
 
        DEBUG(10, ("timed_events_timeout: %d/%d\n", (int)to_ret->tv_sec,
                (int)to_ret->tv_usec));
@@ -297,7 +145,7 @@ struct timeval *get_timed_events_timeout(struct event_context *event_ctx,
        return to_ret;
 }
 
-int event_loop_once(struct event_context *ev)
+static int s3_event_loop_once(struct tevent_context *ev, const char *location)
 {
        struct timeval now, to;
        fd_set r_fds, w_fds;
@@ -310,20 +158,22 @@ int event_loop_once(struct event_context *ev)
        to.tv_sec = 9999;       /* Max timeout */
        to.tv_usec = 0;
 
+       if (run_events(ev, 0, NULL, NULL)) {
+               return 0;
+       }
+
        GetTimeOfDay(&now);
 
        if (!event_add_to_select_args(ev, &now, &r_fds, &w_fds, &to, &maxfd)) {
                return -1;
        }
 
-       if (timeval_is_zero(&to)) {
-               run_events(ev, 0, NULL, NULL);
-               return 0;
-       }
-
        ret = sys_select(maxfd+1, &r_fds, &w_fds, NULL, &to);
 
        if (ret == -1 && errno != EINTR) {
+               tevent_debug(ev, TEVENT_DEBUG_FATAL,
+                            "sys_select() failed: %d:%s\n",
+                            errno, strerror(errno));
                return -1;
        }
 
@@ -331,77 +181,35 @@ int event_loop_once(struct event_context *ev)
        return 0;
 }
 
-static int event_context_destructor(struct event_context *ev)
+static int s3_event_loop_wait(struct tevent_context *ev, const char *location)
 {
-       while (ev->fd_events != NULL) {
-               ev->fd_events->event_ctx = NULL;
-               DLIST_REMOVE(ev->fd_events, ev->fd_events);
-       }
-       while (ev->timed_events != NULL) {
-               ev->timed_events->event_ctx = NULL;
-               DLIST_REMOVE(ev->timed_events, ev->timed_events);
-       }
-       return 0;
-}
+       int ret = 0;
 
-void event_context_reinit(struct event_context *ev)
-{
-       event_context_destructor(ev);
-       return;
-}
-
-struct event_context *event_context_init(TALLOC_CTX *mem_ctx)
-{
-       struct event_context *result;
-
-       result = TALLOC_ZERO_P(mem_ctx, struct event_context);
-       if (result == NULL) {
-               return NULL;
+       while (ret == 0) {
+               ret = s3_event_loop_once(ev, location);
        }
 
-       talloc_set_destructor(result, event_context_destructor);
-       return result;
+       return ret;
 }
 
-int set_event_dispatch_time(struct event_context *event_ctx,
-                           const char *event_name, struct timeval when)
+void event_context_reinit(struct tevent_context *ev)
 {
-       struct timed_event *te;
-
-       for (te = event_ctx->timed_events; te; te = te->next) {
-               if (strcmp(event_name, te->event_name) == 0) {
-                       DLIST_REMOVE(event_ctx->timed_events, te);
-                       te->when = when;
-                       add_event_by_time(te);
-                       return 1;
-               }
-       }
-       return 0;
+       tevent_common_context_destructor(ev);
+       return;
 }
 
-/* Returns 1 if event was found and cancelled, 0 otherwise. */
-
-int cancel_named_event(struct event_context *event_ctx,
-                      const char *event_name)
+static int s3_event_context_init(struct tevent_context *ev)
 {
-       struct timed_event *te;
-
-       for (te = event_ctx->timed_events; te; te = te->next) {
-               if (strcmp(event_name, te->event_name) == 0) {
-                       TALLOC_FREE(te);
-                       return 1;
-               }
-       }
        return 0;
 }
 
-void dump_event_list(struct event_context *event_ctx)
+void dump_event_list(struct tevent_context *ev)
 {
-       struct timed_event *te;
-       struct fd_event *fe;
+       struct tevent_timer *te;
+       struct tevent_fd *fe;
        struct timeval evt, now;
 
-       if (!event_ctx) {
+       if (!ev) {
                return;
        }
 
@@ -409,22 +217,93 @@ void dump_event_list(struct event_context *event_ctx)
 
        DEBUG(10,("dump_event_list:\n"));
 
-       for (te = event_ctx->timed_events; te; te = te->next) {
+       for (te = ev->timer_events; te; te = te->next) {
 
-               evt = timeval_until(&now, &te->when);
+               evt = timeval_until(&now, &te->next_event);
 
-               DEBUGADD(10,("Timed Event \"%s\" %lx handled in %d seconds (at %s)\n",
-                          te->event_name,
-                          (unsigned long)te,
+               DEBUGADD(10,("Timed Event \"%s\" %p handled in %d seconds (at %s)\n",
+                          te->handler_name,
+                          te,
                           (int)evt.tv_sec,
-                          http_timestring(talloc_tos(), te->when.tv_sec)));
+                          http_timestring(talloc_tos(), te->next_event.tv_sec)));
        }
 
-       for (fe = event_ctx->fd_events; fe; fe = fe->next) {
+       for (fe = ev->fd_events; fe; fe = fe->next) {
 
-               DEBUGADD(10,("FD Event %d %lx, flags: 0x%04x\n",
+               DEBUGADD(10,("FD Event %d %p, flags: 0x%04x\n",
                           fe->fd,
-                          (unsigned long)fe,
+                          fe,
                           fe->flags));
        }
 }
+
+static const struct tevent_ops s3_event_ops = {
+       .context_init   = s3_event_context_init,
+       .add_fd         = tevent_common_add_fd,
+       .set_fd_close_fn= tevent_common_fd_set_close_fn,
+       .get_fd_flags   = tevent_common_fd_get_flags,
+       .set_fd_flags   = tevent_common_fd_set_flags,
+       .add_timer      = tevent_common_add_timer,
+       .add_signal     = tevent_common_add_signal,
+       .loop_once      = s3_event_loop_once,
+       .loop_wait      = s3_event_loop_wait,
+};
+
+static bool s3_tevent_init(void)
+{
+       static bool initialized;
+       if (initialized) {
+               return true;
+       }
+       initialized = tevent_register_backend("s3", &s3_event_ops);
+       tevent_set_default_backend("s3");
+       return initialized;
+}
+
+/*
+  this is used to catch debug messages from events
+*/
+static void s3_event_debug(void *context, enum tevent_debug_level level,
+                          const char *fmt, va_list ap)  PRINTF_ATTRIBUTE(3,0);
+
+static void s3_event_debug(void *context, enum tevent_debug_level level,
+                          const char *fmt, va_list ap)
+{
+       int samba_level = -1;
+       char *s = NULL;
+       switch (level) {
+       case TEVENT_DEBUG_FATAL:
+               samba_level = 0;
+               break;
+       case TEVENT_DEBUG_ERROR:
+               samba_level = 1;
+               break;
+       case TEVENT_DEBUG_WARNING:
+               samba_level = 2;
+               break;
+       case TEVENT_DEBUG_TRACE:
+               samba_level = 10;
+               break;
+
+       };
+       if (vasprintf(&s, fmt, ap) == -1) {
+               return;
+       }
+       DEBUG(samba_level, ("s3_event: %s", s));
+       free(s);
+}
+
+struct tevent_context *s3_tevent_context_init(TALLOC_CTX *mem_ctx)
+{
+       struct tevent_context *ev;
+
+       s3_tevent_init();
+
+       ev = tevent_context_init_byname(mem_ctx, "s3");
+       if (ev) {
+               tevent_set_debug(ev, s3_event_debug, NULL);
+       }
+
+       return ev;
+}
+