Update verto to 0.2.2 release
authorGreg Hudson <ghudson@mit.edu>
Tue, 15 Nov 2011 01:59:01 +0000 (01:59 +0000)
committerGreg Hudson <ghudson@mit.edu>
Tue, 15 Nov 2011 01:59:01 +0000 (01:59 +0000)
Update verto sources to 0.2.2 release versions.  verto_reinitialize()
now has a return value; check it in kdc/main.c.  Store verto-libev.c
alongside verto-k5ev.c to make it easy to diff corresponding versions
when updating.

ticket: 7018
target_version: 1.10
tags: pullup

git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@25474 dc483132-0cff-0310-8789-dd5450dbe970

src/kdc/main.c
src/util/k5ev/libverto-k5ev.exports
src/util/k5ev/verto-k5ev.c
src/util/k5ev/verto-libev.c [new file with mode: 0644]
src/util/verto/Makefile.in
src/util/verto/libverto.exports
src/util/verto/module.c [new file with mode: 0644]
src/util/verto/module.h [new file with mode: 0644]
src/util/verto/verto-module.h
src/util/verto/verto.c
src/util/verto/verto.h

index e7d6c6f536ed68d4e62a1bed68c76e52e2f7385e..8d4df8762401b4ddb726fbc25b00af86b06477d6 100644 (file)
@@ -572,7 +572,11 @@ create_workers(verto_ctx *ctx, int num)
     for (i = 0; i < num; i++) {
         pid = fork();
         if (pid == 0) {
-            verto_reinitialize(ctx);
+            if (!verto_reinitialize(ctx)) {
+                krb5_klog_syslog(LOG_ERR,
+                                 _("Unable to reinitialize main loop"));
+                return ENOMEM;
+            }
             retval = loop_setup_signals(ctx, NULL, reset_for_hangup);
             if (retval) {
                 krb5_klog_syslog(LOG_ERR, _("Unable to initialize signal "
index fe128fd47048a859162485eec6315b1a29f42a31..7907fbef707809b51519ec5dd30170072c670621 100644 (file)
@@ -1,3 +1,3 @@
 verto_default_k5ev
-verto_module_table
+verto_module_table_k5ev
 verto_new_k5ev
index 134192fac66bb6465ec984694ee02dd016e3dc43..d8155d4beec57a38d246bb59ccef091a98945c51 100644 (file)
  * SOFTWARE.
  */
 
-/* An edited version of verto's verto-libev.c, using an embedded libev with
- * renamed symbols. */
+/*
+ * An edited version of verto-libev.c, using an embedded libev with renamed
+ * symbols.  The corresponding version of verto-libev.c is stored in this
+ * directory for reference, although it is not built here.
+ */
 
 #include <stdlib.h>
 #include <string.h>
 #define EV_USE_SELECT 1
 #include "ev.c"
 
+static verto_mod_ctx *
+k5ev_ctx_new(void)
+{
+    return ev_loop_new(EVFLAG_AUTO);
+}
+
+static verto_mod_ctx *
+k5ev_ctx_default(void)
+{
+    return ev_default_loop(EVFLAG_AUTO);
+}
+
 static void
-k5ev_ctx_free(void *ctx)
+k5ev_ctx_free(verto_mod_ctx *ctx)
 {
     if (ctx != EV_DEFAULT)
         ev_loop_destroy(ctx);
 }
 
 static void
-k5ev_ctx_run(void *ctx)
+k5ev_ctx_run(verto_mod_ctx *ctx)
 {
     ev_run(ctx, 0);
 }
 
 static void
-k5ev_ctx_run_once(void *ctx)
+k5ev_ctx_run_once(verto_mod_ctx *ctx)
 {
     ev_run(ctx, EVRUN_ONCE);
 }
 
 static void
-k5ev_ctx_break(void *ctx)
+k5ev_ctx_break(verto_mod_ctx *ctx)
 {
     ev_break(ctx, EVBREAK_ONE);
 }
 
 static void
-k5ev_ctx_reinitialize(void *ctx)
+k5ev_ctx_reinitialize(verto_mod_ctx *ctx)
 {
     ev_loop_fork(ctx);
 }
@@ -84,26 +99,29 @@ libev_callback(EV_P_ ev_watcher *w, int revents)
     verto_fire(w->data);
 }
 
-#define setuptype(type, priv, ...) \
-    type ## w = malloc(sizeof(ev_ ## type)); \
-    if (!type ## w) \
-        return NULL; \
-    ev_ ## type ## _init(type ## w, (EV_CB(type, (*))) __VA_ARGS__); \
-    type ## w->data = (void *) priv; \
-    ev_ ## type ## _start(ctx, type ## w); \
-    return type ## w
-
-static void *
-k5ev_ctx_add(void *ctx, const verto_ev *ev, verto_ev_flag *flags)
+#define setuptype(type, ...) \
+    w.type = malloc(sizeof(ev_ ## type)); \
+    if (w.type) { \
+       ev_ ## type ## _init(w.type, (EV_CB(type, (*))) __VA_ARGS__); \
+       ev_ ## type ## _start(ctx, w.type); \
+    } \
+    break
+
+static verto_mod_ev *
+k5ev_ctx_add(verto_mod_ctx *ctx, const verto_ev *ev, verto_ev_flag *flags)
 {
-    ev_io *iow = NULL;
-    ev_timer *timerw = NULL;
-    ev_idle *idlew = NULL;
-    ev_signal *signalw = NULL;
-    ev_child *childw = NULL;
+    union {
+       ev_watcher *watcher;
+       ev_io *io;
+       ev_timer *timer;
+       ev_idle *idle;
+       ev_signal *signal;
+       ev_child *child;
+    } w;
     ev_tstamp interval;
     int events = EV_NONE;
 
+    w.watcher = NULL;
     *flags |= VERTO_EV_FLAG_PERSIST;
     switch (verto_get_type(ev)) {
         case VERTO_EV_TYPE_IO:
@@ -111,41 +129,45 @@ k5ev_ctx_add(void *ctx, const verto_ev *ev, verto_ev_flag *flags)
                 events |= EV_READ;
             if (verto_get_flags(ev) & VERTO_EV_FLAG_IO_WRITE)
                 events |= EV_WRITE;
-            setuptype(io, ev, libev_callback, verto_get_fd(ev), events);
+            setuptype(io, libev_callback, verto_get_fd(ev), events);
         case VERTO_EV_TYPE_TIMEOUT:
             interval = ((ev_tstamp) verto_get_interval(ev)) / 1000.0;
-            setuptype(timer, ev, libev_callback, interval, interval);
+            setuptype(timer, libev_callback, interval, interval);
         case VERTO_EV_TYPE_IDLE:
-            setuptype(idle, ev, libev_callback);
+            setuptype(idle, libev_callback);
         case VERTO_EV_TYPE_SIGNAL:
-            setuptype(signal, ev, libev_callback, verto_get_signal(ev));
+            setuptype(signal, libev_callback, verto_get_signal(ev));
         case VERTO_EV_TYPE_CHILD:
             *flags &= ~VERTO_EV_FLAG_PERSIST; /* Child events don't persist */
-            setuptype(child, ev, libev_callback, verto_get_proc(ev), 0);
+            setuptype(child, libev_callback, verto_get_proc(ev), 0);
         default:
-            return NULL; /* Not supported */
+            break; /* Not supported */
     }
+
+    if (w.watcher)
+        w.watcher->data = (void*) ev;
+    return w.watcher;
 }
 
 static void
-k5ev_ctx_del(void *ctx, const verto_ev *ev, void *evpriv)
+k5ev_ctx_del(verto_mod_ctx *ctx, const verto_ev *ev, verto_mod_ev *evpriv)
 {
     switch (verto_get_type(ev)) {
         case VERTO_EV_TYPE_IO:
-            ev_io_stop(ctx, evpriv);
-           break;
+            ev_io_stop(ctx, (ev_io*) evpriv);
+            break;
         case VERTO_EV_TYPE_TIMEOUT:
-            ev_timer_stop(ctx, evpriv);
-           break;
+            ev_timer_stop(ctx, (ev_timer*) evpriv);
+            break;
         case VERTO_EV_TYPE_IDLE:
-            ev_idle_stop(ctx, evpriv);
-           break;
+            ev_idle_stop(ctx, (ev_idle*) evpriv);
+            break;
         case VERTO_EV_TYPE_SIGNAL:
-            ev_signal_stop(ctx, evpriv);
-           break;
+            ev_signal_stop(ctx, (ev_signal*) evpriv);
+            break;
         case VERTO_EV_TYPE_CHILD:
-            ev_child_stop(ctx, evpriv);
-           break;
+            ev_child_stop(ctx, (ev_child*) evpriv);
+            break;
         default:
             break;
     }
@@ -153,8 +175,6 @@ k5ev_ctx_del(void *ctx, const verto_ev *ev, void *evpriv)
     free(evpriv);
 }
 
-static verto_ctx *verto_convert_k5ev(struct ev_loop* loop);
-
 VERTO_MODULE(k5ev, NULL,
              VERTO_EV_TYPE_IO |
              VERTO_EV_TYPE_TIMEOUT |
@@ -163,20 +183,7 @@ VERTO_MODULE(k5ev, NULL,
              VERTO_EV_TYPE_CHILD);
 
 verto_ctx *
-verto_new_k5ev(void)
-{
-    return verto_convert_k5ev(ev_loop_new(EVFLAG_AUTO));
-}
-
-verto_ctx *
-verto_default_k5ev(void)
-{
-    return verto_convert_k5ev(ev_default_loop(EVFLAG_AUTO));
-}
-
-/* Don't export this since our underlying libev is hidden. */
-static verto_ctx *
 verto_convert_k5ev(struct ev_loop* loop)
 {
-    return verto_convert(k5ev, loop);
+    return verto_convert(k5ev, 0, loop);
 }
diff --git a/src/util/k5ev/verto-libev.c b/src/util/k5ev/verto-libev.c
new file mode 100644 (file)
index 0000000..4e6e816
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * Copyright 2011 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <verto-libev.h>
+#define VERTO_MODULE_TYPES
+typedef struct ev_loop verto_mod_ctx;
+typedef ev_watcher verto_mod_ev;
+#include <verto-module.h>
+
+static verto_mod_ctx *
+libev_ctx_new(void)
+{
+    return ev_loop_new(EVFLAG_AUTO);
+}
+
+static verto_mod_ctx *
+libev_ctx_default(void)
+{
+    return ev_default_loop(EVFLAG_AUTO);
+}
+
+static void
+libev_ctx_free(verto_mod_ctx *ctx)
+{
+    if (ctx != EV_DEFAULT)
+        ev_loop_destroy(ctx);
+}
+
+static void
+libev_ctx_run(verto_mod_ctx *ctx)
+{
+    ev_run(ctx, 0);
+}
+
+static void
+libev_ctx_run_once(verto_mod_ctx *ctx)
+{
+    ev_run(ctx, EVRUN_ONCE);
+}
+
+static void
+libev_ctx_break(verto_mod_ctx *ctx)
+{
+    ev_break(ctx, EVBREAK_ONE);
+}
+
+static void
+libev_ctx_reinitialize(verto_mod_ctx *ctx)
+{
+    ev_loop_fork(ctx);
+}
+
+static void
+libev_callback(EV_P_ ev_watcher *w, int revents)
+{
+    if (verto_get_type(w->data) == VERTO_EV_TYPE_CHILD)
+        verto_set_proc_status(w->data, ((ev_child*) w)->rstatus);
+
+    verto_fire(w->data);
+}
+
+#define setuptype(type, ...) \
+    w.type = malloc(sizeof(ev_ ## type)); \
+    if (w.type) { \
+       ev_ ## type ## _init(w.type, (EV_CB(type, (*))) __VA_ARGS__); \
+       ev_ ## type ## _start(ctx, w.type); \
+    } \
+    break
+
+static verto_mod_ev *
+libev_ctx_add(verto_mod_ctx *ctx, const verto_ev *ev, verto_ev_flag *flags)
+{
+    union {
+       ev_watcher *watcher;
+       ev_io *io;
+       ev_timer *timer;
+       ev_idle *idle;
+       ev_signal *signal;
+       ev_child *child;
+    } w;
+    ev_tstamp interval;
+    int events = EV_NONE;
+
+    w.watcher = NULL;
+    *flags |= VERTO_EV_FLAG_PERSIST;
+    switch (verto_get_type(ev)) {
+        case VERTO_EV_TYPE_IO:
+            if (verto_get_flags(ev) & VERTO_EV_FLAG_IO_READ)
+                events |= EV_READ;
+            if (verto_get_flags(ev) & VERTO_EV_FLAG_IO_WRITE)
+                events |= EV_WRITE;
+            setuptype(io, libev_callback, verto_get_fd(ev), events);
+        case VERTO_EV_TYPE_TIMEOUT:
+            interval = ((ev_tstamp) verto_get_interval(ev)) / 1000.0;
+            setuptype(timer, libev_callback, interval, interval);
+        case VERTO_EV_TYPE_IDLE:
+            setuptype(idle, libev_callback);
+        case VERTO_EV_TYPE_SIGNAL:
+            setuptype(signal, libev_callback, verto_get_signal(ev));
+        case VERTO_EV_TYPE_CHILD:
+            *flags &= ~VERTO_EV_FLAG_PERSIST; /* Child events don't persist */
+            setuptype(child, libev_callback, verto_get_proc(ev), 0);
+        default:
+            break; /* Not supported */
+    }
+
+    if (w.watcher)
+        w.watcher->data = (void*) ev;
+    return w.watcher;
+}
+
+static void
+libev_ctx_del(verto_mod_ctx *ctx, const verto_ev *ev, verto_mod_ev *evpriv)
+{
+    switch (verto_get_type(ev)) {
+        case VERTO_EV_TYPE_IO:
+            ev_io_stop(ctx, (ev_io*) evpriv);
+            break;
+        case VERTO_EV_TYPE_TIMEOUT:
+            ev_timer_stop(ctx, (ev_timer*) evpriv);
+            break;
+        case VERTO_EV_TYPE_IDLE:
+            ev_idle_stop(ctx, (ev_idle*) evpriv);
+            break;
+        case VERTO_EV_TYPE_SIGNAL:
+            ev_signal_stop(ctx, (ev_signal*) evpriv);
+            break;
+        case VERTO_EV_TYPE_CHILD:
+            ev_child_stop(ctx, (ev_child*) evpriv);
+            break;
+        default:
+            break;
+    }
+
+    free(evpriv);
+}
+
+VERTO_MODULE(libev, ev_loop_new,
+             VERTO_EV_TYPE_IO |
+             VERTO_EV_TYPE_TIMEOUT |
+             VERTO_EV_TYPE_IDLE |
+             VERTO_EV_TYPE_SIGNAL |
+             VERTO_EV_TYPE_CHILD);
+
+verto_ctx *
+verto_convert_libev(struct ev_loop* loop)
+{
+    return verto_convert(libev, 0, loop);
+}
index 3e07227e24d220191d1f865243b39b7406e0a551..db6c387ce7bc25bdcc734ef123bd3eb5292c8755 100644 (file)
@@ -12,9 +12,9 @@ DEFINES=-DDEFAULT_LIBRARY=\"k5ev\"
 # Turn off extra warnings since we're not going to clean up libverto's code.
 WARN_CFLAGS=
 
-STLIBOBJS=verto.o
-LIBOBJS=$(OUTPRE)verto.$(OBJEXT)
-SRCS=verto.c
+STLIBOBJS=verto.o module.o
+LIBOBJS=$(OUTPRE)verto.$(OBJEXT) $(OUTPRE)module.$(OBJEXT)
+SRCS=verto.c module.c
 
 STOBJLISTS=OBJS.ST
 SHLIB_EXPLIBS= $(DL_LIB)
index 2f9b1ee2aee59bcbbf509d286a4bff565d2a5b4e..1e487744a32008f25e2f1dcaedb349d8bef4c8b0 100644 (file)
@@ -4,7 +4,7 @@ verto_add_io
 verto_add_signal
 verto_add_timeout
 verto_break
-verto_convert_funcs
+verto_convert_module
 verto_default
 verto_del
 verto_fire
diff --git a/src/util/verto/module.c b/src/util/verto/module.c
new file mode 100644 (file)
index 0000000..8b81646
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * Copyright 2011 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifdef WIN32
+#include <windows.h>
+#define dlltype HMODULE
+static char *
+dllerror(void) {
+    char *amsg;
+    LPTSTR msg;
+
+    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
+                      | FORMAT_MESSAGE_FROM_SYSTEM
+                      | FORMAT_MESSAGE_IGNORE_INSERTS,
+                  NULL, GetLastError(),
+                  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+                  (LPTSTR) &msg, 0, NULL);
+    amsg = strdup((const char*) msg);
+    LocalFree(msg);
+    return amsg;
+}
+#else
+#define _GNU_SOURCE
+#include <stdlib.h>
+#include <string.h>
+#include <dlfcn.h>
+#define dlltype void *
+#define dllerror() strdup(dlerror())
+#endif
+
+int
+module_symbol_is_present(const char *modname, const char *symbname)
+{
+#ifdef WIN32
+    return (GetProcAddress(GetModuleHandle(modname), symbname) != NULL ||
+            GetProcAddress(GetModuleHandle(NULL), symbname) != NULL);
+#else  /* WIN32 */
+    void* mod = dlopen(NULL, RTLD_LAZY | RTLD_LOCAL);
+    if (mod) {
+        void* sym = dlsym(mod, symbname);
+        dlclose(mod);
+        return sym != NULL;
+    }
+#endif /* WIN32 */
+    return 0;
+}
+
+int
+module_get_filename_for_symbol(void *addr, char **filename)
+{
+#ifdef WIN32
+    MEMORY_BASIC_INFORMATION info;
+    HMODULE mod;
+    char tmp[MAX_PATH];
+
+    if (!VirtualQuery(addr, &info, sizeof(info)))
+        return 0;
+    mod = (HMODULE) info.AllocationBase;
+
+    if (!GetModuleFileNameA(mod, tmp, MAX_PATH))
+        return 0;
+#else  /* WIN32 */
+    const char *tmp;
+    Dl_info dlinfo;
+
+    if (!dladdr(addr, &dlinfo))
+        return 0;
+    tmp = dlinfo.dli_fname;
+#endif /* WIN32 */
+
+    if (filename) {
+        *filename = strdup(tmp);
+        if (!*filename)
+            return 0;
+    }
+
+    return 1;
+}
+
+void
+module_close(void *dll)
+{
+    if (!dll)
+        return;
+
+#ifdef WIN32
+    FreeLibrary((dlltype) dll);
+#else  /* WIN32 */
+    dlclose((dlltype) dll);
+#endif /* WIN32 */
+}
+
+char *
+module_load(const char *filename, const char *symbname,
+            int (*shouldload)(void *symb, void *misc, char **err), void *misc,
+            void **dll, void **symb)
+{
+    dlltype intdll = NULL;
+    void *  intsym = NULL;
+    char *  interr = NULL;
+
+    if (dll)
+        *dll = NULL;
+    if (symb)
+        *symb = NULL;
+
+    /* Open the module library */
+#ifdef WIN32
+    /* NOTE: DONT_RESOLVE_DLL_REFERENCES is evil. Don't use this in your own
+     * code. However, our design pattern avoids all the issues surrounding a
+     * more general use of this evil flag. */
+    intdll = LoadLibraryEx(filename, NULL, DONT_RESOLVE_DLL_REFERENCES);
+#else  /* WIN32 */
+    intdll = dlopen(filename, RTLD_LAZY | RTLD_LOCAL);
+#endif /* WIN32 */
+    if (!intdll)
+        return dllerror();
+
+    /* Get the module symbol */
+#ifdef WIN32
+    intsym = (void *) GetProcAddress(intdll, symbname);
+#else /* WIN32 */
+    intsym = dlsym(intdll, symbname);
+#endif /* WIN32 */
+    if (!intsym) {
+        module_close(intdll);
+        return dllerror();
+    }
+
+    /* Figure out whether or not to load this module */
+    if (!shouldload(intsym, misc, &interr)) {
+        module_close(intdll);
+        return interr;
+    }
+
+    /* Re-open the module */
+    module_close(intdll);
+#ifdef WIN32
+    intdll = LoadLibrary(filename);
+#else  /* WIN32 */
+    intdll = dlopen(filename, RTLD_NOW | RTLD_LOCAL);
+#endif /* WIN32 */
+    if (!intdll) {
+        return dllerror();
+    }
+
+    /* Get the symbol again */
+#ifdef WIN32
+    intsym = (void *) GetProcAddress(intdll, symbname);
+#else /* WIN32 */
+    intsym = dlsym(intdll, symbname);
+#endif /* WIN32 */
+    if (!intsym) {
+        module_close(intdll);
+        return dllerror();
+    }
+
+    if (dll)
+        *dll = intdll;
+    if (symb)
+        *symb = intsym;
+    return NULL;
+}
diff --git a/src/util/verto/module.h b/src/util/verto/module.h
new file mode 100644 (file)
index 0000000..38c431d
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2011 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* Determines if a symbol is present in a given module.
+ *
+ * @param modname The name of the module.
+ * @param symbname The name of the symbol.
+ * @return Non-zero if found, zero if not found.
+ */
+int
+module_symbol_is_present(const char *modname, const char *symbname);
+
+/* Finds the file for a given symbol.
+ *
+ * If filename is non-null, the name of the file will be stored. This must
+ * be freed with free().
+ *
+ * @param addr The address to resolve.
+ * @param filename Where to store the name of the file.
+ * @return 0 on error, non-zero on success.
+ */
+int
+module_get_filename_for_symbol(void *addr, char **filename);
+
+/* Closes a module.
+ *
+ * Does nothing if dll is NULL.
+ *
+ * @param dll The module to close.
+ */
+void
+module_close(void *dll);
+
+
+/* Loads a module and extracts the given symbol.
+ *
+ * This function loads the module specified by filename, but does not resolve
+ * any of its symbol dependencies. Next is gets the symbol symbname and calls
+ * shouldload(). If shouldload() returns non-zero, the module is reloaded
+ * with full symbol resolution and stores the results in dll and symb.
+ *
+ * The job of shouldload() is to determine, based on the metadata in the
+ * symbol fetched, if the module should be fully loaded. The shouldload()
+ * callback MUST NOT attempt to call any functions in the module. This will
+ * crash on WIN32.
+ *
+ * If an error occurs, an error string will be allocated and returned. If
+ * allocation of this string fails, NULL will be returned. Since this is the
+ * same as the non-error case, you should additionally check if dll or symb
+ * is NULL.
+ *
+ * @param filename Path to the module
+ * @param symbname Symbol name to load from the file and pass to shouldload()
+ * @param shouldload Callback to determine whether to fullly load the module
+ * @param misc Opaque pointer to pass to shouldload()
+ * @param dll Where the module will be stored (can be NULL)
+ * @param symb Where the symbol will be stored (can be NULL)
+ * @return An error string.
+ */
+char *
+module_load(const char *filename, const char *symbname,
+            int (*shouldload)(void *symb, void *misc, char **err), void *misc,
+            void **dll, void **symb);
index 05a920f9e3734bcc935d397fc34e7a84a0e8c206..b0e7232b1eaa15d4cdcc9a2081c385284700d1f4 100644 (file)
 
 #include <verto.h>
 
-#define VERTO_MODULE_VERSION 1
-#define VERTO_MODULE_TABLE verto_module_table
+#ifndef VERTO_MODULE_TYPES
+#define VERTO_MODULE_TYPES
+typedef void verto_mod_ctx;
+typedef void verto_mod_ev;
+#endif
+
+#define VERTO_MODULE_VERSION 2
+#define VERTO_MODULE_TABLE(name) verto_module_table_ ## name
 #define VERTO_MODULE(name, symb, types) \
     static verto_ctx_funcs name ## _funcs = { \
+        name ## _ctx_new, \
+        name ## _ctx_default, \
         name ## _ctx_free, \
         name ## _ctx_run, \
         name ## _ctx_run_once, \
         name ## _ctx_add, \
         name ## _ctx_del \
     }; \
-    verto_module VERTO_MODULE_TABLE = { \
+    verto_module VERTO_MODULE_TABLE(name) = { \
         VERTO_MODULE_VERSION, \
         # name, \
         # symb, \
         types, \
-        verto_new_ ## name, \
-        verto_default_ ## name, \
-    };
+        &name ## _funcs, \
+    }; \
+    verto_ctx * \
+    verto_new_ ## name() \
+    { \
+        return verto_convert(name, 0, NULL); \
+    } \
+    verto_ctx * \
+    verto_default_ ## name() \
+    { \
+        return verto_convert(name, 1, NULL); \
+    }
 
-typedef verto_ctx *(*verto_ctx_constructor)();
+typedef struct {
+    /* Required */ verto_mod_ctx *(*ctx_new)();
+    /* Optional */ verto_mod_ctx *(*ctx_default)();
+    /* Required */ void (*ctx_free)(verto_mod_ctx *ctx);
+    /* Optional */ void (*ctx_run)(verto_mod_ctx *ctx);
+    /* Required */ void (*ctx_run_once)(verto_mod_ctx *ctx);
+    /* Optional */ void (*ctx_break)(verto_mod_ctx *ctx);
+    /* Optional */ void (*ctx_reinitialize)(verto_mod_ctx *ctx);
+    /* Required */ verto_mod_ev *(*ctx_add)(verto_mod_ctx *ctx,
+                                            const verto_ev *ev,
+                                            verto_ev_flag *flags);
+    /* Required */ void (*ctx_del)(verto_mod_ctx *ctx,
+                                   const verto_ev *ev,
+                                   verto_mod_ev *modev);
+} verto_ctx_funcs;
 
 typedef struct {
     unsigned int vers;
     const char *name;
     const char *symb;
     verto_ev_type types;
-    verto_ctx_constructor new_ctx;
-    verto_ctx_constructor def_ctx;
+    verto_ctx_funcs *funcs;
 } verto_module;
 
-typedef struct {
-    void  (*ctx_free)(void *ctx);
-    void  (*ctx_run)(void *ctx);
-    void  (*ctx_run_once)(void *ctx);
-    void  (*ctx_break)(void *ctx);
-    void  (*ctx_reinitialize)(void *ctx);
-    void *(*ctx_add)(void *ctx, const verto_ev *ev, verto_ev_flag *flags);
-    void  (*ctx_del)(void *ctx, const verto_ev *ev, void *evpriv);
-} verto_ctx_funcs;
-
 /**
  * Converts an existing implementation specific loop to a verto_ctx.
  *
  * This function also sets the internal default implementation so that future
  * calls to verto_new(NULL) or verto_default(NULL) will use this specific
- * implementation.
+ * implementation if it was not already set.
  *
  * @param name The name of the module (unquoted)
- * @param priv The context private to store
- * @return A new _ev_ctx, or NULL on error. Call verto_free() when done.
+ * @param deflt Whether the ctx is the default context or not
+ * @param ctx The context to store
+ * @return A new verto_ctx, or NULL on error. Call verto_free() when done.
  */
-#define verto_convert(name, priv) \
-        verto_convert_funcs(&name ## _funcs, &VERTO_MODULE_TABLE, priv)
+#define verto_convert(name, deflt, ctx) \
+        verto_convert_module(&VERTO_MODULE_TABLE(name), deflt, ctx)
 
 /**
  * Converts an existing implementation specific loop to a verto_ctx.
  *
- * This function also sets the internal default implementation so that future
- * calls to verto_new(NULL) or verto_default(NULL) will use this specific
- * implementation.
- *
  * If you are a module implementation, you probably want the macro above.  This
  * function is generally used directly only when an application is attempting
  * to expose a home-grown event loop to verto.
  *
+ * If deflt is non-zero and a default ctx was already defined for this module
+ * and ctx is not NULL, than ctx will be free'd and the previously defined
+ * default will be returned.
+ *
+ * If ctx is non-NULL, than the pre-existing verto_mod_ctx will be converted to
+ * to a verto_ctx; if deflt is non-zero than this verto_mod_ctx will also be
+ * marked as the default loop for this process. If ctx is NULL, than the
+ * appropriate constructor will be called: either module->ctx_new() or
+ * module->ctx_default() depending on the boolean value of deflt. If
+ * module->ctx_default is NULL and deflt is non-zero, than module->ctx_new()
+ * will be called and the resulting verto_mod_ctx will be utilized as the
+ * default.
+ *
+ * This function also sets the internal default implementation so that future
+ * calls to verto_new(NULL) or verto_default(NULL) will use this specific
+ * implementation if it was not already set.
+ *
  * @param name The name of the module (unquoted)
- * @param priv The context private to store
- * @return A new _ev_ctx, or NULL on error. Call verto_free() when done.
+ * @param ctx The context private to store
+ * @return A new verto_ctx, or NULL on error. Call verto_free() when done.
  */
 verto_ctx *
-verto_convert_funcs(const verto_ctx_funcs *funcs,
-                    const verto_module *module,
-                    void *priv);
+verto_convert_module(const verto_module *module, int deflt, verto_mod_ctx *ctx);
 
 /**
  * Calls the callback of the verto_ev and then frees it via verto_del().
index 34d453c7027e039793abf61c3b572820fc025ad3..af4172687dd6f12731f396eb407e0e69c4d14511 100644 (file)
 #include <sys/types.h>
 #include <dirent.h>
 
-#ifdef WIN32
-#include <windows.h>
-#else
-#include <dlfcn.h>
+#ifdef HAVE_PTHREAD
+#include <pthread.h>
 #endif
 
 #include <verto-module.h>
-
-#ifdef WIN32
-#define pdlmtype HMODULE
-#define pdlopenl(filename) LoadLibraryEx(filename, NULL, \
-                                         DONT_RESOLVE_DLL_REFERENCES)
-#define pdlclose(module) FreeLibrary((pdlmtype) module)
-#define pdlsym(mod, sym) ((void *) GetProcAddress(mod, sym))
-
-static pdlmtype
-pdlreopen(const char *filename, pdlmtype module)
-{
-    pdlclose(module);
-    return LoadLibrary(filename);
-}
-
-static char *
-pdlerror(void) {
-    char *amsg;
-    LPTSTR msg;
-
-    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
-                      | FORMAT_MESSAGE_FROM_SYSTEM
-                      | FORMAT_MESSAGE_IGNORE_INSERTS,
-                  NULL, GetLastError(),
-                  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
-                  (LPTSTR) &msg, 0, NULL);
-    amsg = strdup((const char*) msg);
-    LocalFree(msg);
-    return amsg;
-}
-
-static bool
-pdlsymlinked(const char *modn, const char *symb) {
-    return (GetProcAddress(GetModuleHandle(modn), symb) != NULL ||
-            GetProcAddress(GetModuleHandle(NULL), symb) != NULL);
-}
-
-static bool
-pdladdrmodname(void *addr, char **buf) {
-    MEMORY_BASIC_INFORMATION info;
-    HMODULE mod;
-    char modname[MAX_PATH];
-
-    if (!VirtualQuery(addr, &info, sizeof(info)))
-        return false;
-    mod = (HMODULE) info.AllocationBase;
-
-    if (!GetModuleFileNameA(mod, modname, MAX_PATH))
-        return false;
-
-    if (buf) {
-        *buf = strdup(modname);
-        if (!buf)
-            return false;
-    }
-
-    return true;
-}
-#else
-#define pdlmtype void *
-#define pdlopenl(filename) dlopen(filename, RTLD_LAZY | RTLD_LOCAL)
-#define pdlclose(module) dlclose((pdlmtype) module)
-#define pdlreopen(filename, module) module
-#define pdlsym(mod, sym) dlsym(mod, sym)
-#define pdlerror() strdup(dlerror())
-
-static int
-pdlsymlinked(const char* modn, const char* symb)
-{
-    void* mod = dlopen(NULL, RTLD_LAZY | RTLD_LOCAL);
-    if (mod) {
-        void* sym = dlsym(mod, symb);
-        dlclose(mod);
-        return sym != NULL;
-    }
-    return 0;
-}
-
-static int
-pdladdrmodname(void *addr, char **buf) {
-    Dl_info dlinfo;
-    if (!dladdr(addr, &dlinfo))
-        return 0;
-    if (buf) {
-        *buf = strdup(dlinfo.dli_fname);
-        if (!*buf)
-            return 0;
-    }
-    return 1;
-}
-#endif
-
-#ifndef NSIG
-#ifdef _NSIG
-#define NSIG _NSIG
-#else
-#define NSIG SIGRTMIN
-#endif
-#endif
+#include "module.h"
 
 #define  _str(s) # s
 #define __str(s) _str(s)
-#define vnew(type) ((type*) malloc(sizeof(type)))
-#define vnew0(type) ((type*) memset(vnew(type), 0, sizeof(type)))
 
-struct _verto_ctx {
-    void *dll;
-    void *modpriv;
-    verto_ev_type types;
-    verto_ctx_funcs funcs;
+struct verto_ctx {
+    size_t ref;
+    verto_mod_ctx *ctx;
+    const verto_module *module;
     verto_ev *events;
+    int deflt;
+    int exit;
 };
 
 typedef struct {
@@ -160,14 +59,14 @@ typedef struct {
     verto_proc_status status;
 } verto_child;
 
-struct _verto_ev {
+struct verto_ev {
     verto_ev *next;
     verto_ctx *ctx;
     verto_ev_type type;
     verto_callback *callback;
     verto_callback *onfree;
     void *priv;
-    void *modpriv;
+    verto_mod_ev *ev;
     verto_ev_flag flags;
     verto_ev_flag actual;
     size_t depth;
@@ -180,7 +79,24 @@ struct _verto_ev {
     } option;
 };
 
-const verto_module *defmodule;
+typedef struct module_record module_record;
+struct module_record {
+    module_record *next;
+    const verto_module *module;
+    void *dll;
+    char *filename;
+    verto_ctx *defctx;
+};
+
+static module_record *loaded_modules;
+#ifdef HAVE_PTHREAD
+static pthread_mutex_t loaded_modules_mutex = PTHREAD_MUTEX_INITIALIZER;
+#define mutex_lock(x) pthread_mutex_lock(x)
+#define mutex_unlock(x) pthread_mutex_unlock(x)
+#else
+#define mutex_lock(x)
+#define mutex_unlock(x)
+#endif
 
 static int
 int_vasprintf(char **strp, const char *fmt, va_list ap) {
@@ -208,55 +124,160 @@ int_asprintf(char **strp, const char *fmt, ...) {
     return size;
 }
 
+static char *
+int_get_table_name(const char *suffix)
+{
+    char *tmp;
+
+    tmp = malloc(strlen(suffix) + strlen(__str(VERTO_MODULE_TABLE())) + 1);
+    if (tmp) {
+        strcpy(tmp, __str(VERTO_MODULE_TABLE()));
+        strcat(tmp, suffix);
+    }
+    return tmp;
+}
+
+static char *
+int_get_table_name_from_filename(const char *filename)
+{
+    char *bn = NULL, *tmp = NULL;
+
+    if (!filename)
+        return NULL;
+
+    tmp = strdup(filename);
+    if (!tmp)
+        return NULL;
+
+    bn = basename(tmp);
+    if (bn)
+        bn = strdup(bn);
+    free(tmp);
+    if (!bn)
+        return NULL;
+
+    tmp = strchr(bn, '-');
+    if (tmp) {
+        if (strchr(tmp+1, '.')) {
+            *strchr(tmp+1, '.') = '\0';
+            tmp = int_get_table_name(tmp + 1);
+        } else
+            tmp = NULL;
+    }
+
+    free(bn);
+    return tmp;
+}
+
+typedef struct {
+    int reqsym;
+    verto_ev_type reqtypes;
+} shouldload_data;
+
 static int
-do_load_file(const char *filename, int reqsym, verto_ev_type reqtypes,
-             pdlmtype *dll, const verto_module **module)
+shouldload(void *symb, void *misc, char **err)
 {
-    *dll = pdlopenl(filename);
-    if (!*dll) {
-        /* printf("%s -- %s\n", filename, pdlerror()); */
+    verto_module *table = (verto_module*) symb;
+    shouldload_data *data = (shouldload_data*) misc;
+
+    /* Make sure we have the proper version */
+    if (table->vers != VERTO_MODULE_VERSION) {
+        if (err)
+            *err = strdup("Invalid module version!");
         return 0;
     }
 
-    *module = (verto_module*) pdlsym(*dll, __str(VERTO_MODULE_TABLE));
-    if (!*module || (*module)->vers != VERTO_MODULE_VERSION
-            || !(*module)->new_ctx || !(*module)->def_ctx)
-        goto error;
-
     /* Check to make sure that we have our required symbol if reqsym == true */
-    if ((*module)->symb && reqsym && !pdlsymlinked(NULL, (*module)->symb))
-        goto error;
+    if (table->symb && data->reqsym
+            && !module_symbol_is_present(NULL, table->symb)) {
+        if (err)
+            int_asprintf(err, "Symbol not found: %s!", table->symb);
+        return 0;
+    }
 
     /* Check to make sure that this module supports our required features */
-    if (reqtypes != VERTO_EV_TYPE_NONE && ((*module)->types & reqtypes) != reqtypes)
-        goto error;
-
-    /* Re-open in execution mode */
-    *dll = pdlreopen(filename, *dll);
-    if (!*dll)
+    if (data->reqtypes != VERTO_EV_TYPE_NONE
+            && (table->types & data->reqtypes) != data->reqtypes) {
+        if (err)
+            *err = strdup("Module does not support required features!");
         return 0;
-
-    /* Get the module struct again */
-    *module = (verto_module*) pdlsym(*dll, __str(VERTO_MODULE_TABLE));
-    if (!*module)
-        goto error;
+    }
 
     return 1;
+}
+
+static int
+do_load_file(const char *filename, int reqsym, verto_ev_type reqtypes,
+             module_record **record)
+{
+    char *tblname = NULL, *error = NULL;
+    module_record *tmp;
+    shouldload_data data  = { reqsym, reqtypes };
+
+    /* Check the loaded modules to see if we already loaded one */
+    mutex_lock(&loaded_modules_mutex);
+    for (*record = loaded_modules ; *record ; *record = (*record)->next) {
+        if (!strcmp((*record)->filename, filename)) {
+            mutex_unlock(&loaded_modules_mutex);
+            return 1;
+        }
+    }
+    mutex_unlock(&loaded_modules_mutex);
 
-    error:
-        pdlclose(*dll);
+    /* Create our module record */
+    tmp = *record = malloc(sizeof(module_record));
+    if (!tmp)
+        return 0;
+    memset(tmp, 0, sizeof(module_record));
+    tmp->filename = strdup(filename);
+    if (!tmp->filename) {
+        free(tmp);
         return 0;
+    }
+
+    /* Get the name of the module struct in the library */
+    tblname = int_get_table_name_from_filename(filename);
+    if (!tblname) {
+        free(tblname);
+        free(tmp);
+        return 0;
+    }
+
+    /* Load the module */
+    error = module_load(filename, tblname, shouldload, &data, &tmp->dll,
+                        (void **) &tmp->module);
+    if (error || !tmp->dll || !tmp->module) {
+        /*if (error)
+            fprintf(stderr, "%s\n", error);*/
+        free(error);
+        module_close(tmp->dll);
+        free(tblname);
+        free(tmp);
+        return 0;
+    }
+
+    /* Append the new module to the end of the loaded modules */
+    mutex_lock(&loaded_modules_mutex);
+    for (tmp = loaded_modules ; tmp && tmp->next; tmp = tmp->next)
+        continue;
+    if (tmp)
+        tmp->next = *record;
+    else
+        loaded_modules = *record;
+    mutex_unlock(&loaded_modules_mutex);
+
+    free(tblname);
+    return 1;
 }
 
 static int
 do_load_dir(const char *dirname, const char *prefix, const char *suffix,
-            int reqsym, verto_ev_type reqtypes, pdlmtype *dll,
-            const verto_module **module)
+            int reqsym, verto_ev_type reqtypes, module_record **record)
 {
     DIR *dir;
     struct dirent *ent = NULL;
 
-    *module = NULL;
+    *record = NULL;
     dir = opendir(dirname);
     if (!dir)
         return 0;
@@ -280,27 +301,47 @@ do_load_dir(const char *dirname, const char *prefix, const char *suffix,
         if (int_asprintf(&tmp, "%s/%s", dirname, ent->d_name) < 0)
             continue;
 
-        success = do_load_file(tmp, reqsym, reqtypes, dll, module);
+        success = do_load_file(tmp, reqsym, reqtypes, record);
         free(tmp);
         if (success)
             break;
-        *module = NULL;
+        *record = NULL;
     }
 
     closedir(dir);
-    return *module != NULL;
+    return *record != NULL;
 }
 
 static int
-load_module(const char *impl, verto_ev_type reqtypes, pdlmtype *dll,
-            const verto_module **module)
+load_module(const char *impl, verto_ev_type reqtypes, module_record **record)
 {
     int success = 0;
     char *prefix = NULL;
     char *suffix = NULL;
     char *tmp = NULL;
 
-    if (!pdladdrmodname(verto_convert_funcs, &prefix))
+    /* Check the cache */
+    mutex_lock(&loaded_modules_mutex);
+    if (impl) {
+        for (*record = loaded_modules ; *record ; *record = (*record)->next) {
+            if ((strchr(impl, '/') && !strcmp(impl, (*record)->filename))
+                    || !strcmp(impl, (*record)->module->name)) {
+                mutex_unlock(&loaded_modules_mutex);
+                return 1;
+            }
+        }
+    } else if (loaded_modules) {
+        for (*record = loaded_modules ; *record ; *record = (*record)->next) {
+            if (reqtypes == VERTO_EV_TYPE_NONE
+                    || ((*record)->module->types & reqtypes) == reqtypes) {
+                mutex_unlock(&loaded_modules_mutex);
+                return 1;
+            }
+        }
+    }
+    mutex_unlock(&loaded_modules_mutex);
+
+    if (!module_get_filename_for_symbol(verto_convert_module, &prefix))
         return 0;
 
     /* Example output:
@@ -326,56 +367,45 @@ load_module(const char *impl, verto_ev_type reqtypes, pdlmtype *dll,
 
     if (impl) {
         /* Try to do a load by the path */
-        if (strchr(impl, '/'))
-            success = do_load_file(impl, 0, reqtypes, dll, module);
+        if (!success && strchr(impl, '/'))
+            success = do_load_file(impl, 0, reqtypes, record);
         if (!success) {
             /* Try to do a load by the name */
             tmp = NULL;
             if (int_asprintf(&tmp, "%s%s%s", prefix, impl, suffix) > 0) {
-                success = do_load_file(tmp, 0, reqtypes, dll, module);
+                success = do_load_file(tmp, 0, reqtypes, record);
                 free(tmp);
             }
         }
     } else {
-        /* First, try the default implementation (aka 'the cache')*/
-        *dll = NULL;
-        *module = NULL;
-
-        if (defmodule != NULL
-                && (reqtypes == VERTO_EV_TYPE_NONE
-                        || (defmodule->types & reqtypes) == reqtypes))
-            *module = defmodule;
-
-        if (!(success = *module != NULL)) {
-            /* NULL was passed, so we will use the dirname of
-             * the prefix to try and find any possible plugins */
-            tmp = strdup(prefix);
-            if (tmp) {
-                char *dname = strdup(dirname(tmp));
-                free(tmp);
-
-                tmp = strdup(basename(prefix));
-                free(prefix);
-                prefix = tmp;
-
-                if (dname && prefix) {
-                    /* Attempt to find a module we are already linked to */
-                    success = do_load_dir(dname, prefix, suffix, 1, reqtypes,
-                                          dll, module);
-                    if (!success) {
+        /* NULL was passed, so we will use the dirname of
+         * the prefix to try and find any possible plugins */
+        tmp = strdup(prefix);
+        if (tmp) {
+            char *dname = strdup(dirname(tmp));
+            free(tmp);
+
+            tmp = strdup(basename(prefix));
+            free(prefix);
+            prefix = tmp;
+
+            if (dname && prefix) {
+                /* Attempt to find a module we are already linked to */
+                success = do_load_dir(dname, prefix, suffix, 1, reqtypes,
+                                      record);
+                if (!success) {
 #ifdef DEFAULT_LIBRARY
-                        /* Attempt to find the default module */
-                        success = load_module(DEFAULT_LIBRARY, reqtypes, dll, module);
-                        if (!success)
+                    /* Attempt to find the default module */
+                    success = load_module(DEFAULT_LIBRARY, reqtypes, record);
+                    if (!success)
 #endif /* DEFAULT_LIBRARY */
-                        /* Attempt to load any plugin (we're desperate) */
-                        success = do_load_dir(dname, prefix, suffix, 0,
-                                              reqtypes, dll, module);
-                    }
+                    /* Attempt to load any plugin (we're desperate) */
+                    success = do_load_dir(dname, prefix, suffix, 0,
+                                          reqtypes, record);
                 }
-
-                free(dname);
             }
+
+            free(dname);
         }
     }
 
@@ -438,99 +468,57 @@ signal_ignore(verto_ctx *ctx, verto_ev *ev)
 verto_ctx *
 verto_new(const char *impl, verto_ev_type reqtypes)
 {
-    pdlmtype dll = NULL;
-    const verto_module *module = NULL;
-    verto_ctx *ctx = NULL;
+    module_record *mr = NULL;
 
-    if (!load_module(impl, reqtypes, &dll, &module))
+    if (!load_module(impl, reqtypes, &mr))
         return NULL;
 
-    ctx = module->new_ctx();
-    if (!ctx && dll)
-        pdlclose(dll);
-    if (ctx && defmodule != module)
-        ctx->dll = dll;
-
-    return ctx;
+    return verto_convert_module(mr->module, 0, NULL);
 }
 
 verto_ctx *
 verto_default(const char *impl, verto_ev_type reqtypes)
 {
-    pdlmtype dll = NULL;
-    const verto_module *module = NULL;
-    verto_ctx *ctx = NULL;
+    module_record *mr = NULL;
 
-    if (!load_module(impl, reqtypes, &dll, &module))
+    if (!load_module(impl, reqtypes, &mr))
         return NULL;
 
-    ctx = module->def_ctx();
-    if (!ctx && dll)
-        pdlclose(dll);
-    if (ctx && defmodule != module)
-        ctx->dll = dll;
-
-    return ctx;
+    return verto_convert_module(mr->module, 1, NULL);
 }
 
 int
 verto_set_default(const char *impl, verto_ev_type reqtypes)
 {
-    pdlmtype dll = NULL; /* we will leak the dll */
-    return (!defmodule && impl && load_module(impl, reqtypes, &dll, &defmodule));
+    module_record *mr;
+
+    mutex_lock(&loaded_modules_mutex);
+    if (loaded_modules || !impl) {
+        mutex_unlock(&loaded_modules_mutex);
+        return 0;
+    }
+    mutex_unlock(&loaded_modules_mutex);
+
+    return load_module(impl, reqtypes, &mr);
 }
 
 void
 verto_free(verto_ctx *ctx)
 {
-#ifndef WIN32
-    int i;
-    sigset_t old;
-    sigset_t block;
-    struct sigaction act;
-#endif
-
     if (!ctx)
         return;
 
+    ctx->ref = ctx->ref > 0 ? ctx->ref - 1 : 0;
+    if (ctx->ref > 0)
+        return;
+
     /* Cancel all pending events */
     while (ctx->events)
         verto_del(ctx->events);
 
     /* Free the private */
-    ctx->funcs.ctx_free(ctx->modpriv);
-
-    /* Unload the module */
-    if (ctx->dll) {
-        /* If dlclose() unmaps memory that is registered as a signal handler
-         * we have to remove that handler otherwise if that signal is fired
-         * we jump into unmapped memory. So we loop through and test each
-         * handler to see if it is in unmapped memory.  If it is, we set it
-         * back to the default handler. Lastly, if a signal were to fire it
-         * could be a race condition. So we mask out all signals during this
-         * process.
-         */
-#ifndef WIN32
-        sigfillset(&block);
-        sigprocmask(SIG_SETMASK, &block, &old);
-#endif
-        pdlclose(ctx->dll);
-#ifndef WIN32
-        for (i=1 ; i < NSIG ; i++) {
-            if (sigaction(i, NULL, &act) == 0) {
-                if (act.sa_flags & SA_SIGINFO) {
-                    if (!pdladdrmodname(act.sa_sigaction, NULL))
-                        signal(i, SIG_DFL);
-                } else if (act.sa_handler != SIG_DFL
-                        && act.sa_handler != SIG_IGN) {
-                    if (!pdladdrmodname(act.sa_handler, NULL))
-                        signal(i, SIG_DFL);
-                }
-            }
-        }
-        sigprocmask(SIG_SETMASK, &old, NULL);
-#endif
-    }
+    if (!ctx->deflt || !ctx->module->funcs->ctx_default)
+        ctx->module->funcs->ctx_free(ctx->ctx);
 
     free(ctx);
 }
@@ -540,7 +528,14 @@ verto_run(verto_ctx *ctx)
 {
     if (!ctx)
         return;
-    ctx->funcs.ctx_run(ctx->modpriv);
+
+    if (ctx->module->funcs->ctx_break && ctx->module->funcs->ctx_run)
+        ctx->module->funcs->ctx_run(ctx->ctx);
+    else {
+        while (!ctx->exit)
+            ctx->module->funcs->ctx_run_once(ctx->ctx);
+        ctx->exit = 0;
+    }
 }
 
 void
@@ -548,7 +543,7 @@ verto_run_once(verto_ctx *ctx)
 {
     if (!ctx)
         return;
-    ctx->funcs.ctx_run_once(ctx->modpriv);
+    ctx->module->funcs->ctx_run_once(ctx->ctx);
 }
 
 void
@@ -556,35 +551,45 @@ verto_break(verto_ctx *ctx)
 {
     if (!ctx)
         return;
-    ctx->funcs.ctx_break(ctx->modpriv);
+
+    if (ctx->module->funcs->ctx_break && ctx->module->funcs->ctx_run)
+        ctx->module->funcs->ctx_break(ctx->ctx);
+    else
+        ctx->exit = 1;
 }
 
-void
+int
 verto_reinitialize(verto_ctx *ctx)
 {
     verto_ev *tmp, *next;
+    int error = 1;
+
     if (!ctx)
-        return;
+        return 0;
 
     /* Delete all events, but keep around the forkable ev structs */
     for (tmp = ctx->events; tmp; tmp = next) {
         next = tmp->next;
 
         if (tmp->flags & VERTO_EV_FLAG_REINITIABLE)
-            ctx->funcs.ctx_del(ctx->modpriv, tmp, tmp->modpriv);
+            ctx->module->funcs->ctx_del(ctx->ctx, tmp, tmp->ev);
         else
             verto_del(tmp);
     }
 
     /* Reinit the loop */
-    ctx->funcs.ctx_reinitialize(ctx->modpriv);
+    if (ctx->module->funcs->ctx_reinitialize)
+        ctx->module->funcs->ctx_reinitialize(ctx->ctx);
 
     /* Recreate events that were marked forkable */
     for (tmp = ctx->events; tmp; tmp = tmp->next) {
         tmp->actual = tmp->flags;
-        tmp->modpriv = ctx->funcs.ctx_add(ctx->modpriv, tmp, &tmp->actual);
-        assert(tmp->modpriv);
+        tmp->ev = ctx->module->funcs->ctx_add(ctx->ctx, tmp, &tmp->actual);
+        if (!tmp->ev)
+            error = 0;
     }
+
+    return error;
 }
 
 #define doadd(ev, set, type) \
@@ -592,14 +597,13 @@ verto_reinitialize(verto_ctx *ctx)
     if (ev) { \
         set; \
         ev->actual = ev->flags; \
-        ev->modpriv = ctx->funcs.ctx_add(ctx->modpriv, ev, &ev->actual); \
-        if (!ev->modpriv) { \
+        ev->ev = ctx->module->funcs->ctx_add(ctx->ctx, ev, &ev->actual); \
+        if (!ev->ev) { \
             free(ev); \
             return NULL; \
         } \
         push_ev(ctx, ev); \
-    } \
-    return ev;
+    }
 
 verto_ev *
 verto_add_io(verto_ctx *ctx, verto_ev_flag flags,
@@ -611,6 +615,7 @@ verto_add_io(verto_ctx *ctx, verto_ev_flag flags,
         return NULL;
 
     doadd(ev, ev->option.fd = fd, VERTO_EV_TYPE_IO);
+    return ev;
 }
 
 verto_ev *
@@ -619,6 +624,7 @@ verto_add_timeout(verto_ctx *ctx, verto_ev_flag flags,
 {
     verto_ev *ev;
     doadd(ev, ev->option.interval = interval, VERTO_EV_TYPE_TIMEOUT);
+    return ev;
 }
 
 verto_ev *
@@ -627,6 +633,7 @@ verto_add_idle(verto_ctx *ctx, verto_ev_flag flags,
 {
     verto_ev *ev;
     doadd(ev,, VERTO_EV_TYPE_IDLE);
+    return ev;
 }
 
 verto_ev *
@@ -647,6 +654,7 @@ verto_add_signal(verto_ctx *ctx, verto_ev_flag flags,
             return NULL;
     }
     doadd(ev, ev->option.signal = signal, VERTO_EV_TYPE_SIGNAL);
+    return ev;
 }
 
 verto_ev *
@@ -664,6 +672,7 @@ verto_add_child(verto_ctx *ctx, verto_ev_flag flags,
 #endif
         return NULL;
     doadd(ev, ev->option.child.proc = proc, VERTO_EV_TYPE_CHILD);
+    return ev;
 }
 
 void
@@ -749,7 +758,7 @@ verto_del(verto_ev *ev)
 
     if (ev->onfree)
         ev->onfree(ev->ctx, ev);
-    ev->ctx->funcs.ctx_del(ev->ctx->modpriv, ev, ev->modpriv);
+    ev->ctx->module->funcs->ctx_del(ev->ctx->ctx, ev, ev->ev);
     remove_ev(&(ev->ctx->events), ev);
     free(ev);
 }
@@ -757,33 +766,93 @@ verto_del(verto_ev *ev)
 verto_ev_type
 verto_get_supported_types(verto_ctx *ctx)
 {
-    return ctx->types;
+    return ctx->module->types;
 }
 
 /*** THE FOLLOWING ARE FOR IMPLEMENTATION MODULES ONLY ***/
 
 verto_ctx *
-verto_convert_funcs(const verto_ctx_funcs *funcs,
-               const verto_module *module,
-               void *ctx_private)
+verto_convert_module(const verto_module *module, int deflt, verto_mod_ctx *mctx)
 {
     verto_ctx *ctx = NULL;
+    module_record *mr;
 
-    if (!funcs || !module || !ctx_private)
-        return NULL;
+    if (!module)
+        goto error;
+
+    if (deflt) {
+        mutex_lock(&loaded_modules_mutex);
+        for (mr = loaded_modules ; mr ; mr = mr->next) {
+            verto_ctx *tmp;
+            if (mr->module == module && mr->defctx) {
+                if (mctx)
+                    module->funcs->ctx_free(mctx);
+                tmp = mr->defctx;
+                tmp->ref++;
+                mutex_unlock(&loaded_modules_mutex);
+                return tmp;
+            }
+        }
+        mutex_unlock(&loaded_modules_mutex);
+    }
+
+    if (!mctx) {
+        mctx = deflt
+                    ? (module->funcs->ctx_default
+                        ? module->funcs->ctx_default()
+                        : module->funcs->ctx_new())
+                    : module->funcs->ctx_new();
+        if (!mctx)
+            goto error;
+    }
 
-    ctx = vnew0(verto_ctx);
+    ctx = malloc(sizeof(verto_ctx));
     if (!ctx)
-        return NULL;
+        goto error;
+    memset(ctx, 0, sizeof(verto_ctx));
+
+    ctx->ref = 1;
+    ctx->ctx = mctx;
+    ctx->module = module;
+    ctx->deflt = deflt;
+
+    if (deflt) {
+        module_record **tmp;
+
+        mutex_lock(&loaded_modules_mutex);
+        tmp = &loaded_modules;
+        for (mr = loaded_modules ; mr ; mr = mr->next) {
+            if (mr->module == module) {
+                assert(mr->defctx == NULL);
+                mr->defctx = ctx;
+                mutex_unlock(&loaded_modules_mutex);
+                return ctx;
+            }
+
+            if (!mr->next) {
+                tmp = &mr->next;
+                break;
+            }
+        }
+        mutex_unlock(&loaded_modules_mutex);
 
-    ctx->modpriv = ctx_private;
-    ctx->funcs = *funcs;
-    ctx->types = module->types;
+        *tmp = malloc(sizeof(module_record));
+        if (!*tmp) {
+            free(ctx);
+            goto error;
+        }
 
-    if (!defmodule)
-        defmodule = module;
+        memset(*tmp, 0, sizeof(module_record));
+        (*tmp)->defctx = ctx;
+        (*tmp)->module = module;
+    }
 
     return ctx;
+
+error:
+    if (mctx)
+        module->funcs->ctx_free(mctx);
+    return NULL;
 }
 
 void
@@ -800,10 +869,10 @@ verto_fire(verto_ev *ev)
             verto_del(ev);
         else if (!ev->actual & VERTO_EV_FLAG_PERSIST) {
             ev->actual = ev->flags;
-            priv = ev->ctx->funcs.ctx_add(ev->ctx->modpriv, ev, &ev->actual);
+            priv = ev->ctx->module->funcs->ctx_add(ev->ctx->ctx, ev, &ev->actual);
             assert(priv); /* TODO: create an error callback */
-            ev->ctx->funcs.ctx_del(ev->ctx->modpriv, ev, ev->modpriv);
-            ev->modpriv = priv;
+            ev->ctx->module->funcs->ctx_del(ev->ctx->ctx, ev, ev->ev);
+            ev->ev = priv;
         }
     }
 }
index d7ab47956e468df73251396b73d0c0bcee48f69e..23d9a2096925293e019433489b8bb1c07ed43b22 100644 (file)
@@ -39,8 +39,8 @@ typedef int verto_proc_status;
 
 #define VERTO_SIG_IGN ((verto_callback *) 1)
 
-typedef struct _verto_ctx verto_ctx;
-typedef struct _verto_ev verto_ev;
+typedef struct verto_ctx verto_ctx;
+typedef struct verto_ev verto_ev;
 
 typedef enum {
     VERTO_EV_TYPE_NONE = 0,
@@ -119,7 +119,7 @@ typedef void (verto_callback)(verto_ctx *ctx, verto_ev *ev);
  * @see verto_set_default()
  * @param impl The implementation to use, or NULL.
  * @param reqtypes A bitwise or'd list of required event type features.
- * @return A new _ev_ctx, or NULL on error.  Call verto_free() when done.
+ * @return A new verto_ctx, or NULL on error.  Call verto_free() when done.
  */
 verto_ctx *
 verto_new(const char *impl, verto_ev_type reqtypes);
@@ -141,7 +141,7 @@ verto_new(const char *impl, verto_ev_type reqtypes);
  * @see verto_free()
  * @param impl The implementation to use, or NULL.
  * @param reqtypes A bitwise or'd list of required event type features.
- * @return The default _ev_ctx, or NULL on error.  Call verto_free() when done.
+ * @return The default verto_ctx, or NULL on error.  Call verto_free() when done.
  */
 verto_ctx *
 verto_default(const char *impl, verto_ev_type reqtypes);
@@ -165,7 +165,7 @@ verto_default(const char *impl, verto_ev_type reqtypes);
  * @see verto_default()
  * @param impl The implementation to use.
  * @param reqtypes A bitwise or'd list of required event type features.
- * @return The default _ev_ctx, or NULL on error.  Call verto_free() when done.
+ * @return The default verto_ctx, or NULL on error.  Call verto_free() when done.
  */
 int
 verto_set_default(const char *impl, verto_ev_type reqtypes);
@@ -217,11 +217,15 @@ verto_break(verto_ctx *ctx);
  * VERTO_EV_FLAG_REINITIABLE flag. If you fork(), you MUST call this in the
  * child process after the fork!
  *
+ * If this function fails it indicates that at least one
+ * VERTO_EV_FLAG_REINITIABLE event was not rearmed or that ctx was NULL.
+ *
  * @see verto_new()
  * @see verto_default()
  * @param ctx The verto_ctx to re-initialize.
+ * @return Non-zero on success, 0 on error.
  */
-void
+int
 verto_reinitialize(verto_ctx *ctx);
 
 /**
@@ -306,7 +310,7 @@ verto_add_idle(verto_ctx *ctx, verto_ev_flag flags,
  * NOTE: SIGCHLD is expressly not supported. If you want this notification,
  * please use verto_add_child().
  *
- * WARNNIG: Signal events can only be reliably received in the default _ev_ctx
+ * WARNNIG: Signal events can only be reliably received in the default verto_ctx
  * in some implementations.  Attempting to receive signal events in non-default
  * loops may result in assert() failures.
  *