From e13c54f53ddf11864a4ca43bac2f88ba55a83eb8 Mon Sep 17 00:00:00 2001 From: Tom Yu Date: Mon, 5 Dec 2011 19:44:11 +0000 Subject: [PATCH] pull up r25474 from trunk ------------------------------------------------------------------------ r25474 | ghudson | 2011-11-14 20:59:01 -0500 (Mon, 14 Nov 2011) | 10 lines ticket: 7018 subject: Update verto to 0.2.2 release target_version: 1.10 tags: pullup 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 version_fixed: 1.10 status: resolved git-svn-id: svn://anonsvn.mit.edu/krb5/branches/krb5-1-10@25509 dc483132-0cff-0310-8789-dd5450dbe970 --- src/kdc/main.c | 6 +- src/util/k5ev/libverto-k5ev.exports | 2 +- src/util/k5ev/verto-k5ev.c | 119 +++--- src/util/k5ev/verto-libev.c | 174 ++++++++ src/util/verto/Makefile.in | 6 +- src/util/verto/libverto.exports | 2 +- src/util/verto/module.c | 184 ++++++++ src/util/verto/module.h | 84 ++++ src/util/verto/verto-module.h | 98 +++-- src/util/verto/verto.c | 627 +++++++++++++++------------- src/util/verto/verto.h | 18 +- 11 files changed, 939 insertions(+), 381 deletions(-) create mode 100644 src/util/k5ev/verto-libev.c create mode 100644 src/util/verto/module.c create mode 100644 src/util/verto/module.h diff --git a/src/kdc/main.c b/src/kdc/main.c index e7d6c6f53..8d4df8762 100644 --- a/src/kdc/main.c +++ b/src/kdc/main.c @@ -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 " diff --git a/src/util/k5ev/libverto-k5ev.exports b/src/util/k5ev/libverto-k5ev.exports index fe128fd47..7907fbef7 100644 --- a/src/util/k5ev/libverto-k5ev.exports +++ b/src/util/k5ev/libverto-k5ev.exports @@ -1,3 +1,3 @@ verto_default_k5ev -verto_module_table +verto_module_table_k5ev verto_new_k5ev diff --git a/src/util/k5ev/verto-k5ev.c b/src/util/k5ev/verto-k5ev.c index 134192fac..d8155d4be 100644 --- a/src/util/k5ev/verto-k5ev.c +++ b/src/util/k5ev/verto-k5ev.c @@ -22,8 +22,11 @@ * 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 #include @@ -44,33 +47,45 @@ #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 index 000000000..4e6e816b9 --- /dev/null +++ b/src/util/k5ev/verto-libev.c @@ -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 +#include +#include + +#include +#define VERTO_MODULE_TYPES +typedef struct ev_loop verto_mod_ctx; +typedef ev_watcher verto_mod_ev; +#include + +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); +} diff --git a/src/util/verto/Makefile.in b/src/util/verto/Makefile.in index 3e07227e2..db6c387ce 100644 --- a/src/util/verto/Makefile.in +++ b/src/util/verto/Makefile.in @@ -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) diff --git a/src/util/verto/libverto.exports b/src/util/verto/libverto.exports index 2f9b1ee2a..1e487744a 100644 --- a/src/util/verto/libverto.exports +++ b/src/util/verto/libverto.exports @@ -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 index 000000000..8b8164659 --- /dev/null +++ b/src/util/verto/module.c @@ -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 +#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 +#include +#include +#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 index 000000000..38c431dcb --- /dev/null +++ b/src/util/verto/module.h @@ -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); diff --git a/src/util/verto/verto-module.h b/src/util/verto/verto-module.h index 05a920f9e..b0e7232b1 100644 --- a/src/util/verto/verto-module.h +++ b/src/util/verto/verto-module.h @@ -29,10 +29,18 @@ #include -#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, \ @@ -41,69 +49,93 @@ 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(). diff --git a/src/util/verto/verto.c b/src/util/verto/verto.c index 34d453c70..af4172687 100644 --- a/src/util/verto/verto.c +++ b/src/util/verto/verto.c @@ -35,124 +35,23 @@ #include #include -#ifdef WIN32 -#include -#else -#include +#ifdef HAVE_PTHREAD +#include #endif #include - -#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; } } } diff --git a/src/util/verto/verto.h b/src/util/verto/verto.h index d7ab47956..23d9a2096 100644 --- a/src/util/verto/verto.h +++ b/src/util/verto/verto.h @@ -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. * -- 2.26.2