r25026: Move param/param.h out of includes.h
[kai/samba-autobuild/.git] / source4 / lib / events / events.c
index b6ba79430c633438692f088f2e953912dc5ed758..77225b9ddf34af4643c37111e74cd4b295d332a8 100644 (file)
@@ -5,7 +5,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,
@@ -14,8 +14,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/>.
 */
 
 /*
 #include "includes.h"
 #include "lib/events/events.h"
 #include "lib/events/events_internal.h"
+#include "lib/util/dlinklist.h"
+#include "param/param.h"
+#if _SAMBA_BUILD_
+#include "build.h"
+#endif
+
+struct event_ops_list {
+       struct event_ops_list *next, *prev;
+       const char *name;
+       const struct event_ops *ops;
+};
+
+/* list of registered event backends */
+static struct event_ops_list *event_backends;
+
+static char *event_default_backend = NULL;
+
+/*
+  register an events backend
+*/
+bool event_register_backend(const char *name, const struct event_ops *ops)
+{
+       struct event_ops_list *e;
+       e = talloc(talloc_autofree_context(), struct event_ops_list);
+       if (e == NULL) return False;
+       e->name = name;
+       e->ops = ops;
+       DLIST_ADD(event_backends, e);
+       return True;
+}
+
+/*
+  set the default event backend
+ */
+void event_set_default_backend(const char *backend)
+{
+       if (event_default_backend) free(event_default_backend);
+       event_default_backend = strdup(backend);
+}
+
+/*
+  initialise backends if not already done
+*/
+static void event_backend_init(void)
+{
+#if _SAMBA_BUILD_
+       init_module_fn static_init[] = STATIC_LIBEVENTS_MODULES;
+       init_module_fn *shared_init;
+       if (event_backends) return;
+       shared_init = load_samba_modules(NULL, "LIBEVENTS");
+       run_init_functions(static_init);
+       run_init_functions(shared_init);
+#else
+       bool events_standard_init(void);
+       bool events_select_init(void);
+       events_select_init();
+       events_standard_init();
+#if HAVE_EVENTS_EPOLL
+       {
+               bool events_epoll_init(void);
+               events_epoll_init();
+       }
+#endif
+#endif
+}
+
+/*
+  list available backends
+*/
+const char **event_backend_list(TALLOC_CTX *mem_ctx)
+{
+       const char **list = NULL;
+       struct event_ops_list *e;
+
+       event_backend_init();
+
+       for (e=event_backends;e;e=e->next) {
+               list = str_list_add(list, e->name);
+       }
+
+       talloc_steal(mem_ctx, list);
+
+       return list;
+}
 
 /*
   create a event_context structure for a specific implemementation.
 
   NOTE: use event_context_init() inside of samba!
 */
