s3:events: pass __location__ to event_loop_*()
[ira/wip.git] / source3 / lib / events.c
index d6f3c328288d5e51e5bfe1e1c24f77d9da763bfb..8c56941829002030cbb654beb1fcc7d030c1e37b 100644 (file)
@@ -6,7 +6,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,
    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/>.
 */
 
 #include "includes.h"
+#include <tevent_internal.h>
 
-static struct timed_event *timed_events;
+void event_fd_set_writeable(struct tevent_fd *fde)
+{
+       TEVENT_FD_WRITEABLE(fde);
+}
 
-static int timed_event_destructor(struct timed_event *te)
+void event_fd_set_not_writeable(struct tevent_fd *fde)
 {
-       DEBUG(10, ("Destroying timed event %lx \"%s\"\n", (unsigned long)te,
-               te->event_name));
-       DLIST_REMOVE(timed_events, te);
-       return 0;
+       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 *add_timed_event(TALLOC_CTX *mem_ctx,
-                               struct timeval when,
-                               const char *event_name,
-                               void (*handler)(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, *last_te, *cur_te;
+       TEVENT_FD_READABLE(fde);
+}
 
-       te = TALLOC_P(mem_ctx, struct timed_event);
-       if (te == NULL) {
-               DEBUG(0, ("talloc failed\n"));
-               return NULL;
-       }
+void event_fd_set_not_readable(struct tevent_fd *fde)
+{
+       TEVENT_FD_NOT_READABLE(fde);
+}
+
+/*
+ * Return if there's something in the queue
+ */
 
-       te->when = when;
-       te->event_name = event_name;
-       te->handler = handler;
-       te->private_data = private_data;
+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 tevent_fd *fde;
+       struct timeval diff;
+       bool ret = false;
 
-       /* keep the list ordered - this is NOT guarenteed as event times
-          may be changed after insertion */
-       last_te = NULL;
-       for (cur_te = 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;
+       for (fde = ev->fd_events; fde; fde = fde->next) {
+               if (fde->flags & EVENT_FD_READ) {
+                       FD_SET(fde->fd, read_fds);
+                       ret = true;
+               }
+               if (fde->flags & EVENT_FD_WRITE) {
+                       FD_SET(fde->fd, write_fds);
+                       ret = true;
                }
-               last_te = cur_te;
+
+               if ((fde->flags & (EVENT_FD_READ|EVENT_FD_WRITE))
+                   && (fde->fd > *maxfd)) {
+                       *maxfd = fde->fd;
+               }
+       }
+
+       if (ev->timer_events == NULL) {
+               return ret;
        }
 
-       DLIST_ADD_AFTER(timed_events, te, last_te);
-       talloc_set_destructor(te, timed_event_destructor);
+       diff = timeval_until(now, &ev->timer_events->next_event);
+       *timeout = timeval_min(timeout, &diff);
 
-       DEBUG(10, ("Added timed event \"%s\": %lx\n", event_name,
-                       (unsigned long)te));
-       return te;
+       return true;
 }
 
-void run_events(void)
+bool run_events(struct tevent_context *ev,
+               int selrtn, fd_set *read_fds, fd_set *write_fds)
 {
-       /* Run all events that are pending, not just one (as we
-          did previously. */
+       struct tevent_fd *fde;
+       struct timeval now;
 
-       while (timed_events) {
-               struct timeval now;
-               GetTimeOfDay(&now);
+       if (ev->signal_events &&
+           tevent_common_check_signal(ev)) {
+               return true;
+       }
 
-               if (timeval_compare(&now, &timed_events->when) < 0) {
-                       /* Nothing to do yet */
-                       DEBUG(11, ("run_events: Nothing to do\n"));
-                       return;
-               }
+       GetTimeOfDay(&now);
+
+       if ((ev->timer_events != NULL)
+           && (timeval_compare(&now, &ev->timer_events->next_event) >= 0)) {
 
-               DEBUG(10, ("Running event \"%s\" %lx\n", timed_events->event_name,
-                       (unsigned long)timed_events));
+               DEBUG(10, ("Running timed event \"%s\" %p\n",
+                          ev->timer_events->handler_name, ev->timer_events));
 
-               timed_events->handler(timed_events, &now, timed_events->private_data);
+               ev->timer_events->handler(ev, ev->timer_events, now,
+                                         ev->timer_events->private_data);
+               return true;
        }
+
+       if (selrtn == 0) {
+               /*
+                * No fd ready
+                */
+               return false;
+       }
+
+       for (fde = ev->fd_events; fde; fde = fde->next) {
+               uint16 flags = 0;
+
+               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(ev, fde, flags, fde->private_data);
+                       return true;
+               }
+       }
+
+       return false;
 }
 
-struct timeval *get_timed_events_timeout(struct timeval *to_ret)
+
+struct timeval *get_timed_events_timeout(struct tevent_context *ev,
+                                        struct timeval *to_ret)
 {
        struct timeval now;
 
-       if (timed_events == NULL) {
+       if (ev->timer_events == NULL) {
                return NULL;
        }
 
        now = timeval_current();
-       *to_ret = timeval_until(&now, &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));
@@ -117,16 +145,165 @@ struct timeval *get_timed_events_timeout(struct timeval *to_ret)
        return to_ret;
 }
 
-int set_event_dispatch_time(const char *event_name, struct timeval when)
+static int s3_event_loop_once(struct tevent_context *ev, const char *location)
 {
-       int num_events = 0;
-       struct timed_event *te;
+       struct timeval now, to;
+       fd_set r_fds, w_fds;
+       int maxfd = 0;
+       int ret;
 
-       for (te = timed_events; te; te = te->next) {
-               if (strcmp(event_name, te->event_name) == 0) {
-                       te->when = when;
-                       num_events++;
-               }
+       FD_ZERO(&r_fds);
+       FD_ZERO(&w_fds);
+
+       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;
+       }
+
+       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;
        }
-       return num_events;
+
+       run_events(ev, ret, &r_fds, &w_fds);
+       return 0;
 }
+
+static int s3_event_loop_wait(struct tevent_context *ev, const char *location)
+{
+       int ret = 0;
+
+       while (ret == 0) {
+               ret = s3_event_loop_once(ev, location);
+       }
+
+       return ret;
+}
+
+void event_context_reinit(struct tevent_context *ev)
+{
+       tevent_common_context_destructor(ev);
+       return;
+}
+
+static int s3_event_context_init(struct tevent_context *ev)
+{
+       return 0;
+}
+
+void dump_event_list(struct tevent_context *ev)
+{
+       struct tevent_timer *te;
+       struct tevent_fd *fe;
+       struct timeval evt, now;
+
+       if (!ev) {
+               return;
+       }
+
+       now = timeval_current();
+
+       DEBUG(10,("dump_event_list:\n"));
+
+       for (te = ev->timer_events; te; te = te->next) {
+
+               evt = timeval_until(&now, &te->next_event);
+
+               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->next_event.tv_sec)));
+       }
+
+       for (fe = ev->fd_events; fe; fe = fe->next) {
+
+               DEBUGADD(10,("FD Event %d %p, flags: 0x%04x\n",
+                          fe->fd,
+                          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;
+}
+