Path: blob/main/crypto/krb5/src/util/verto/verto.c
34907 views
/*1* Copyright 2011 Red Hat, Inc.2*3* Permission is hereby granted, free of charge, to any person4* obtaining a copy of this software and associated documentation files5* (the "Software"), to deal in the Software without restriction,6* including without limitation the rights to use, copy, modify, merge,7* publish, distribute, sublicense, and/or sell copies of the Software,8* and to permit persons to whom the Software is furnished to do so,9* subject to the following conditions:10*11* The above copyright notice and this permission notice shall be12* included in all copies or substantial portions of the Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,15* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF16* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND17* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS18* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN19* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN20* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE21* SOFTWARE.22*/2324#include <stdio.h>25#include <stdlib.h>26#include <string.h>27#include <signal.h>28#include <assert.h>29#include <stdarg.h>3031#include <libgen.h>32#include <sys/types.h>33#include <dirent.h>3435#ifdef HAVE_PTHREAD36#include <pthread.h>37#endif3839#include <verto-module.h>40#include "module.h"4142#define _str(s) # s43#define __str(s) _str(s)4445#define MUTABLE(flags) (flags & _VERTO_EV_FLAG_MUTABLE_MASK)4647/* Remove flags we can emulate */48#define make_actual(flags) ((flags) & ~(VERTO_EV_FLAG_PERSIST|VERTO_EV_FLAG_IO_CLOSE_FD))4950struct verto_ctx {51size_t ref;52verto_mod_ctx *ctx;53const verto_module *module;54verto_ev *events;55int deflt;56int exit;57};5859typedef struct {60verto_proc proc;61verto_proc_status status;62} verto_child;6364typedef struct {65int fd;66verto_ev_flag state;67} verto_io;6869struct verto_ev {70verto_ev *next;71verto_ctx *ctx;72verto_ev_type type;73verto_callback *callback;74verto_callback *onfree;75void *priv;76verto_mod_ev *ev;77verto_ev_flag flags;78verto_ev_flag actual;79size_t depth;80int deleted;81union {82verto_io io;83int signal;84time_t interval;85verto_child child;86} option;87};8889typedef struct module_record module_record;90struct module_record {91module_record *next;92const verto_module *module;93void *dll;94char *filename;95verto_ctx *defctx;96};979899#ifdef BUILTIN_MODULE100#define _MODTABLE(n) verto_module_table_ ## n101#define MODTABLE(n) _MODTABLE(n)102/*103* This symbol can be used when embedding verto.c in a library along with a104* built-in private module, to preload the module instead of dynamically105* linking it in later. Define to <modulename>.106*/107extern verto_module MODTABLE(BUILTIN_MODULE);108static module_record builtin_record = {109NULL, &MODTABLE(BUILTIN_MODULE), NULL, "", NULL110};111static module_record *loaded_modules = &builtin_record;112#else113static module_record *loaded_modules;114#endif115116static void *(*resize_cb)(void *mem, size_t size);117static int resize_cb_hierarchical;118119#ifdef HAVE_PTHREAD120static pthread_mutex_t loaded_modules_mutex = PTHREAD_MUTEX_INITIALIZER;121122#ifndef NDEBUG123#define mutex_lock(x) { \124int c = pthread_mutex_lock(x); \125if (c != 0) { \126fprintf(stderr, "pthread_mutex_lock returned %d (%s) in %s", \127c, strerror(c), __FUNCTION__); \128} \129assert(c == 0); \130}131#define mutex_unlock(x) { \132int c = pthread_mutex_unlock(x); \133if (c != 0) { \134fprintf(stderr, "pthread_mutex_unlock returned %d (%s) in %s", \135c, strerror(c), __FUNCTION__); \136} \137assert(c == 0); \138}139#define mutex_destroy(x) { \140int c = pthread_mutex_destroy(x); \141if (c != 0) { \142fprintf(stderr, "pthread_mutex_destroy returned %d (%s) in %s", \143c, strerror(c), __FUNCTION__); \144} \145assert(c == 0); \146}147#else /* NDEBUG */148#define mutex_lock pthread_mutex_lock149#define mutex_unlock pthread_mutex_unlock150#define mutex_destroy pthread_mutex_destroy151#endif /* NDEBUG */152153#else /* HAVE_PTHREAD */154#define mutex_lock(x)155#define mutex_unlock(x)156#define mutex_destroy(x)157#endif /* HAVE_PTHREAD */158159#define vfree(mem) vresize(mem, 0)160static void *161vresize(void *mem, size_t size)162{163if (!resize_cb)164resize_cb = &realloc;165if (size == 0 && resize_cb == &realloc) {166/* Avoid memleak as realloc(X, 0) can return a free-able pointer. */167free(mem);168return NULL;169}170return (*resize_cb)(mem, size);171}172173#ifndef BUILTIN_MODULE174static char *175string_aconcat(const char *first, const char *second, const char *third) {176char *ret;177size_t len;178179len = strlen(first) + strlen(second);180if (third)181len += strlen(third);182183ret = malloc(len + 1);184if (!ret)185return NULL;186187strncpy(ret, first, strlen(first));188strncpy(ret + strlen(first), second, strlen(second));189if (third)190strncpy(ret + strlen(first) + strlen(second), third, strlen(third));191192ret[len] = '\0';193return ret;194}195196static char *197int_get_table_name_from_filename(const char *filename)198{199char *bn = NULL, *tmp = NULL;200201if (!filename)202return NULL;203204tmp = strdup(filename);205if (!tmp)206return NULL;207208bn = basename(tmp);209if (bn)210bn = strdup(bn);211free(tmp);212if (!bn)213return NULL;214215tmp = strchr(bn, '-');216if (tmp) {217if (strchr(tmp+1, '.')) {218*strchr(tmp+1, '.') = '\0';219tmp = string_aconcat(__str(VERTO_MODULE_TABLE()), tmp + 1, NULL);220} else221tmp = NULL;222}223224free(bn);225return tmp;226}227228typedef struct {229int reqsym;230verto_ev_type reqtypes;231} shouldload_data;232233static int234shouldload(void *symb, void *misc, char **err)235{236verto_module *table = (verto_module*) symb;237shouldload_data *data = (shouldload_data*) misc;238239/* Make sure we have the proper version */240if (table->vers != VERTO_MODULE_VERSION) {241if (err)242*err = strdup("Invalid module version!");243return 0;244}245246/* Check to make sure that we have our required symbol if reqsym == true */247if (table->symb && data->reqsym248&& !module_symbol_is_present(NULL, table->symb)) {249if (err)250*err = string_aconcat("Symbol not found: ", table->symb, "!");251return 0;252}253254/* Check to make sure that this module supports our required features */255if (data->reqtypes != VERTO_EV_TYPE_NONE256&& (table->types & data->reqtypes) != data->reqtypes) {257if (err)258*err = strdup("Module does not support required features!");259return 0;260}261262return 1;263}264265static int266do_load_file(const char *filename, int reqsym, verto_ev_type reqtypes,267module_record **record)268{269char *tblname = NULL, *error = NULL;270module_record *tmp;271shouldload_data data = { reqsym, reqtypes };272273/* Check the loaded modules to see if we already loaded one */274mutex_lock(&loaded_modules_mutex);275for (*record = loaded_modules ; *record ; *record = (*record)->next) {276if (!strcmp((*record)->filename, filename)) {277mutex_unlock(&loaded_modules_mutex);278return 1;279}280}281mutex_unlock(&loaded_modules_mutex);282283/* Create our module record */284tmp = *record = vresize(NULL, sizeof(module_record));285if (!tmp)286return 0;287memset(tmp, 0, sizeof(module_record));288tmp->filename = strdup(filename);289if (!tmp->filename) {290vfree(tmp);291return 0;292}293294/* Get the name of the module struct in the library */295tblname = int_get_table_name_from_filename(filename);296if (!tblname) {297free(tblname);298free(tmp->filename);299vfree(tmp);300return 0;301}302303/* Load the module */304error = module_load(filename, tblname, shouldload, &data, &tmp->dll,305(void **) &tmp->module);306if (error || !tmp->dll || !tmp->module) {307/*if (error)308fprintf(stderr, "%s\n", error);*/309free(error);310module_close(tmp->dll);311free(tblname);312free(tmp->filename);313vfree(tmp);314return 0;315}316317/* Append the new module to the end of the loaded modules */318mutex_lock(&loaded_modules_mutex);319for (tmp = loaded_modules ; tmp && tmp->next; tmp = tmp->next)320continue;321if (tmp)322tmp->next = *record;323else324loaded_modules = *record;325mutex_unlock(&loaded_modules_mutex);326327free(tblname);328return 1;329}330331static int332do_load_dir(const char *dirname, const char *prefix, const char *suffix,333int reqsym, verto_ev_type reqtypes, module_record **record)334{335DIR *dir;336struct dirent *ent = NULL;337338*record = NULL;339dir = opendir(dirname);340if (!dir)341return 0;342343344while ((ent = readdir(dir))) {345char *tmp = NULL;346int success;347size_t flen, slen;348349flen = strlen(ent->d_name);350slen = strlen(suffix);351352if (!strcmp(".", ent->d_name) || !strcmp("..", ent->d_name))353continue;354if (strstr(ent->d_name, prefix) != ent->d_name)355continue;356if (flen < slen || strcmp(ent->d_name + flen - slen, suffix))357continue;358359tmp = string_aconcat(dirname, "/", ent->d_name);360if (!tmp)361continue;362363success = do_load_file(tmp, reqsym, reqtypes, record);364free(tmp);365if (success)366break;367*record = NULL;368}369370closedir(dir);371return *record != NULL;372}373#endif374375static int376load_module(const char *impl, verto_ev_type reqtypes, module_record **record)377{378int success = 0;379#ifndef BUILTIN_MODULE380char *prefix = NULL;381char *suffix = NULL;382char *tmp = NULL;383#endif384385/* Check the cache */386mutex_lock(&loaded_modules_mutex);387if (impl) {388for (*record = loaded_modules ; *record ; *record = (*record)->next) {389if ((strchr(impl, '/') && !strcmp(impl, (*record)->filename))390|| !strcmp(impl, (*record)->module->name)) {391mutex_unlock(&loaded_modules_mutex);392return 1;393}394}395} else if (loaded_modules) {396for (*record = loaded_modules ; *record ; *record = (*record)->next) {397if (reqtypes == VERTO_EV_TYPE_NONE398|| ((*record)->module->types & reqtypes) == reqtypes) {399mutex_unlock(&loaded_modules_mutex);400return 1;401}402}403}404mutex_unlock(&loaded_modules_mutex);405406#ifndef BUILTIN_MODULE407if (!module_get_filename_for_symbol(verto_convert_module, &prefix))408return 0;409410/* Example output:411* prefix == /usr/lib/libverto-412* impl == glib413* suffix == .so.0414* Put them all together: /usr/lib/libverto-glib.so.0 */415tmp = strdup(prefix);416if (!tmp) {417free(prefix);418return 0;419}420421suffix = basename(tmp);422suffix = strchr(suffix, '.');423if (!suffix || strlen(suffix) < 1 || !(suffix = strdup(suffix))) {424free(prefix);425free(tmp);426return 0;427}428strcpy(prefix + strlen(prefix) - strlen(suffix), "-");429free(tmp);430431if (impl) {432/* Try to do a load by the path */433if (!success && strchr(impl, '/'))434success = do_load_file(impl, 0, reqtypes, record);435if (!success) {436/* Try to do a load by the name */437tmp = string_aconcat(prefix, impl, suffix);438if (tmp) {439success = do_load_file(tmp, 0, reqtypes, record);440free(tmp);441}442}443} else {444/* NULL was passed, so we will use the dirname of445* the prefix to try and find any possible plugins */446tmp = strdup(prefix);447if (tmp) {448char *dname = strdup(dirname(tmp));449free(tmp);450451tmp = strdup(basename(prefix));452free(prefix);453prefix = tmp;454455if (dname && prefix) {456/* Attempt to find a module we are already linked to */457success = do_load_dir(dname, prefix, suffix, 1, reqtypes,458record);459if (!success) {460#ifdef DEFAULT_MODULE461/* Attempt to find the default module */462success = load_module(DEFAULT_MODULE, reqtypes, record);463if (!success)464#endif /* DEFAULT_MODULE */465/* Attempt to load any plugin (we're desperate) */466success = do_load_dir(dname, prefix, suffix, 0,467reqtypes, record);468}469}470471free(dname);472}473}474475free(suffix);476free(prefix);477#endif /* BUILTIN_MODULE */478return success;479}480481static verto_ev *482make_ev(verto_ctx *ctx, verto_callback *callback,483verto_ev_type type, verto_ev_flag flags)484{485verto_ev *ev = NULL;486487if (!ctx || !callback)488return NULL;489490ev = vresize(NULL, sizeof(verto_ev));491if (ev) {492memset(ev, 0, sizeof(verto_ev));493ev->ctx = ctx;494ev->type = type;495ev->callback = callback;496ev->flags = flags;497}498499return ev;500}501502static void503push_ev(verto_ctx *ctx, verto_ev *ev)504{505verto_ev *tmp;506507if (!ctx || !ev)508return;509510tmp = ctx->events;511ctx->events = ev;512ctx->events->next = tmp;513}514515static void516remove_ev(verto_ev **origin, verto_ev *item)517{518if (!origin || !*origin || !item)519return;520521if (*origin == item)522*origin = (*origin)->next;523else524remove_ev(&((*origin)->next), item);525}526527static void528signal_ignore(verto_ctx *ctx, verto_ev *ev)529{530(void) ctx;531(void) ev;532}533534verto_ctx *535verto_new(const char *impl, verto_ev_type reqtypes)536{537module_record *mr = NULL;538539if (!load_module(impl, reqtypes, &mr))540return NULL;541542return verto_convert_module(mr->module, 0, NULL);543}544545verto_ctx *546verto_default(const char *impl, verto_ev_type reqtypes)547{548module_record *mr = NULL;549550if (!load_module(impl, reqtypes, &mr))551return NULL;552553return verto_convert_module(mr->module, 1, NULL);554}555556int557verto_set_default(const char *impl, verto_ev_type reqtypes)558{559module_record *mr;560561mutex_lock(&loaded_modules_mutex);562if (loaded_modules || !impl) {563mutex_unlock(&loaded_modules_mutex);564return 0;565}566mutex_unlock(&loaded_modules_mutex);567568return load_module(impl, reqtypes, &mr);569}570571int572verto_set_allocator(void *(*resize)(void *mem, size_t size),573int hierarchical)574{575if (resize_cb || !resize)576return 0;577resize_cb = resize;578resize_cb_hierarchical = hierarchical;579return 1;580}581582void583verto_free(verto_ctx *ctx)584{585if (!ctx)586return;587588ctx->ref = ctx->ref > 0 ? ctx->ref - 1 : 0;589if (ctx->ref > 0)590return;591592/* Cancel all pending events */593while (ctx->events)594verto_del(ctx->events);595596/* Free the private */597if (!ctx->deflt || !ctx->module->funcs->ctx_default)598ctx->module->funcs->ctx_free(ctx->ctx);599600vfree(ctx);601}602603void604verto_cleanup(void)605{606module_record *record;607608mutex_lock(&loaded_modules_mutex);609610for (record = loaded_modules; record; record = record->next) {611module_close(record->dll);612free(record->filename);613}614615vfree(loaded_modules);616loaded_modules = NULL;617618mutex_unlock(&loaded_modules_mutex);619mutex_destroy(&loaded_modules_mutex);620}621622void623verto_run(verto_ctx *ctx)624{625if (!ctx)626return;627628if (ctx->module->funcs->ctx_break && ctx->module->funcs->ctx_run)629ctx->module->funcs->ctx_run(ctx->ctx);630else {631while (!ctx->exit)632ctx->module->funcs->ctx_run_once(ctx->ctx);633ctx->exit = 0;634}635}636637void638verto_run_once(verto_ctx *ctx)639{640if (!ctx)641return;642ctx->module->funcs->ctx_run_once(ctx->ctx);643}644645void646verto_break(verto_ctx *ctx)647{648if (!ctx)649return;650651if (ctx->module->funcs->ctx_break && ctx->module->funcs->ctx_run)652ctx->module->funcs->ctx_break(ctx->ctx);653else654ctx->exit = 1;655}656657int658verto_reinitialize(verto_ctx *ctx)659{660verto_ev *tmp, *next;661int error = 1;662663if (!ctx)664return 0;665666/* Delete all events, but keep around the forkable ev structs */667for (tmp = ctx->events; tmp; tmp = next) {668next = tmp->next;669670if (tmp->flags & VERTO_EV_FLAG_REINITIABLE)671ctx->module->funcs->ctx_del(ctx->ctx, tmp, tmp->ev);672else673verto_del(tmp);674}675676/* Reinit the loop */677if (ctx->module->funcs->ctx_reinitialize)678ctx->module->funcs->ctx_reinitialize(ctx->ctx);679680/* Recreate events that were marked forkable */681for (tmp = ctx->events; tmp; tmp = tmp->next) {682tmp->actual = make_actual(tmp->flags);683tmp->ev = ctx->module->funcs->ctx_add(ctx->ctx, tmp, &tmp->actual);684if (!tmp->ev)685error = 0;686}687688return error;689}690691#define doadd(ev, set, type) \692ev = make_ev(ctx, callback, type, flags); \693if (ev) { \694set; \695ev->actual = make_actual(ev->flags); \696ev->ev = ctx->module->funcs->ctx_add(ctx->ctx, ev, &ev->actual); \697if (!ev->ev) { \698vfree(ev); \699return NULL; \700} \701push_ev(ctx, ev); \702}703704verto_ev *705verto_add_io(verto_ctx *ctx, verto_ev_flag flags,706verto_callback *callback, int fd)707{708verto_ev *ev;709710if (fd < 0 || !(flags & (VERTO_EV_FLAG_IO_READ | VERTO_EV_FLAG_IO_WRITE)))711return NULL;712713doadd(ev, ev->option.io.fd = fd, VERTO_EV_TYPE_IO);714return ev;715}716717verto_ev *718verto_add_timeout(verto_ctx *ctx, verto_ev_flag flags,719verto_callback *callback, time_t interval)720{721verto_ev *ev;722doadd(ev, ev->option.interval = interval, VERTO_EV_TYPE_TIMEOUT);723return ev;724}725726verto_ev *727verto_add_idle(verto_ctx *ctx, verto_ev_flag flags,728verto_callback *callback)729{730verto_ev *ev;731doadd(ev,, VERTO_EV_TYPE_IDLE);732return ev;733}734735verto_ev *736verto_add_signal(verto_ctx *ctx, verto_ev_flag flags,737verto_callback *callback, int signal)738{739verto_ev *ev;740741if (signal < 0)742return NULL;743#ifndef WIN32744if (signal == SIGCHLD)745return NULL;746#endif747if (callback == VERTO_SIG_IGN) {748callback = signal_ignore;749if (!(flags & VERTO_EV_FLAG_PERSIST))750return NULL;751}752doadd(ev, ev->option.signal = signal, VERTO_EV_TYPE_SIGNAL);753return ev;754}755756verto_ev *757verto_add_child(verto_ctx *ctx, verto_ev_flag flags,758verto_callback *callback, verto_proc proc)759{760verto_ev *ev;761762if (flags & VERTO_EV_FLAG_PERSIST) /* persist makes no sense */763return NULL;764#ifdef WIN32765if (proc == NULL)766#else767if (proc < 1)768#endif769return NULL;770doadd(ev, ev->option.child.proc = proc, VERTO_EV_TYPE_CHILD);771return ev;772}773774void775verto_set_private(verto_ev *ev, void *priv, verto_callback *free)776{777if (!ev)778return;779if (ev->onfree && free)780ev->onfree(ev->ctx, ev);781ev->priv = priv;782ev->onfree = free;783}784785void *786verto_get_private(const verto_ev *ev)787{788return ev->priv;789}790791verto_ev_type792verto_get_type(const verto_ev *ev)793{794return ev->type;795}796797verto_ev_flag798verto_get_flags(const verto_ev *ev)799{800return ev->flags;801}802803void804verto_set_flags(verto_ev *ev, verto_ev_flag flags)805{806if (!ev)807return;808809/* No modification is needed, so do nothing. */810if (MUTABLE(ev->flags) == MUTABLE(flags))811return;812813ev->flags &= ~_VERTO_EV_FLAG_MUTABLE_MASK;814ev->flags |= MUTABLE(flags);815816/* If setting flags isn't supported, just rebuild the event */817if (!ev->ctx->module->funcs->ctx_set_flags) {818ev->ctx->module->funcs->ctx_del(ev->ctx->ctx, ev, ev->ev);819ev->actual = make_actual(ev->flags);820ev->ev = ev->ctx->module->funcs->ctx_add(ev->ctx->ctx, ev, &ev->actual);821assert(ev->ev); /* Here is the main reason why modules should */822return; /* implement set_flags(): we cannot fail gracefully. */823}824825ev->actual &= ~_VERTO_EV_FLAG_MUTABLE_MASK;826ev->actual |= MUTABLE(flags);827ev->ctx->module->funcs->ctx_set_flags(ev->ctx->ctx, ev, ev->ev);828}829830int831verto_get_fd(const verto_ev *ev)832{833if (ev && (ev->type == VERTO_EV_TYPE_IO))834return ev->option.io.fd;835return -1;836}837838verto_ev_flag839verto_get_fd_state(const verto_ev *ev)840{841return ev->option.io.state;842}843844time_t845verto_get_interval(const verto_ev *ev)846{847if (ev && (ev->type == VERTO_EV_TYPE_TIMEOUT))848return ev->option.interval;849return 0;850}851852int853verto_get_signal(const verto_ev *ev)854{855if (ev && (ev->type == VERTO_EV_TYPE_SIGNAL))856return ev->option.signal;857return -1;858}859860verto_proc861verto_get_proc(const verto_ev *ev) {862if (ev && ev->type == VERTO_EV_TYPE_CHILD)863return ev->option.child.proc;864return (verto_proc) 0;865}866867verto_proc_status868verto_get_proc_status(const verto_ev *ev)869{870return ev->option.child.status;871}872873verto_ctx *874verto_get_ctx(const verto_ev *ev)875{876return ev->ctx;877}878879void880verto_del(verto_ev *ev)881{882if (!ev)883return;884885/* If the event is freed in the callback, we just set a flag so that886* verto_fire() can actually do the delete when the callback completes.887*888* If we don't do this, than verto_fire() will access freed memory. */889if (ev->depth > 0) {890ev->deleted = 1;891return;892}893894if (ev->onfree)895ev->onfree(ev->ctx, ev);896ev->ctx->module->funcs->ctx_del(ev->ctx->ctx, ev, ev->ev);897remove_ev(&(ev->ctx->events), ev);898899if ((ev->type == VERTO_EV_TYPE_IO) &&900(ev->flags & VERTO_EV_FLAG_IO_CLOSE_FD) &&901!(ev->actual & VERTO_EV_FLAG_IO_CLOSE_FD))902close(ev->option.io.fd);903904vfree(ev);905}906907verto_ev_type908verto_get_supported_types(verto_ctx *ctx)909{910return ctx->module->types;911}912913/*** THE FOLLOWING ARE FOR IMPLEMENTATION MODULES ONLY ***/914915verto_ctx *916verto_convert_module(const verto_module *module, int deflt, verto_mod_ctx *mctx)917{918verto_ctx *ctx = NULL;919module_record *mr;920921if (!module)922return NULL;923924if (deflt) {925mutex_lock(&loaded_modules_mutex);926for (mr = loaded_modules ; mr ; mr = mr->next) {927verto_ctx *tmp;928if (mr->module == module && mr->defctx) {929if (mctx)930module->funcs->ctx_free(mctx);931tmp = mr->defctx;932tmp->ref++;933mutex_unlock(&loaded_modules_mutex);934return tmp;935}936}937mutex_unlock(&loaded_modules_mutex);938}939940if (!mctx) {941mctx = deflt942? (module->funcs->ctx_default943? module->funcs->ctx_default()944: module->funcs->ctx_new())945: module->funcs->ctx_new();946if (!mctx)947goto error;948}949950ctx = vresize(NULL, sizeof(verto_ctx));951if (!ctx)952goto error;953memset(ctx, 0, sizeof(verto_ctx));954955ctx->ref = 1;956ctx->ctx = mctx;957ctx->module = module;958ctx->deflt = deflt;959960if (deflt) {961module_record **tmp;962963mutex_lock(&loaded_modules_mutex);964tmp = &loaded_modules;965for (mr = loaded_modules ; mr ; mr = mr->next) {966if (mr->module == module) {967assert(mr->defctx == NULL);968mr->defctx = ctx;969mutex_unlock(&loaded_modules_mutex);970return ctx;971}972973if (!mr->next) {974tmp = &mr->next;975break;976}977}978mutex_unlock(&loaded_modules_mutex);979980*tmp = vresize(NULL, sizeof(module_record));981if (!*tmp) {982vfree(ctx);983goto error;984}985986memset(*tmp, 0, sizeof(module_record));987(*tmp)->defctx = ctx;988(*tmp)->module = module;989}990991return ctx;992993error:994if (mctx)995module->funcs->ctx_free(mctx);996return NULL;997}998999void1000verto_fire(verto_ev *ev)1001{1002void *priv;10031004ev->depth++;1005ev->callback(ev->ctx, ev);1006ev->depth--;10071008if (ev->depth == 0) {1009if (!(ev->flags & VERTO_EV_FLAG_PERSIST) || ev->deleted)1010verto_del(ev);1011else {1012if (!(ev->actual & VERTO_EV_FLAG_PERSIST)) {1013ev->actual = make_actual(ev->flags);1014priv = ev->ctx->module->funcs->ctx_add(ev->ctx->ctx, ev, &ev->actual);1015assert(priv); /* TODO: create an error callback */1016ev->ctx->module->funcs->ctx_del(ev->ctx->ctx, ev, ev->ev);1017ev->ev = priv;1018}10191020if (ev->type == VERTO_EV_TYPE_IO)1021ev->option.io.state = VERTO_EV_FLAG_NONE;1022if (ev->type == VERTO_EV_TYPE_CHILD)1023ev->option.child.status = 0;1024}1025}1026}10271028void1029verto_set_proc_status(verto_ev *ev, verto_proc_status status)1030{1031if (ev && ev->type == VERTO_EV_TYPE_CHILD)1032ev->option.child.status = status;1033}10341035void1036verto_set_fd_state(verto_ev *ev, verto_ev_flag state)1037{1038/* Filter out only the io flags */1039state = state & (VERTO_EV_FLAG_IO_READ |1040VERTO_EV_FLAG_IO_WRITE |1041VERTO_EV_FLAG_IO_ERROR);10421043/* Don't report read/write if the socket is closed */1044if (state & VERTO_EV_FLAG_IO_ERROR)1045state = VERTO_EV_FLAG_IO_ERROR;10461047if (ev && ev->type == VERTO_EV_TYPE_IO)1048ev->option.io.state = state;1049}105010511052