-struct event_context *event_context_init_ops(TALLOC_CTX *mem_ctx, const struct event_ops *ops, void *private_data)
+static struct event_context *event_context_init_ops(TALLOC_CTX *mem_ctx, 
+                                                   const struct event_ops *ops)
 {
        struct event_context *ev;
        int ret;
@@ -79,7 +163,7 @@ struct event_context *event_context_init_ops(TALLOC_CTX *mem_ctx, const struct e
 
        ev->ops = ops;
 
-       ret = ev->ops->context_init(ev, private_data);
+       ret = ev->ops->context_init(ev);
        if (ret != 0) {
                talloc_free(ev);
                return NULL;
@@ -88,6 +172,38 @@ struct event_context *event_context_init_ops(TALLOC_CTX *mem_ctx, const struct e
        return ev;
 }
 
+/*
+  create a event_context structure. This must be the first events
+  call, and all subsequent calls pass this event_context as the first
+  element. Event handlers also receive this as their first argument.
+*/
+struct event_context *event_context_init_byname(TALLOC_CTX *mem_ctx, const char *name)
+{
+       struct event_ops_list *e;
+
+       event_backend_init();
+
+#if _SAMBA_BUILD_
+       if (name == NULL) {
+               name = lp_parm_string(-1, "event", "backend");
+       }
+#endif
+       if (name == NULL) {
+               name = event_default_backend;
+       }
+       if (name == NULL) {
+               name = "standard";
+       }
+
+       for (e=event_backends;e;e=e->next) {
+               if (strcmp(name, e->name) == 0) {
+                       return event_context_init_ops(mem_ctx, e->ops);
+               }
+       }
+       return NULL;
+}
+
+
 /*
   create a event_context structure. This must be the first events
   call, and all subsequent calls pass this event_context as the first
@@ -95,13 +211,15 @@ struct event_context *event_context_init_ops(TALLOC_CTX *mem_ctx, const struct e
 */
 struct event_context *event_context_init(TALLOC_CTX *mem_ctx)
 {
-       const struct event_ops *ops = event_standard_get_ops();
-       return event_context_init_ops(mem_ctx, ops, NULL);
+       return event_context_init_byname(mem_ctx, NULL);
 }
 
 /*
   add a fd based event
   return NULL on failure (memory allocation error)
+
+  if flags contains EVENT_FD_AUTOCLOSE then the fd will be closed when
+  the returned fd_event context is freed
 */
 struct fd_event *event_add_fd(struct event_context *ev, TALLOC_CTX *mem_ctx,
                              int fd, uint16_t flags, event_fd_handler_t handler,
@@ -110,11 +228,25 @@ struct fd_event *event_add_fd(struct event_context *ev, TALLOC_CTX *mem_ctx,
        return ev->ops->add_fd(ev, mem_ctx, fd, flags, handler, private_data);
 }
 
+/*
+  add a disk aio event
+*/
+struct aio_event *event_add_aio(struct event_context *ev,
+                               TALLOC_CTX *mem_ctx,
+                               struct iocb *iocb,
+                               event_aio_handler_t handler,
+                               void *private_data)
+{
+       if (ev->ops->add_aio == NULL) return NULL;
+       return ev->ops->add_aio(ev, mem_ctx, iocb, handler, private_data);
+}
+
 /*
   return the fd event flags
 */
 uint16_t event_get_fd_flags(struct fd_event *fde)
 {
+       if (!fde) return 0;
        return fde->event_ctx->ops->get_fd_flags(fde);
 }
 
@@ -123,6 +255,7 @@ uint16_t event_get_fd_flags(struct fd_event *fde)
 */
 void event_set_fd_flags(struct fd_event *fde, uint16_t flags)
 {
+       if (!fde) return;
        fde->event_ctx->ops->set_fd_flags(fde, flags);
 }
 
@@ -138,10 +271,26 @@ struct timed_event *event_add_timed(struct event_context *ev, TALLOC_CTX *mem_ct
        return ev->ops->add_timed(ev, mem_ctx, next_event, handler, private_data);
 }
 
+/*
+  add a signal event
+
+  sa_flags are flags to sigaction(2)
+
+  return NULL on failure
+*/
+struct signal_event *event_add_signal(struct event_context *ev, TALLOC_CTX *mem_ctx,
+                                     int signum,
+                                     int sa_flags,
+                                     event_signal_handler_t handler, 
+                                     void *private_data)
+{
+       return ev->ops->add_signal(ev, mem_ctx, signum, sa_flags, handler, private_data);
+}
+
 /*
   do a single event loop using the events defined in ev 
 */
-int event_loop_once(struct event_context *ev)
+_PUBLIC_ int event_loop_once(struct event_context *ev)
 {
        return ev->ops->loop_once(ev);
 }
@@ -158,11 +307,15 @@ int event_loop_wait(struct event_context *ev)
   find an event context that is a parent of the given memory context,
   or create a new event context as a child of the given context if
   none is found
+
+  This should be used in preference to event_context_init() in places
+  where you would prefer to use the existing event context if possible
+  (which is most situations)
 */
 struct event_context *event_context_find(TALLOC_CTX *mem_ctx)
 {
        struct event_context *ev = talloc_find_parent_bytype(mem_ctx, struct event_context);
-       if (ev == NULL) {
+       if (ev == NULL) {               
                ev = event_context_init(mem_ctx);
        }
        return ev;