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 *
vresize(void * mem,size_t size)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 *
string_aconcat(const char * first,const char * second,const char * third)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 *
int_get_table_name_from_filename(const char * filename)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
shouldload(void * symb,void * misc,char ** err)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
do_load_file(const char * filename,int reqsym,verto_ev_type reqtypes,module_record ** record)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
do_load_dir(const char * dirname,const char * prefix,const char * suffix,int reqsym,verto_ev_type reqtypes,module_record ** record)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
load_module(const char * impl,verto_ev_type reqtypes,module_record ** record)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 *
make_ev(verto_ctx * ctx,verto_callback * callback,verto_ev_type type,verto_ev_flag flags)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
push_ev(verto_ctx * ctx,verto_ev * ev)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
remove_ev(verto_ev ** origin,verto_ev * item)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
signal_ignore(verto_ctx * ctx,verto_ev * ev)529 signal_ignore(verto_ctx *ctx, verto_ev *ev)
530 {
531 (void) ctx;
532 (void) ev;
533 }
534
535 verto_ctx *
verto_new(const char * impl,verto_ev_type reqtypes)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 *
verto_default(const char * impl,verto_ev_type reqtypes)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
verto_set_default(const char * impl,verto_ev_type reqtypes)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
verto_set_allocator(void * (* resize)(void * mem,size_t size),int hierarchical)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
verto_free(verto_ctx * ctx)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
verto_cleanup(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
verto_run(verto_ctx * ctx)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
verto_run_once(verto_ctx * ctx)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
verto_break(verto_ctx * ctx)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
verto_reinitialize(verto_ctx * ctx)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 *
verto_add_io(verto_ctx * ctx,verto_ev_flag flags,verto_callback * callback,int fd)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 *
verto_add_timeout(verto_ctx * ctx,verto_ev_flag flags,verto_callback * callback,time_t interval)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 *
verto_add_idle(verto_ctx * ctx,verto_ev_flag flags,verto_callback * callback)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 *
verto_add_signal(verto_ctx * ctx,verto_ev_flag flags,verto_callback * callback,int signal)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 *
verto_add_child(verto_ctx * ctx,verto_ev_flag flags,verto_callback * callback,verto_proc proc)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
verto_set_private(verto_ev * ev,void * priv,verto_callback * free)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 *
verto_get_private(const verto_ev * ev)787 verto_get_private(const verto_ev *ev)
788 {
789 return ev->priv;
790 }
791
792 verto_ev_type
verto_get_type(const verto_ev * ev)793 verto_get_type(const verto_ev *ev)
794 {
795 return ev->type;
796 }
797
798 verto_ev_flag
verto_get_flags(const verto_ev * ev)799 verto_get_flags(const verto_ev *ev)
800 {
801 return ev->flags;
802 }
803
804 void
verto_set_flags(verto_ev * ev,verto_ev_flag flags)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
verto_get_fd(const verto_ev * ev)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
verto_get_fd_state(const verto_ev * ev)840 verto_get_fd_state(const verto_ev *ev)
841 {
842 return ev->option.io.state;
843 }
844
845 time_t
verto_get_interval(const verto_ev * ev)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
verto_get_signal(const verto_ev * ev)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
verto_get_proc(const verto_ev * ev)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
verto_get_proc_status(const verto_ev * ev)869 verto_get_proc_status(const verto_ev *ev)
870 {
871 return ev->option.child.status;
872 }
873
874 verto_ctx *
verto_get_ctx(const verto_ev * ev)875 verto_get_ctx(const verto_ev *ev)
876 {
877 return ev->ctx;
878 }
879
880 void
verto_del(verto_ev * ev)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
verto_get_supported_types(verto_ctx * ctx)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 *
verto_convert_module(const verto_module * module,int deflt,verto_mod_ctx * mctx)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
verto_fire(verto_ev * ev)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
verto_set_proc_status(verto_ev * ev,verto_proc_status status)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
verto_set_fd_state(verto_ev * ev,verto_ev_flag state)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 }
1051