Fix autoconf 2.70 compatibility
[platform/upstream/krb5.git] / src / util / verto / verto.c
1 /*
2  * Copyright 2011 Red Hat, Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person
5  * obtaining a copy of this software and associated documentation files
6  * (the "Software"), to deal in the Software without restriction,
7  * including without limitation the rights to use, copy, modify, merge,
8  * publish, distribute, sublicense, and/or sell copies of the Software,
9  * and to permit persons to whom the Software is furnished to do so,
10  * subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be
13  * included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  */
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <signal.h>
29 #include <assert.h>
30 #include <stdarg.h>
31
32 #include <libgen.h>
33 #include <sys/types.h>
34 #include <dirent.h>
35
36 #ifdef HAVE_PTHREAD
37 #include <pthread.h>
38 #endif
39
40 #include <verto-module.h>
41 #include "module.h"
42
43 #define  _str(s) # s
44 #define __str(s) _str(s)
45
46 #define MUTABLE(flags) (flags & _VERTO_EV_FLAG_MUTABLE_MASK)
47
48 /* Remove flags we can emulate */
49 #define make_actual(flags) ((flags) & ~(VERTO_EV_FLAG_PERSIST|VERTO_EV_FLAG_IO_CLOSE_FD))
50
51 struct verto_ctx {
52     size_t ref;
53     verto_mod_ctx *ctx;
54     const verto_module *module;
55     verto_ev *events;
56     int deflt;
57     int exit;
58 };
59
60 typedef struct {
61     verto_proc proc;
62     verto_proc_status status;
63 } verto_child;
64
65 typedef struct {
66     int fd;
67     verto_ev_flag state;
68 } verto_io;
69
70 struct verto_ev {
71     verto_ev *next;
72     verto_ctx *ctx;
73     verto_ev_type type;
74     verto_callback *callback;
75     verto_callback *onfree;
76     void *priv;
77     verto_mod_ev *ev;
78     verto_ev_flag flags;
79     verto_ev_flag actual;
80     size_t depth;
81     int deleted;
82     union {
83         verto_io io;
84         int signal;
85         time_t interval;
86         verto_child child;
87     } option;
88 };
89
90 typedef struct module_record module_record;
91 struct module_record {
92     module_record *next;
93     const verto_module *module;
94     void *dll;
95     char *filename;
96     verto_ctx *defctx;
97 };
98
99
100 #ifdef BUILTIN_MODULE
101 #define _MODTABLE(n) verto_module_table_ ## n
102 #define MODTABLE(n) _MODTABLE(n)
103 /*
104  * This symbol can be used when embedding verto.c in a library along with a
105  * built-in private module, to preload the module instead of dynamically
106  * linking it in later.  Define to <modulename>.
107  */
108 extern verto_module MODTABLE(BUILTIN_MODULE);
109 static module_record builtin_record = {
110     NULL, &MODTABLE(BUILTIN_MODULE), NULL, "", NULL
111 };
112 static module_record *loaded_modules = &builtin_record;
113 #else
114 static module_record *loaded_modules;
115 #endif
116
117 static void *(*resize_cb)(void *mem, size_t size);
118 static int resize_cb_hierarchical;
119
120 #ifdef HAVE_PTHREAD
121 static pthread_mutex_t loaded_modules_mutex = PTHREAD_MUTEX_INITIALIZER;
122
123 #ifndef NDEBUG
124 #define mutex_lock(x) { \
125         int c = pthread_mutex_lock(x); \
126         if (c != 0) { \
127             fprintf(stderr, "pthread_mutex_lock returned %d (%s) in %s", \
128                     c, strerror(c), __FUNCTION__); \
129         } \
130         assert(c == 0); \
131     }
132 #define mutex_unlock(x) { \
133         int c = pthread_mutex_unlock(x); \
134         if (c != 0) { \
135             fprintf(stderr, "pthread_mutex_unlock returned %d (%s) in %s", \
136                     c, strerror(c), __FUNCTION__); \
137         } \
138         assert(c == 0); \
139     }
140 #define mutex_destroy(x) { \
141         int c = pthread_mutex_destroy(x); \
142         if (c != 0) { \
143             fprintf(stderr, "pthread_mutex_destroy returned %d (%s) in %s", \
144                     c, strerror(c), __FUNCTION__); \
145         } \
146         assert(c == 0); \
147     }
148 #else /* NDEBUG */
149 #define mutex_lock pthread_mutex_lock
150 #define mutex_unlock pthread_mutex_unlock
151 #define mutex_destroy pthread_mutex_destroy
152 #endif /* NDEBUG */
153
154 #else /* HAVE_PTHREAD */
155 #define mutex_lock(x)
156 #define mutex_unlock(x)
157 #define mutex_destroy(x)
158 #endif /* HAVE_PTHREAD */
159
160 #define vfree(mem) vresize(mem, 0)
161 static void *
162 vresize(void *mem, size_t size)
163 {
164     if (!resize_cb)
165         resize_cb = &realloc;
166     if (size == 0 && resize_cb == &realloc) {
167         /* Avoid memleak as realloc(X, 0) can return a free-able pointer. */
168         free(mem);
169         return NULL;
170     }
171     return (*resize_cb)(mem, size);
172 }
173
174 #ifndef BUILTIN_MODULE
175 static char *
176 string_aconcat(const char *first, const char *second, const char *third) {
177     char *ret;
178     size_t len;
179
180     len = strlen(first) + strlen(second);
181     if (third)
182         len += strlen(third);
183
184     ret = malloc(len + 1);
185     if (!ret)
186         return NULL;
187
188     strncpy(ret, first, strlen(first));
189     strncpy(ret + strlen(first), second, strlen(second));
190     if (third)
191         strncpy(ret + strlen(first) + strlen(second), third, strlen(third));
192
193     ret[len] = '\0';
194     return ret;
195 }
196
197 static char *
198 int_get_table_name_from_filename(const char *filename)
199 {
200     char *bn = NULL, *tmp = NULL;
201
202     if (!filename)
203         return NULL;
204
205     tmp = strdup(filename);
206     if (!tmp)
207         return NULL;
208
209     bn = basename(tmp);
210     if (bn)
211         bn = strdup(bn);
212     free(tmp);
213     if (!bn)
214         return NULL;
215
216     tmp = strchr(bn, '-');
217     if (tmp) {
218         if (strchr(tmp+1, '.')) {
219             *strchr(tmp+1, '.') = '\0';
220             tmp = string_aconcat(__str(VERTO_MODULE_TABLE()), tmp + 1, NULL);
221         } else
222             tmp = NULL;
223     }
224
225     free(bn);
226     return tmp;
227 }
228
229 typedef struct {
230     int reqsym;
231     verto_ev_type reqtypes;
232 } shouldload_data;
233
234 static int
235 shouldload(void *symb, void *misc, char **err)
236 {
237     verto_module *table = (verto_module*) symb;
238     shouldload_data *data = (shouldload_data*) misc;
239
240     /* Make sure we have the proper version */
241     if (table->vers != VERTO_MODULE_VERSION) {
242         if (err)
243             *err = strdup("Invalid module version!");
244         return 0;
245     }
246
247     /* Check to make sure that we have our required symbol if reqsym == true */
248     if (table->symb && data->reqsym
249             && !module_symbol_is_present(NULL, table->symb)) {
250         if (err)
251             *err = string_aconcat("Symbol not found: ", table->symb, "!");
252         return 0;
253     }
254
255     /* Check to make sure that this module supports our required features */
256     if (data->reqtypes != VERTO_EV_TYPE_NONE
257             && (table->types & data->reqtypes) != data->reqtypes) {
258         if (err)
259             *err = strdup("Module does not support required features!");
260         return 0;
261     }
262
263     return 1;
264 }
265
266 static int
267 do_load_file(const char *filename, int reqsym, verto_ev_type reqtypes,
268              module_record **record)
269 {
270     char *tblname = NULL, *error = NULL;
271     module_record *tmp;
272     shouldload_data data  = { reqsym, reqtypes };
273
274     /* Check the loaded modules to see if we already loaded one */
275     mutex_lock(&loaded_modules_mutex);
276     for (*record = loaded_modules ; *record ; *record = (*record)->next) {
277         if (!strcmp((*record)->filename, filename)) {
278             mutex_unlock(&loaded_modules_mutex);
279             return 1;
280         }
281     }
282     mutex_unlock(&loaded_modules_mutex);
283
284     /* Create our module record */
285     tmp = *record = vresize(NULL, sizeof(module_record));
286     if (!tmp)
287         return 0;
288     memset(tmp, 0, sizeof(module_record));
289     tmp->filename = strdup(filename);
290     if (!tmp->filename) {
291         vfree(tmp);
292         return 0;
293     }
294
295     /* Get the name of the module struct in the library */
296     tblname = int_get_table_name_from_filename(filename);
297     if (!tblname) {
298         free(tblname);
299         free(tmp->filename);
300         vfree(tmp);
301         return 0;
302     }
303
304     /* Load the module */
305     error = module_load(filename, tblname, shouldload, &data, &tmp->dll,
306                         (void **) &tmp->module);
307     if (error || !tmp->dll || !tmp->module) {
308         /*if (error)
309             fprintf(stderr, "%s\n", error);*/
310         free(error);
311         module_close(tmp->dll);
312         free(tblname);
313         free(tmp->filename);
314         vfree(tmp);
315         return 0;
316     }
317
318     /* Append the new module to the end of the loaded modules */
319     mutex_lock(&loaded_modules_mutex);
320     for (tmp = loaded_modules ; tmp && tmp->next; tmp = tmp->next)
321         continue;
322     if (tmp)
323         tmp->next = *record;
324     else
325         loaded_modules = *record;
326     mutex_unlock(&loaded_modules_mutex);
327
328     free(tblname);
329     return 1;
330 }
331
332 static int
333 do_load_dir(const char *dirname, const char *prefix, const char *suffix,
334             int reqsym, verto_ev_type reqtypes, module_record **record)
335 {
336     DIR *dir;
337     struct dirent *ent = NULL;
338
339     *record = NULL;
340     dir = opendir(dirname);
341     if (!dir)
342         return 0;
343
344
345     while ((ent = readdir(dir))) {
346         char *tmp = NULL;
347         int success;
348         size_t flen, slen;
349
350         flen = strlen(ent->d_name);
351         slen = strlen(suffix);
352
353         if (!strcmp(".", ent->d_name) || !strcmp("..", ent->d_name))
354             continue;
355         if (strstr(ent->d_name, prefix) != ent->d_name)
356             continue;
357         if (flen < slen || strcmp(ent->d_name + flen - slen, suffix))
358             continue;
359
360         tmp = string_aconcat(dirname, "/", ent->d_name);
361         if (!tmp)
362             continue;
363
364         success = do_load_file(tmp, reqsym, reqtypes, record);
365         free(tmp);
366         if (success)
367             break;
368         *record = NULL;
369     }
370
371     closedir(dir);
372     return *record != NULL;
373 }
374 #endif
375
376 static int
377 load_module(const char *impl, verto_ev_type reqtypes, module_record **record)
378 {
379     int success = 0;
380 #ifndef BUILTIN_MODULE
381     char *prefix = NULL;
382     char *suffix = NULL;
383     char *tmp = NULL;
384 #endif
385
386     /* Check the cache */
387     mutex_lock(&loaded_modules_mutex);
388     if (impl) {
389         for (*record = loaded_modules ; *record ; *record = (*record)->next) {
390             if ((strchr(impl, '/') && !strcmp(impl, (*record)->filename))
391                     || !strcmp(impl, (*record)->module->name)) {
392                 mutex_unlock(&loaded_modules_mutex);
393                 return 1;
394             }
395         }
396     } else if (loaded_modules) {
397         for (*record = loaded_modules ; *record ; *record = (*record)->next) {
398             if (reqtypes == VERTO_EV_TYPE_NONE
399                     || ((*record)->module->types & reqtypes) == reqtypes) {
400                 mutex_unlock(&loaded_modules_mutex);
401                 return 1;
402             }
403         }
404     }
405     mutex_unlock(&loaded_modules_mutex);
406
407 #ifndef BUILTIN_MODULE
408     if (!module_get_filename_for_symbol(verto_convert_module, &prefix))
409         return 0;
410
411     /* Example output:
412      *    prefix == /usr/lib/libverto-
413      *    impl == glib
414      *    suffix == .so.0
415      * Put them all together: /usr/lib/libverto-glib.so.0 */
416     tmp = strdup(prefix);
417     if (!tmp) {
418         free(prefix);
419         return 0;
420     }
421
422     suffix = basename(tmp);
423     suffix = strchr(suffix, '.');
424     if (!suffix || strlen(suffix) < 1 || !(suffix = strdup(suffix))) {
425         free(prefix);
426         free(tmp);
427         return 0;
428     }
429     strcpy(prefix + strlen(prefix) - strlen(suffix), "-");
430     free(tmp);
431
432     if (impl) {
433         /* Try to do a load by the path */
434         if (!success && strchr(impl, '/'))
435             success = do_load_file(impl, 0, reqtypes, record);
436         if (!success) {
437             /* Try to do a load by the name */
438             tmp = string_aconcat(prefix, impl, suffix);
439             if (tmp) {
440                 success = do_load_file(tmp, 0, reqtypes, record);
441                 free(tmp);
442             }
443         }
444     } else {
445         /* NULL was passed, so we will use the dirname of
446          * the prefix to try and find any possible plugins */
447         tmp = strdup(prefix);
448         if (tmp) {
449             char *dname = strdup(dirname(tmp));
450             free(tmp);
451
452             tmp = strdup(basename(prefix));
453             free(prefix);
454             prefix = tmp;
455
456             if (dname && prefix) {
457                 /* Attempt to find a module we are already linked to */
458                 success = do_load_dir(dname, prefix, suffix, 1, reqtypes,
459                                       record);
460                 if (!success) {
461 #ifdef DEFAULT_MODULE
462                     /* Attempt to find the default module */
463                     success = load_module(DEFAULT_MODULE, reqtypes, record);
464                     if (!success)
465 #endif /* DEFAULT_MODULE */
466                         /* Attempt to load any plugin (we're desperate) */
467                         success = do_load_dir(dname, prefix, suffix, 0,
468                                               reqtypes, record);
469                 }
470             }
471
472             free(dname);
473         }
474     }
475
476     free(suffix);
477     free(prefix);
478 #endif /* BUILTIN_MODULE */
479     return success;
480 }
481
482 static verto_ev *
483 make_ev(verto_ctx *ctx, verto_callback *callback,
484         verto_ev_type type, verto_ev_flag flags)
485 {
486     verto_ev *ev = NULL;
487
488     if (!ctx || !callback)
489         return NULL;
490
491     ev = vresize(NULL, sizeof(verto_ev));
492     if (ev) {
493         memset(ev, 0, sizeof(verto_ev));
494         ev->ctx        = ctx;
495         ev->type       = type;
496         ev->callback   = callback;
497         ev->flags      = flags;
498     }
499
500     return ev;
501 }
502
503 static void
504 push_ev(verto_ctx *ctx, verto_ev *ev)
505 {
506     verto_ev *tmp;
507
508     if (!ctx || !ev)
509         return;
510
511     tmp = ctx->events;
512     ctx->events = ev;
513     ctx->events->next = tmp;
514 }
515
516 static void
517 remove_ev(verto_ev **origin, verto_ev *item)
518 {
519     if (!origin || !*origin || !item)
520         return;
521
522     if (*origin == item)
523         *origin = (*origin)->next;
524     else
525         remove_ev(&((*origin)->next), item);
526 }
527
528 static void
529 signal_ignore(verto_ctx *ctx, verto_ev *ev)
530 {
531     (void) ctx;
532     (void) ev;
533 }
534
535 verto_ctx *
536 verto_new(const char *impl, verto_ev_type reqtypes)
537 {
538     module_record *mr = NULL;
539
540     if (!load_module(impl, reqtypes, &mr))
541         return NULL;
542
543     return verto_convert_module(mr->module, 0, NULL);
544 }
545
546 verto_ctx *
547 verto_default(const char *impl, verto_ev_type reqtypes)
548 {
549     module_record *mr = NULL;
550
551     if (!load_module(impl, reqtypes, &mr))
552         return NULL;
553
554     return verto_convert_module(mr->module, 1, NULL);
555 }
556
557 int
558 verto_set_default(const char *impl, verto_ev_type reqtypes)
559 {
560     module_record *mr;
561
562     mutex_lock(&loaded_modules_mutex);
563     if (loaded_modules || !impl) {
564         mutex_unlock(&loaded_modules_mutex);
565         return 0;
566     }
567     mutex_unlock(&loaded_modules_mutex);
568
569     return load_module(impl, reqtypes, &mr);
570 }
571
572 int
573 verto_set_allocator(void *(*resize)(void *mem, size_t size),
574                     int hierarchical)
575 {
576     if (resize_cb || !resize)
577         return 0;
578     resize_cb = resize;
579     resize_cb_hierarchical = hierarchical;
580     return 1;
581 }
582
583 void
584 verto_free(verto_ctx *ctx)
585 {
586     if (!ctx)
587         return;
588
589     ctx->ref = ctx->ref > 0 ? ctx->ref - 1 : 0;
590     if (ctx->ref > 0)
591         return;
592
593     /* Cancel all pending events */
594     while (ctx->events)
595         verto_del(ctx->events);
596
597     /* Free the private */
598     if (!ctx->deflt || !ctx->module->funcs->ctx_default)
599         ctx->module->funcs->ctx_free(ctx->ctx);
600
601     vfree(ctx);
602 }
603
604 void
605 verto_cleanup(void)
606 {
607     module_record *record;
608
609     mutex_lock(&loaded_modules_mutex);
610
611     for (record = loaded_modules; record; record = record->next) {
612         module_close(record->dll);
613         free(record->filename);
614     }
615
616     vfree(loaded_modules);
617     loaded_modules = NULL;
618
619     mutex_unlock(&loaded_modules_mutex);
620     mutex_destroy(&loaded_modules_mutex);
621 }
622
623 void
624 verto_run(verto_ctx *ctx)
625 {
626     if (!ctx)
627         return;
628
629     if (ctx->module->funcs->ctx_break && ctx->module->funcs->ctx_run)
630         ctx->module->funcs->ctx_run(ctx->ctx);
631     else {
632         while (!ctx->exit)
633             ctx->module->funcs->ctx_run_once(ctx->ctx);
634         ctx->exit = 0;
635     }
636 }
637
638 void
639 verto_run_once(verto_ctx *ctx)
640 {
641     if (!ctx)
642         return;
643     ctx->module->funcs->ctx_run_once(ctx->ctx);
644 }
645
646 void
647 verto_break(verto_ctx *ctx)
648 {
649     if (!ctx)
650         return;
651
652     if (ctx->module->funcs->ctx_break && ctx->module->funcs->ctx_run)
653         ctx->module->funcs->ctx_break(ctx->ctx);
654     else
655         ctx->exit = 1;
656 }
657
658 int
659 verto_reinitialize(verto_ctx *ctx)
660 {
661     verto_ev *tmp, *next;
662     int error = 1;
663
664     if (!ctx)
665         return 0;
666
667     /* Delete all events, but keep around the forkable ev structs */
668     for (tmp = ctx->events; tmp; tmp = next) {
669         next = tmp->next;
670
671         if (tmp->flags & VERTO_EV_FLAG_REINITIABLE)
672             ctx->module->funcs->ctx_del(ctx->ctx, tmp, tmp->ev);
673         else
674             verto_del(tmp);
675     }
676
677     /* Reinit the loop */
678     if (ctx->module->funcs->ctx_reinitialize)
679         ctx->module->funcs->ctx_reinitialize(ctx->ctx);
680
681     /* Recreate events that were marked forkable */
682     for (tmp = ctx->events; tmp; tmp = tmp->next) {
683         tmp->actual = make_actual(tmp->flags);
684         tmp->ev = ctx->module->funcs->ctx_add(ctx->ctx, tmp, &tmp->actual);
685         if (!tmp->ev)
686             error = 0;
687     }
688
689     return error;
690 }
691
692 #define doadd(ev, set, type) \
693     ev = make_ev(ctx, callback, type, flags); \
694     if (ev) { \
695         set; \
696         ev->actual = make_actual(ev->flags); \
697         ev->ev = ctx->module->funcs->ctx_add(ctx->ctx, ev, &ev->actual); \
698         if (!ev->ev) { \
699             vfree(ev); \
700             return NULL; \
701         } \
702         push_ev(ctx, ev); \
703     }
704
705 verto_ev *
706 verto_add_io(verto_ctx *ctx, verto_ev_flag flags,
707              verto_callback *callback, int fd)
708 {
709     verto_ev *ev;
710
711     if (fd < 0 || !(flags & (VERTO_EV_FLAG_IO_READ | VERTO_EV_FLAG_IO_WRITE)))
712         return NULL;
713
714     doadd(ev, ev->option.io.fd = fd, VERTO_EV_TYPE_IO);
715     return ev;
716 }
717
718 verto_ev *
719 verto_add_timeout(verto_ctx *ctx, verto_ev_flag flags,
720                   verto_callback *callback, time_t interval)
721 {
722     verto_ev *ev;
723     doadd(ev, ev->option.interval = interval, VERTO_EV_TYPE_TIMEOUT);
724     return ev;
725 }
726
727 verto_ev *
728 verto_add_idle(verto_ctx *ctx, verto_ev_flag flags,
729                verto_callback *callback)
730 {
731     verto_ev *ev;
732     doadd(ev,, VERTO_EV_TYPE_IDLE);
733     return ev;
734 }
735
736 verto_ev *
737 verto_add_signal(verto_ctx *ctx, verto_ev_flag flags,
738                  verto_callback *callback, int signal)
739 {
740     verto_ev *ev;
741
742     if (signal < 0)
743         return NULL;
744 #ifndef WIN32
745     if (signal == SIGCHLD)
746         return NULL;
747 #endif
748     if (callback == VERTO_SIG_IGN) {
749         callback = signal_ignore;
750         if (!(flags & VERTO_EV_FLAG_PERSIST))
751             return NULL;
752     }
753     doadd(ev, ev->option.signal = signal, VERTO_EV_TYPE_SIGNAL);
754     return ev;
755 }
756
757 verto_ev *
758 verto_add_child(verto_ctx *ctx, verto_ev_flag flags,
759                 verto_callback *callback, verto_proc proc)
760 {
761     verto_ev *ev;
762
763     if (flags & VERTO_EV_FLAG_PERSIST) /* persist makes no sense */
764         return NULL;
765 #ifdef WIN32
766     if (proc == NULL)
767 #else
768     if (proc < 1)
769 #endif
770         return NULL;
771     doadd(ev, ev->option.child.proc = proc, VERTO_EV_TYPE_CHILD);
772     return ev;
773 }
774
775 void
776 verto_set_private(verto_ev *ev, void *priv, verto_callback *free)
777 {
778     if (!ev)
779         return;
780     if (ev->onfree && free)
781         ev->onfree(ev->ctx, ev);
782     ev->priv = priv;
783     ev->onfree = free;
784 }
785
786 void *
787 verto_get_private(const verto_ev *ev)
788 {
789     return ev->priv;
790 }
791
792 verto_ev_type
793 verto_get_type(const verto_ev *ev)
794 {
795     return ev->type;
796 }
797
798 verto_ev_flag
799 verto_get_flags(const verto_ev *ev)
800 {
801     return ev->flags;
802 }
803
804 void
805 verto_set_flags(verto_ev *ev, verto_ev_flag flags)
806 {
807     if (!ev)
808         return;
809
810     /* No modification is needed, so do nothing. */
811     if (MUTABLE(ev->flags) == MUTABLE(flags))
812         return;
813
814     ev->flags  &= ~_VERTO_EV_FLAG_MUTABLE_MASK;
815     ev->flags  |= MUTABLE(flags);
816
817     /* If setting flags isn't supported, just rebuild the event */
818     if (!ev->ctx->module->funcs->ctx_set_flags) {
819         ev->ctx->module->funcs->ctx_del(ev->ctx->ctx, ev, ev->ev);
820         ev->actual = make_actual(ev->flags);
821         ev->ev = ev->ctx->module->funcs->ctx_add(ev->ctx->ctx, ev, &ev->actual);
822         assert(ev->ev); /* Here is the main reason why modules should */
823         return;         /* implement set_flags(): we cannot fail gracefully. */
824     }
825
826     ev->actual &= ~_VERTO_EV_FLAG_MUTABLE_MASK;
827     ev->actual |= MUTABLE(flags);
828     ev->ctx->module->funcs->ctx_set_flags(ev->ctx->ctx, ev, ev->ev);
829 }
830
831 int
832 verto_get_fd(const verto_ev *ev)
833 {
834     if (ev && (ev->type == VERTO_EV_TYPE_IO))
835         return ev->option.io.fd;
836     return -1;
837 }
838
839 verto_ev_flag
840 verto_get_fd_state(const verto_ev *ev)
841 {
842     return ev->option.io.state;
843 }
844
845 time_t
846 verto_get_interval(const verto_ev *ev)
847 {
848     if (ev && (ev->type == VERTO_EV_TYPE_TIMEOUT))
849         return ev->option.interval;
850     return 0;
851 }
852
853 int
854 verto_get_signal(const verto_ev *ev)
855 {
856     if (ev && (ev->type == VERTO_EV_TYPE_SIGNAL))
857         return ev->option.signal;
858     return -1;
859 }
860
861 verto_proc
862 verto_get_proc(const verto_ev *ev) {
863     if (ev && ev->type == VERTO_EV_TYPE_CHILD)
864         return ev->option.child.proc;
865     return (verto_proc) 0;
866 }
867
868 verto_proc_status
869 verto_get_proc_status(const verto_ev *ev)
870 {
871     return ev->option.child.status;
872 }
873
874 verto_ctx *
875 verto_get_ctx(const verto_ev *ev)
876 {
877     return ev->ctx;
878 }
879
880 void
881 verto_del(verto_ev *ev)
882 {
883     if (!ev)
884         return;
885
886     /* If the event is freed in the callback, we just set a flag so that
887      * verto_fire() can actually do the delete when the callback completes.
888      *
889      * If we don't do this, than verto_fire() will access freed memory. */
890     if (ev->depth > 0) {
891         ev->deleted = 1;
892         return;
893     }
894
895     if (ev->onfree)
896         ev->onfree(ev->ctx, ev);
897     ev->ctx->module->funcs->ctx_del(ev->ctx->ctx, ev, ev->ev);
898     remove_ev(&(ev->ctx->events), ev);
899
900     if ((ev->type == VERTO_EV_TYPE_IO) &&
901         (ev->flags & VERTO_EV_FLAG_IO_CLOSE_FD) &&
902         !(ev->actual & VERTO_EV_FLAG_IO_CLOSE_FD))
903         close(ev->option.io.fd);
904
905     vfree(ev);
906 }
907
908 verto_ev_type
909 verto_get_supported_types(verto_ctx *ctx)
910 {
911     return ctx->module->types;
912 }
913
914 /*** THE FOLLOWING ARE FOR IMPLEMENTATION MODULES ONLY ***/
915
916 verto_ctx *
917 verto_convert_module(const verto_module *module, int deflt, verto_mod_ctx *mctx)
918 {
919     verto_ctx *ctx = NULL;
920     module_record *mr;
921
922     if (!module)
923         return NULL;
924
925     if (deflt) {
926         mutex_lock(&loaded_modules_mutex);
927         for (mr = loaded_modules ; mr ; mr = mr->next) {
928             verto_ctx *tmp;
929             if (mr->module == module && mr->defctx) {
930                 if (mctx)
931                     module->funcs->ctx_free(mctx);
932                 tmp = mr->defctx;
933                 tmp->ref++;
934                 mutex_unlock(&loaded_modules_mutex);
935                 return tmp;
936             }
937         }
938         mutex_unlock(&loaded_modules_mutex);
939     }
940
941     if (!mctx) {
942         mctx = deflt
943                     ? (module->funcs->ctx_default
944                         ? module->funcs->ctx_default()
945                         : module->funcs->ctx_new())
946                     : module->funcs->ctx_new();
947         if (!mctx)
948             goto error;
949     }
950
951     ctx = vresize(NULL, sizeof(verto_ctx));
952     if (!ctx)
953         goto error;
954     memset(ctx, 0, sizeof(verto_ctx));
955
956     ctx->ref = 1;
957     ctx->ctx = mctx;
958     ctx->module = module;
959     ctx->deflt = deflt;
960
961     if (deflt) {
962         module_record **tmp;
963
964         mutex_lock(&loaded_modules_mutex);
965         tmp = &loaded_modules;
966         for (mr = loaded_modules ; mr ; mr = mr->next) {
967             if (mr->module == module) {
968                 assert(mr->defctx == NULL);
969                 mr->defctx = ctx;
970                 mutex_unlock(&loaded_modules_mutex);
971                 return ctx;
972             }
973
974             if (!mr->next) {
975                 tmp = &mr->next;
976                 break;
977             }
978         }
979         mutex_unlock(&loaded_modules_mutex);
980
981         *tmp = vresize(NULL, sizeof(module_record));
982         if (!*tmp) {
983             vfree(ctx);
984             goto error;
985         }
986
987         memset(*tmp, 0, sizeof(module_record));
988         (*tmp)->defctx = ctx;
989         (*tmp)->module = module;
990     }
991
992     return ctx;
993
994 error:
995     if (mctx)
996         module->funcs->ctx_free(mctx);
997     return NULL;
998 }
999
1000 void
1001 verto_fire(verto_ev *ev)
1002 {
1003     void *priv;
1004
1005     ev->depth++;
1006     ev->callback(ev->ctx, ev);
1007     ev->depth--;
1008
1009     if (ev->depth == 0) {
1010         if (!(ev->flags & VERTO_EV_FLAG_PERSIST) || ev->deleted)
1011             verto_del(ev);
1012         else {
1013             if (!(ev->actual & VERTO_EV_FLAG_PERSIST)) {
1014                 ev->actual = make_actual(ev->flags);
1015                 priv = ev->ctx->module->funcs->ctx_add(ev->ctx->ctx, ev, &ev->actual);
1016                 assert(priv); /* TODO: create an error callback */
1017                 ev->ctx->module->funcs->ctx_del(ev->ctx->ctx, ev, ev->ev);
1018                 ev->ev = priv;
1019             }
1020
1021             if (ev->type == VERTO_EV_TYPE_IO)
1022                 ev->option.io.state = VERTO_EV_FLAG_NONE;
1023             if (ev->type == VERTO_EV_TYPE_CHILD)
1024                 ev->option.child.status = 0;
1025         }
1026     }
1027 }
1028
1029 void
1030 verto_set_proc_status(verto_ev *ev, verto_proc_status status)
1031 {
1032     if (ev && ev->type == VERTO_EV_TYPE_CHILD)
1033         ev->option.child.status = status;
1034 }
1035
1036 void
1037 verto_set_fd_state(verto_ev *ev, verto_ev_flag state)
1038 {
1039     /* Filter out only the io flags */
1040     state = state & (VERTO_EV_FLAG_IO_READ |
1041                      VERTO_EV_FLAG_IO_WRITE |
1042                      VERTO_EV_FLAG_IO_ERROR);
1043
1044     /* Don't report read/write if the socket is closed */
1045     if (state & VERTO_EV_FLAG_IO_ERROR)
1046         state = VERTO_EV_FLAG_IO_ERROR;
1047
1048     if (ev && ev->type == VERTO_EV_TYPE_IO)
1049         ev->option.io.state = state;
1050 }