Imported Upstream version 1.15.1
[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 #define _GNU_SOURCE /* For asprintf() */
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <signal.h>
31 #include <assert.h>
32 #include <stdarg.h>
33
34 #include <libgen.h>
35 #include <sys/types.h>
36 #include <dirent.h>
37
38 #ifdef HAVE_PTHREAD
39 #include <pthread.h>
40 #endif
41
42 #include <verto-module.h>
43 #include "module.h"
44
45 #define  _str(s) # s
46 #define __str(s) _str(s)
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 verto_module_table_<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 #define mutex_lock(x) pthread_mutex_lock(x)
123 #define mutex_unlock(x) pthread_mutex_unlock(x)
124 #else
125 #define mutex_lock(x)
126 #define mutex_unlock(x)
127 #endif
128
129 #define vfree(mem) vresize(mem, 0)
130 static void *
131 vresize(void *mem, size_t size)
132 {
133     if (!resize_cb)
134         resize_cb = &realloc;
135     return (*resize_cb)(mem, size);
136 }
137
138 #ifndef BUILTIN_MODULE
139 static int
140 int_vasprintf(char **strp, const char *fmt, va_list ap) {
141     va_list apc;
142     int size = 0;
143
144     va_copy(apc, ap);
145     size = vsnprintf(NULL, 0, fmt, apc);
146     va_end(apc);
147
148     if (size <= 0 || !(*strp = malloc(size + 1)))
149         return -1;
150
151     return vsnprintf(*strp, size + 1, fmt, ap);
152 }
153
154 static int
155 int_asprintf(char **strp, const char *fmt, ...) {
156     va_list ap;
157     int size = 0;
158
159     va_start(ap, fmt);
160     size = int_vasprintf(strp, fmt, ap);
161     va_end(ap);
162     return size;
163 }
164
165 static char *
166 int_get_table_name_from_filename(const char *filename)
167 {
168     char *bn = NULL, *tmp = NULL;
169
170     if (!filename)
171         return NULL;
172
173     tmp = strdup(filename);
174     if (!tmp)
175         return NULL;
176
177     bn = basename(tmp);
178     if (bn)
179         bn = strdup(bn);
180     free(tmp);
181     if (!bn)
182         return NULL;
183
184     tmp = strchr(bn, '-');
185     if (tmp) {
186         if (strchr(tmp+1, '.')) {
187             *strchr(tmp+1, '.') = '\0';
188             if (int_asprintf(&tmp, "%s%s", __str(VERTO_MODULE_TABLE()), tmp + 1) < 0)
189                 tmp = NULL;
190         } else
191             tmp = NULL;
192     }
193
194     free(bn);
195     return tmp;
196 }
197
198 typedef struct {
199     int reqsym;
200     verto_ev_type reqtypes;
201 } shouldload_data;
202
203 static int
204 shouldload(void *symb, void *misc, char **err)
205 {
206     verto_module *table = (verto_module*) symb;
207     shouldload_data *data = (shouldload_data*) misc;
208
209     /* Make sure we have the proper version */
210     if (table->vers != VERTO_MODULE_VERSION) {
211         if (err)
212             *err = strdup("Invalid module version!");
213         return 0;
214     }
215
216     /* Check to make sure that we have our required symbol if reqsym == true */
217     if (table->symb && data->reqsym
218             && !module_symbol_is_present(NULL, table->symb)) {
219         if (err)
220             int_asprintf(err, "Symbol not found: %s!", table->symb);
221         return 0;
222     }
223
224     /* Check to make sure that this module supports our required features */
225     if (data->reqtypes != VERTO_EV_TYPE_NONE
226             && (table->types & data->reqtypes) != data->reqtypes) {
227         if (err)
228             *err = strdup("Module does not support required features!");
229         return 0;
230     }
231
232     return 1;
233 }
234
235 static int
236 do_load_file(const char *filename, int reqsym, verto_ev_type reqtypes,
237              module_record **record)
238 {
239     char *tblname = NULL, *error = NULL;
240     module_record *tmp;
241     shouldload_data data  = { reqsym, reqtypes };
242
243     /* Check the loaded modules to see if we already loaded one */
244     mutex_lock(&loaded_modules_mutex);
245     for (*record = loaded_modules ; *record ; *record = (*record)->next) {
246         if (!strcmp((*record)->filename, filename)) {
247             mutex_unlock(&loaded_modules_mutex);
248             return 1;
249         }
250     }
251     mutex_unlock(&loaded_modules_mutex);
252
253     /* Create our module record */
254     tmp = *record = vresize(NULL, sizeof(module_record));
255     if (!tmp)
256         return 0;
257     memset(tmp, 0, sizeof(module_record));
258     tmp->filename = strdup(filename);
259     if (!tmp->filename) {
260         vfree(tmp);
261         return 0;
262     }
263
264     /* Get the name of the module struct in the library */
265     tblname = int_get_table_name_from_filename(filename);
266     if (!tblname) {
267         free(tblname);
268         vfree(tmp);
269         return 0;
270     }
271
272     /* Load the module */
273     error = module_load(filename, tblname, shouldload, &data, &tmp->dll,
274                         (void **) &tmp->module);
275     if (error || !tmp->dll || !tmp->module) {
276         /*if (error)
277             fprintf(stderr, "%s\n", error);*/
278         free(error);
279         module_close(tmp->dll);
280         free(tblname);
281         vfree(tmp);
282         return 0;
283     }
284
285     /* Append the new module to the end of the loaded modules */
286     mutex_lock(&loaded_modules_mutex);
287     for (tmp = loaded_modules ; tmp && tmp->next; tmp = tmp->next)
288         continue;
289     if (tmp)
290         tmp->next = *record;
291     else
292         loaded_modules = *record;
293     mutex_unlock(&loaded_modules_mutex);
294
295     free(tblname);
296     return 1;
297 }
298
299 static int
300 do_load_dir(const char *dirname, const char *prefix, const char *suffix,
301             int reqsym, verto_ev_type reqtypes, module_record **record)
302 {
303     DIR *dir;
304     struct dirent *ent = NULL;
305
306     *record = NULL;
307     dir = opendir(dirname);
308     if (!dir)
309         return 0;
310
311
312     while ((ent = readdir(dir))) {
313         char *tmp = NULL;
314         int success;
315         size_t flen, slen;
316
317         flen = strlen(ent->d_name);
318         slen = strlen(suffix);
319
320         if (!strcmp(".", ent->d_name) || !strcmp("..", ent->d_name))
321             continue;
322         if (strstr(ent->d_name, prefix) != ent->d_name)
323             continue;
324         if (flen < slen || strcmp(ent->d_name + flen - slen, suffix))
325             continue;
326
327         if (int_asprintf(&tmp, "%s/%s", dirname, ent->d_name) < 0)
328             continue;
329
330         success = do_load_file(tmp, reqsym, reqtypes, record);
331         free(tmp);
332         if (success)
333             break;
334         *record = NULL;
335     }
336
337     closedir(dir);
338     return *record != NULL;
339 }
340 #endif
341
342 static int
343 load_module(const char *impl, verto_ev_type reqtypes, module_record **record)
344 {
345     int success = 0;
346 #ifndef BUILTIN_MODULE
347     char *prefix = NULL;
348     char *suffix = NULL;
349     char *tmp = NULL;
350 #endif
351
352     /* Check the cache */
353     mutex_lock(&loaded_modules_mutex);
354     if (impl) {
355         for (*record = loaded_modules ; *record ; *record = (*record)->next) {
356             if ((strchr(impl, '/') && !strcmp(impl, (*record)->filename))
357                     || !strcmp(impl, (*record)->module->name)) {
358                 mutex_unlock(&loaded_modules_mutex);
359                 return 1;
360             }
361         }
362     } else if (loaded_modules) {
363         for (*record = loaded_modules ; *record ; *record = (*record)->next) {
364             if (reqtypes == VERTO_EV_TYPE_NONE
365                     || ((*record)->module->types & reqtypes) == reqtypes) {
366                 mutex_unlock(&loaded_modules_mutex);
367                 return 1;
368             }
369         }
370     }
371     mutex_unlock(&loaded_modules_mutex);
372
373 #ifndef BUILTIN_MODULE
374     if (!module_get_filename_for_symbol(verto_convert_module, &prefix))
375         return 0;
376
377     /* Example output:
378      *    prefix == /usr/lib/libverto-
379      *    impl == glib
380      *    suffix == .so.0
381      * Put them all together: /usr/lib/libverto-glib.so.0 */
382     tmp = strdup(prefix);
383     if (!tmp) {
384         free(prefix);
385         return 0;
386     }
387
388     suffix = basename(tmp);
389     suffix = strchr(suffix, '.');
390     if (!suffix || strlen(suffix) < 1 || !(suffix = strdup(suffix))) {
391         free(prefix);
392         free(tmp);
393         return 0;
394     }
395     strcpy(prefix + strlen(prefix) - strlen(suffix), "-");
396     free(tmp);
397
398     if (impl) {
399         /* Try to do a load by the path */
400         if (!success && strchr(impl, '/'))
401             success = do_load_file(impl, 0, reqtypes, record);
402         if (!success) {
403             /* Try to do a load by the name */
404             tmp = NULL;
405             if (int_asprintf(&tmp, "%s%s%s", prefix, impl, suffix) > 0) {
406                 success = do_load_file(tmp, 0, reqtypes, record);
407                 free(tmp);
408             }
409         }
410     } else {
411         /* NULL was passed, so we will use the dirname of
412          * the prefix to try and find any possible plugins */
413         tmp = strdup(prefix);
414         if (tmp) {
415             char *dname = strdup(dirname(tmp));
416             free(tmp);
417
418             tmp = strdup(basename(prefix));
419             free(prefix);
420             prefix = tmp;
421
422             if (dname && prefix) {
423                 /* Attempt to find a module we are already linked to */
424                 success = do_load_dir(dname, prefix, suffix, 1, reqtypes,
425                                       record);
426                 if (!success) {
427 #ifdef DEFAULT_MODULE
428                     /* Attempt to find the default module */
429                     success = load_module(DEFAULT_MODULE, reqtypes, record);
430                     if (!success)
431 #endif /* DEFAULT_MODULE */
432                         /* Attempt to load any plugin (we're desperate) */
433                         success = do_load_dir(dname, prefix, suffix, 0,
434                                               reqtypes, record);
435                 }
436             }
437
438             free(dname);
439         }
440     }
441
442     free(suffix);
443     free(prefix);
444 #endif /* BUILTIN_MODULE */
445     return success;
446 }
447
448 static verto_ev *
449 make_ev(verto_ctx *ctx, verto_callback *callback,
450         verto_ev_type type, verto_ev_flag flags)
451 {
452     verto_ev *ev = NULL;
453
454     if (!ctx || !callback)
455         return NULL;
456
457     ev = vresize(NULL, sizeof(verto_ev));
458     if (ev) {
459         memset(ev, 0, sizeof(verto_ev));
460         ev->ctx        = ctx;
461         ev->type       = type;
462         ev->callback   = callback;
463         ev->flags      = flags;
464     }
465
466     return ev;
467 }
468
469 static void
470 push_ev(verto_ctx *ctx, verto_ev *ev)
471 {
472     verto_ev *tmp;
473
474     if (!ctx || !ev)
475         return;
476
477     tmp = ctx->events;
478     ctx->events = ev;
479     ctx->events->next = tmp;
480 }
481
482 static void
483 remove_ev(verto_ev **origin, verto_ev *item)
484 {
485     if (!origin || !*origin || !item)
486         return;
487
488     if (*origin == item)
489         *origin = (*origin)->next;
490     else
491         remove_ev(&((*origin)->next), item);
492 }
493
494 static void
495 signal_ignore(verto_ctx *ctx, verto_ev *ev)
496 {
497 }
498
499 verto_ctx *
500 verto_new(const char *impl, verto_ev_type reqtypes)
501 {
502     module_record *mr = NULL;
503
504     if (!load_module(impl, reqtypes, &mr))
505         return NULL;
506
507     return verto_convert_module(mr->module, 0, NULL);
508 }
509
510 verto_ctx *
511 verto_default(const char *impl, verto_ev_type reqtypes)
512 {
513     module_record *mr = NULL;
514
515     if (!load_module(impl, reqtypes, &mr))
516         return NULL;
517
518     return verto_convert_module(mr->module, 1, NULL);
519 }
520
521 int
522 verto_set_default(const char *impl, verto_ev_type reqtypes)
523 {
524     module_record *mr;
525
526     mutex_lock(&loaded_modules_mutex);
527     if (loaded_modules || !impl) {
528         mutex_unlock(&loaded_modules_mutex);
529         return 0;
530     }
531     mutex_unlock(&loaded_modules_mutex);
532
533     return load_module(impl, reqtypes, &mr);
534 }
535
536 int
537 verto_set_allocator(void *(*resize)(void *mem, size_t size),
538                     int hierarchical)
539 {
540     if (resize_cb || !resize)
541         return 0;
542     resize_cb = resize;
543     resize_cb_hierarchical = hierarchical;
544     return 1;
545 }
546
547 void
548 verto_free(verto_ctx *ctx)
549 {
550     if (!ctx)
551         return;
552
553     ctx->ref = ctx->ref > 0 ? ctx->ref - 1 : 0;
554     if (ctx->ref > 0)
555         return;
556
557     /* Cancel all pending events */
558     while (ctx->events)
559         verto_del(ctx->events);
560
561     /* Free the private */
562     if (!ctx->deflt || !ctx->module->funcs->ctx_default)
563         ctx->module->funcs->ctx_free(ctx->ctx);
564
565     vfree(ctx);
566 }
567
568 void
569 verto_run(verto_ctx *ctx)
570 {
571     if (!ctx)
572         return;
573
574     if (ctx->module->funcs->ctx_break && ctx->module->funcs->ctx_run)
575         ctx->module->funcs->ctx_run(ctx->ctx);
576     else {
577         while (!ctx->exit)
578             ctx->module->funcs->ctx_run_once(ctx->ctx);
579         ctx->exit = 0;
580     }
581 }
582
583 void
584 verto_run_once(verto_ctx *ctx)
585 {
586     if (!ctx)
587         return;
588     ctx->module->funcs->ctx_run_once(ctx->ctx);
589 }
590
591 void
592 verto_break(verto_ctx *ctx)
593 {
594     if (!ctx)
595         return;
596
597     if (ctx->module->funcs->ctx_break && ctx->module->funcs->ctx_run)
598         ctx->module->funcs->ctx_break(ctx->ctx);
599     else
600         ctx->exit = 1;
601 }
602
603 int
604 verto_reinitialize(verto_ctx *ctx)
605 {
606     verto_ev *tmp, *next;
607     int error = 1;
608
609     if (!ctx)
610         return 0;
611
612     /* Delete all events, but keep around the forkable ev structs */
613     for (tmp = ctx->events; tmp; tmp = next) {
614         next = tmp->next;
615
616         if (tmp->flags & VERTO_EV_FLAG_REINITIABLE)
617             ctx->module->funcs->ctx_del(ctx->ctx, tmp, tmp->ev);
618         else
619             verto_del(tmp);
620     }
621
622     /* Reinit the loop */
623     if (ctx->module->funcs->ctx_reinitialize)
624         ctx->module->funcs->ctx_reinitialize(ctx->ctx);
625
626     /* Recreate events that were marked forkable */
627     for (tmp = ctx->events; tmp; tmp = tmp->next) {
628         tmp->actual = make_actual(tmp->flags);
629         tmp->ev = ctx->module->funcs->ctx_add(ctx->ctx, tmp, &tmp->actual);
630         if (!tmp->ev)
631             error = 0;
632     }
633
634     return error;
635 }
636
637 #define doadd(ev, set, type) \
638     ev = make_ev(ctx, callback, type, flags); \
639     if (ev) { \
640         set; \
641         ev->actual = make_actual(ev->flags); \
642         ev->ev = ctx->module->funcs->ctx_add(ctx->ctx, ev, &ev->actual); \
643         if (!ev->ev) { \
644             vfree(ev); \
645             return NULL; \
646         } \
647         push_ev(ctx, ev); \
648     }
649
650 verto_ev *
651 verto_add_io(verto_ctx *ctx, verto_ev_flag flags,
652              verto_callback *callback, int fd)
653 {
654     verto_ev *ev;
655
656     if (fd < 0 || !(flags & (VERTO_EV_FLAG_IO_READ | VERTO_EV_FLAG_IO_WRITE)))
657         return NULL;
658
659     doadd(ev, ev->option.io.fd = fd, VERTO_EV_TYPE_IO);
660     return ev;
661 }
662
663 verto_ev *
664 verto_add_timeout(verto_ctx *ctx, verto_ev_flag flags,
665                   verto_callback *callback, time_t interval)
666 {
667     verto_ev *ev;
668     doadd(ev, ev->option.interval = interval, VERTO_EV_TYPE_TIMEOUT);
669     return ev;
670 }
671
672 verto_ev *
673 verto_add_idle(verto_ctx *ctx, verto_ev_flag flags,
674                verto_callback *callback)
675 {
676     verto_ev *ev;
677     doadd(ev,, VERTO_EV_TYPE_IDLE);
678     return ev;
679 }
680
681 verto_ev *
682 verto_add_signal(verto_ctx *ctx, verto_ev_flag flags,
683                  verto_callback *callback, int signal)
684 {
685     verto_ev *ev;
686
687     if (signal < 0)
688         return NULL;
689 #ifndef WIN32
690     if (signal == SIGCHLD)
691         return NULL;
692 #endif
693     if (callback == VERTO_SIG_IGN) {
694         callback = signal_ignore;
695         if (!(flags & VERTO_EV_FLAG_PERSIST))
696             return NULL;
697     }
698     doadd(ev, ev->option.signal = signal, VERTO_EV_TYPE_SIGNAL);
699     return ev;
700 }
701
702 verto_ev *
703 verto_add_child(verto_ctx *ctx, verto_ev_flag flags,
704                 verto_callback *callback, verto_proc proc)
705 {
706     verto_ev *ev;
707
708     if (flags & VERTO_EV_FLAG_PERSIST) /* persist makes no sense */
709         return NULL;
710 #ifdef WIN32
711     if (proc == NULL)
712 #else
713     if (proc < 1)
714 #endif
715         return NULL;
716     doadd(ev, ev->option.child.proc = proc, VERTO_EV_TYPE_CHILD);
717     return ev;
718 }
719
720 void
721 verto_set_private(verto_ev *ev, void *priv, verto_callback *free)
722 {
723     if (!ev)
724         return;
725     if (ev->onfree && free)
726         ev->onfree(ev->ctx, ev);
727     ev->priv = priv;
728     ev->onfree = free;
729 }
730
731 void *
732 verto_get_private(const verto_ev *ev)
733 {
734     return ev->priv;
735 }
736
737 verto_ev_type
738 verto_get_type(const verto_ev *ev)
739 {
740     return ev->type;
741 }
742
743 verto_ev_flag
744 verto_get_flags(const verto_ev *ev)
745 {
746     return ev->flags;
747 }
748
749 void
750 verto_set_flags(verto_ev *ev, verto_ev_flag flags)
751 {
752     if (!ev)
753         return;
754
755     ev->flags  &= ~_VERTO_EV_FLAG_MUTABLE_MASK;
756     ev->flags  |= flags & _VERTO_EV_FLAG_MUTABLE_MASK;
757
758     /* If setting flags isn't supported, just rebuild the event */
759     if (!ev->ctx->module->funcs->ctx_set_flags) {
760         ev->ctx->module->funcs->ctx_del(ev->ctx->ctx, ev, ev->ev);
761         ev->actual = make_actual(ev->flags);
762         ev->ev = ev->ctx->module->funcs->ctx_add(ev->ctx->ctx, ev, &ev->actual);
763         assert(ev->ev); /* Here is the main reason why modules should */
764         return;         /* implement set_flags(): we cannot fail gracefully. */
765     }
766
767     ev->actual &= ~_VERTO_EV_FLAG_MUTABLE_MASK;
768     ev->actual |= flags & _VERTO_EV_FLAG_MUTABLE_MASK;
769     ev->ctx->module->funcs->ctx_set_flags(ev->ctx->ctx, ev, ev->ev);
770 }
771
772 int
773 verto_get_fd(const verto_ev *ev)
774 {
775     if (ev && (ev->type == VERTO_EV_TYPE_IO))
776         return ev->option.io.fd;
777     return -1;
778 }
779
780 verto_ev_flag
781 verto_get_fd_state(const verto_ev *ev)
782 {
783     return ev->option.io.state;
784 }
785
786 time_t
787 verto_get_interval(const verto_ev *ev)
788 {
789     if (ev && (ev->type == VERTO_EV_TYPE_TIMEOUT))
790         return ev->option.interval;
791     return 0;
792 }
793
794 int
795 verto_get_signal(const verto_ev *ev)
796 {
797     if (ev && (ev->type == VERTO_EV_TYPE_SIGNAL))
798         return ev->option.signal;
799     return -1;
800 }
801
802 verto_proc
803 verto_get_proc(const verto_ev *ev) {
804     if (ev && ev->type == VERTO_EV_TYPE_CHILD)
805         return ev->option.child.proc;
806     return (verto_proc) 0;
807 }
808
809 verto_proc_status
810 verto_get_proc_status(const verto_ev *ev)
811 {
812     return ev->option.child.status;
813 }
814
815 verto_ctx *
816 verto_get_ctx(const verto_ev *ev)
817 {
818     return ev->ctx;
819 }
820
821 void
822 verto_del(verto_ev *ev)
823 {
824     if (!ev)
825         return;
826
827     /* If the event is freed in the callback, we just set a flag so that
828      * verto_fire() can actually do the delete when the callback completes.
829      *
830      * If we don't do this, than verto_fire() will access freed memory. */
831     if (ev->depth > 0) {
832         ev->deleted = 1;
833         return;
834     }
835
836     if (ev->onfree)
837         ev->onfree(ev->ctx, ev);
838     ev->ctx->module->funcs->ctx_del(ev->ctx->ctx, ev, ev->ev);
839     remove_ev(&(ev->ctx->events), ev);
840
841     if ((ev->type == VERTO_EV_TYPE_IO) &&
842         (ev->flags & VERTO_EV_FLAG_IO_CLOSE_FD) &&
843         !(ev->actual & VERTO_EV_FLAG_IO_CLOSE_FD))
844         close(ev->option.io.fd);
845
846     vfree(ev);
847 }
848
849 verto_ev_type
850 verto_get_supported_types(verto_ctx *ctx)
851 {
852     return ctx->module->types;
853 }
854
855 /*** THE FOLLOWING ARE FOR IMPLEMENTATION MODULES ONLY ***/
856
857 verto_ctx *
858 verto_convert_module(const verto_module *module, int deflt, verto_mod_ctx *mctx)
859 {
860     verto_ctx *ctx = NULL;
861     module_record *mr;
862
863     if (!module)
864         goto error;
865
866     if (deflt) {
867         mutex_lock(&loaded_modules_mutex);
868         for (mr = loaded_modules ; mr ; mr = mr->next) {
869             verto_ctx *tmp;
870             if (mr->module == module && mr->defctx) {
871                 if (mctx)
872                     module->funcs->ctx_free(mctx);
873                 tmp = mr->defctx;
874                 tmp->ref++;
875                 mutex_unlock(&loaded_modules_mutex);
876                 return tmp;
877             }
878         }
879         mutex_unlock(&loaded_modules_mutex);
880     }
881
882     if (!mctx) {
883         mctx = deflt
884                     ? (module->funcs->ctx_default
885                         ? module->funcs->ctx_default()
886                         : module->funcs->ctx_new())
887                     : module->funcs->ctx_new();
888         if (!mctx)
889             goto error;
890     }
891
892     ctx = vresize(NULL, sizeof(verto_ctx));
893     if (!ctx)
894         goto error;
895     memset(ctx, 0, sizeof(verto_ctx));
896
897     ctx->ref = 1;
898     ctx->ctx = mctx;
899     ctx->module = module;
900     ctx->deflt = deflt;
901
902     if (deflt) {
903         module_record **tmp;
904
905         mutex_lock(&loaded_modules_mutex);
906         tmp = &loaded_modules;
907         for (mr = loaded_modules ; mr ; mr = mr->next) {
908             if (mr->module == module) {
909                 assert(mr->defctx == NULL);
910                 mr->defctx = ctx;
911                 mutex_unlock(&loaded_modules_mutex);
912                 return ctx;
913             }
914
915             if (!mr->next) {
916                 tmp = &mr->next;
917                 break;
918             }
919         }
920         mutex_unlock(&loaded_modules_mutex);
921
922         *tmp = vresize(NULL, sizeof(module_record));
923         if (!*tmp) {
924             vfree(ctx);
925             goto error;
926         }
927
928         memset(*tmp, 0, sizeof(module_record));
929         (*tmp)->defctx = ctx;
930         (*tmp)->module = module;
931     }
932
933     return ctx;
934
935 error:
936     if (mctx)
937         module->funcs->ctx_free(mctx);
938     return NULL;
939 }
940
941 void
942 verto_fire(verto_ev *ev)
943 {
944     void *priv;
945
946     ev->depth++;
947     ev->callback(ev->ctx, ev);
948     ev->depth--;
949
950     if (ev->depth == 0) {
951         if (!(ev->flags & VERTO_EV_FLAG_PERSIST) || ev->deleted)
952             verto_del(ev);
953         else {
954             if (!(ev->actual & VERTO_EV_FLAG_PERSIST)) {
955                 ev->actual = make_actual(ev->flags);
956                 priv = ev->ctx->module->funcs->ctx_add(ev->ctx->ctx, ev, &ev->actual);
957                 assert(priv); /* TODO: create an error callback */
958                 ev->ctx->module->funcs->ctx_del(ev->ctx->ctx, ev, ev->ev);
959                 ev->ev = priv;
960             }
961
962             if (ev->type == VERTO_EV_TYPE_IO)
963                 ev->option.io.state = VERTO_EV_FLAG_NONE;
964             if (ev->type == VERTO_EV_TYPE_CHILD)
965                 ev->option.child.status = 0;
966         }
967     }
968 }
969
970 void
971 verto_set_proc_status(verto_ev *ev, verto_proc_status status)
972 {
973     if (ev && ev->type == VERTO_EV_TYPE_CHILD)
974         ev->option.child.status = status;
975 }
976
977 void
978 verto_set_fd_state(verto_ev *ev, verto_ev_flag state)
979 {
980     /* Filter out only the io flags */
981     state = state & (VERTO_EV_FLAG_IO_READ |
982                      VERTO_EV_FLAG_IO_WRITE |
983                      VERTO_EV_FLAG_IO_ERROR);
984
985     /* Don't report read/write if the socket is closed */
986     if (state & VERTO_EV_FLAG_IO_ERROR)
987         state = VERTO_EV_FLAG_IO_ERROR;
988
989     if (ev && ev->type == VERTO_EV_TYPE_IO)
990         ev->option.io.state = state;
991 }