+void io_del(event_loop_t *loop, io_t *io) {
+ assert(io->cb);
+
+ loop->deletion = true;
+
+ io_set(loop, io, 0);
+
+ splay_unlink_node(&loop->ios, &io->node);
+ io->cb = NULL;
+}
+
+void timeout_add(event_loop_t *loop, timeout_t *timeout, timeout_cb_t cb, void *data, struct timeval *tv) {
+ timeout->cb = cb;
+ timeout->data = data;
+ timeout->node.data = timeout;
+
+ timeout_set(loop, timeout, tv);
+}
+
+void timeout_set(event_loop_t *loop, timeout_t *timeout, struct timeval *tv) {
+ assert(timeout->cb);
+
+ if(timerisset(&timeout->tv)) {
+ splay_unlink_node(&loop->timeouts, &timeout->node);
+ }
+
+ if(!loop->now.tv_sec) {
+ gettimeofday(&loop->now, NULL);
+ }
+
+ timeradd(&loop->now, tv, &timeout->tv);
+
+ if(!splay_insert_node(&loop->timeouts, &timeout->node)) {
+ abort();
+ }
+
+ loop->deletion = true;
+}
+
+static void timeout_disable(event_loop_t *loop, timeout_t *timeout) {
+ splay_unlink_node(&loop->timeouts, &timeout->node);
+ timeout->tv = (struct timeval) {
+ 0, 0
+ };
+}
+
+void timeout_del(event_loop_t *loop, timeout_t *timeout) {
+ if(!timeout->cb) {
+ return;
+ }
+
+ if(timerisset(&timeout->tv)) {
+ timeout_disable(loop, timeout);
+ }
+
+ timeout->cb = NULL;
+ loop->deletion = true;
+}
+
+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) {
+ (void)data;
+ (void)flags;
+ unsigned char signum;
+
+ if(read(loop->pipefd[0], &signum, 1) != 1) {
+ return;
+ }
+
+ signal_t *sig = splay_search(&loop->signals, &((signal_t) {
+ .signum = signum
+ }));