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 "
verto_default_k5ev
-verto_module_table
+verto_module_table_k5ev
verto_new_k5ev
* 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);
}
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:
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;
}
free(evpriv);
}
-static verto_ctx *verto_convert_k5ev(struct ev_loop* loop);
-
VERTO_MODULE(k5ev, NULL,
VERTO_EV_TYPE_IO |
VERTO_EV_TYPE_TIMEOUT |
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);
}
--- /dev/null
+/*
+ * 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);
+}
# 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)
verto_add_signal
verto_add_timeout
verto_break
-verto_convert_funcs
+verto_convert_module
verto_default
verto_del
verto_fire
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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);
#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().
#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 {
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;
} 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) {
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;
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:
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);
}
}
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);
}
{
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
{
if (!ctx)
return;
- ctx->funcs.ctx_run_once(ctx->modpriv);
+ ctx->module->funcs->ctx_run_once(ctx->ctx);
}
void
{
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) \
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,
return NULL;
doadd(ev, ev->option.fd = fd, VERTO_EV_TYPE_IO);
+ return ev;
}
verto_ev *
{
verto_ev *ev;
doadd(ev, ev->option.interval = interval, VERTO_EV_TYPE_TIMEOUT);
+ return ev;
}
verto_ev *
{
verto_ev *ev;
doadd(ev,, VERTO_EV_TYPE_IDLE);
+ return ev;
}
verto_ev *
return NULL;
}
doadd(ev, ev->option.signal = signal, VERTO_EV_TYPE_SIGNAL);
+ return ev;
}
verto_ev *
#endif
return NULL;
doadd(ev, ev->option.child.proc = proc, VERTO_EV_TYPE_CHILD);
+ return ev;
}
void
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);
}
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
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;
}
}
}
#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,
* @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);
* @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);
* @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);
* 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);
/**
* 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.
*