X-Git-Url: http://git.meshlink.io/?a=blobdiff_plain;f=src%2Fevent.c;h=5a131b64875bb7e2317b2e83fe40fb427b387fe6;hb=fe1a9111456a73a6e690927e90d8bfa1e1d0ad22;hp=cfc6d899eead2fad4e2dddb8295c8306f975fb49;hpb=12fd793a46d1695bedb96a5d9531dfd9f3efd7be;p=meshlink diff --git a/src/event.c b/src/event.c index cfc6d899..5a131b64 100644 --- a/src/event.c +++ b/src/event.c @@ -1,5 +1,5 @@ /* - event.c -- I/O and timeout event handling + event.c -- I/O, timeout and signal event handling Copyright (C) 2014 Guus Sliepen This program is free software; you can redistribute it and/or modify @@ -81,6 +81,8 @@ void io_del(event_loop_t *loop, io_t *io) { if(!io->cb) return; + loop->deletion = true; + io_set(loop, io, 0); splay_unlink_node(&loop->ios, &io->node); @@ -88,6 +90,9 @@ void io_del(event_loop_t *loop, io_t *io) { } void timeout_add(event_loop_t *loop, timeout_t *timeout, timeout_cb_t cb, void *data, struct timeval *tv) { + if(!timeout->cb) + timeout->tv = (struct timeval){0, 0}; + timeout->cb = cb; timeout->data = data; timeout->node.data = timeout; @@ -112,12 +117,72 @@ void timeout_del(event_loop_t *loop, timeout_t *timeout) { if(!timeout->cb) return; + loop->deletion = true; + splay_unlink_node(&loop->timeouts, &timeout->node); timeout->cb = 0; timeout->tv = (struct timeval){0, 0}; } -bool event_loop_run(event_loop_t *loop) { +static int signal_compare(const signal_t *a, const signal_t *b) { + return (int)a->signum - (int)b->signum; +} + +static void signalio_handler(event_loop_t *loop, void *data, int flags) { + unsigned char signum; + if(read(loop->pipefd[0], &signum, 1) != 1) + return; + + signal_t *sig = splay_search(&loop->signals, &((signal_t){.signum = signum})); + if(sig) + sig->cb(loop, sig->data); +} + +static void pipe_init(event_loop_t *loop) { + if(!pipe(loop->pipefd)) + io_add(loop, &loop->signalio, signalio_handler, NULL, loop->pipefd[0], IO_READ); +} + +void signal_trigger(event_loop_t *loop, signal_t *sig) { + + uint8_t signum = sig->signum; + write(loop->pipefd[1], &signum, 1); + return; + +} + +void signal_add(event_loop_t *loop, signal_t *sig, signal_cb_t cb, void *data, uint8_t signum) { + if(sig->cb) + return; + + sig->cb = cb; + sig->data = data; + sig->signum = signum; + sig->node.data = sig; + + if(loop->pipefd[0] == -1) + pipe_init(loop); + + if(!splay_insert_node(&loop->signals, &sig->node)) + abort(); +} + +void signal_del(event_loop_t *loop, signal_t *sig) { + if(!sig->cb) + return; + + loop->deletion = true; + + splay_unlink_node(&loop->signals, &sig->node); + sig->cb = NULL; +} + +void idle_set(event_loop_t *loop, idle_cb_t cb, void *data) { + loop->idle_cb = cb; + loop->idle_data = data; +} + +bool event_loop_run(event_loop_t *loop, pthread_mutex_t *mutex) { loop->running = true; fd_set readable; @@ -125,7 +190,7 @@ bool event_loop_run(event_loop_t *loop) { while(loop->running) { gettimeofday(&loop->now, NULL); - struct timeval diff, *tv = NULL; + struct timeval diff, it, *tv = NULL; while(loop->timeouts.head) { timeout_t *timeout = loop->timeouts.head->data; @@ -141,6 +206,12 @@ bool event_loop_run(event_loop_t *loop) { } } + if(loop->idle_cb) { + it = loop->idle_cb(loop, loop->idle_data); + if(it.tv_sec >= 0 && (!tv || timercmp(&it, tv, <))) + tv = ⁢ + } + memcpy(&readable, &loop->readfds, sizeof readable); memcpy(&writable, &loop->writefds, sizeof writable); @@ -151,7 +222,12 @@ bool event_loop_run(event_loop_t *loop) { fds = last->fd + 1; } + // release mesh mutex during select + if(mutex) + pthread_mutex_unlock(mutex); int n = select(fds, &readable, &writable, NULL, tv); + if(mutex) + pthread_mutex_lock(mutex); if(n < 0) { if(sockwouldblock(errno)) @@ -163,11 +239,21 @@ bool event_loop_run(event_loop_t *loop) { if(!n) continue; + // Normally, splay_each allows the current node to be deleted. However, + // it can be that one io callback triggers the deletion of another io, + // so we have to detect this and break the loop. + + loop->deletion = false; + for splay_each(io_t, io, &loop->ios) { - if(FD_ISSET(io->fd, &writable)) + if(FD_ISSET(io->fd, &writable) && io->cb) io->cb(loop, io->data, IO_WRITE); - else if(FD_ISSET(io->fd, &readable)) + if(loop->deletion) + break; + if(FD_ISSET(io->fd, &readable) && io->cb) io->cb(loop, io->data, IO_READ); + if(loop->deletion) + break; } } @@ -187,12 +273,17 @@ void event_loop_stop(event_loop_t *loop) { void event_loop_init(event_loop_t *loop) { loop->ios.compare = (splay_compare_t)io_compare; loop->timeouts.compare = (splay_compare_t)timeout_compare; + loop->signals.compare = (splay_compare_t)signal_compare; + loop->pipefd[0] = -1; + loop->pipefd[1] = -1; gettimeofday(&loop->now, NULL); } void event_loop_exit(event_loop_t *loop) { for splay_each(io_t, io, &loop->ios) - splay_free_node(&loop->ios, node); + splay_unlink_node(&loop->ios, node); for splay_each(timeout_t, timeout, &loop->timeouts) - splay_free_node(&loop->timeouts, node); + splay_unlink_node(&loop->timeouts, node); + for splay_each(signal_t, signal, &loop->signals) + splay_unlink_node(&loop->signals, node); }