about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRichard Nyberg <rnyberg@murmeldjur.se>2009-01-09 18:49:16 +0100
committerRichard Nyberg <rnyberg@murmeldjur.se>2009-01-11 15:26:54 +0100
commiteb421cc586f047968763b6e1f595ee5988686690 (patch)
treeb66cc894a6891b0aab35ddc1055e6b28f9fdaeb6
parent59905999ce145a81e0003766d468945c2444a90e (diff)
downloadbtpd-eb421cc586f047968763b6e1f595ee5988686690.tar.gz
btpd-eb421cc586f047968763b6e1f595ee5988686690.zip
Btpd now uses evloop, it's own event loop, instead of libevent.
-rw-r--r--btpd/btpd.c47
-rw-r--r--btpd/btpd.h11
-rw-r--r--btpd/cli_if.c13
-rw-r--r--btpd/content.c8
-rw-r--r--btpd/http_tr_if.c40
-rw-r--r--btpd/main.c13
-rw-r--r--btpd/nameconn.c15
-rw-r--r--btpd/net.c47
-rw-r--r--btpd/net.h3
-rw-r--r--btpd/net_types.h3
-rw-r--r--btpd/peer.c11
-rw-r--r--btpd/thread_cb.c5
-rw-r--r--btpd/tracker_req.c24
-rw-r--r--btpd/upload.c10
-rw-r--r--btpd/util.c35
15 files changed, 160 insertions, 125 deletions
diff --git a/btpd/btpd.c b/btpd/btpd.c
index e6e0f30..f49511d 100644
--- a/btpd/btpd.c
+++ b/btpd/btpd.c
@@ -4,9 +4,9 @@
 #include <signal.h>
 
 static uint8_t m_peer_id[20];
-static struct event m_sigint;
-static struct event m_sigterm;
-static struct event m_heartbeat;
+static struct timeout m_heartbeat;
+static struct timeout m_grace_timer;
+static int m_signal;
 static int m_shutdown;
 
 long btpd_seconds;
@@ -37,11 +37,9 @@ btpd_shutdown(int grace_seconds)
         BTPDQ_FOREACH(tp, torrent_get_all(), entry)
             if (tp->state != T_STOPPING)
                 torrent_stop(tp, 0);
-        if (grace_seconds >= 0) {
-            if (event_once(-1, EV_TIMEOUT, grace_cb, NULL,
-                    (& (struct timeval) { grace_seconds, 0 })) != 0)
-                btpd_err("failed to add event (%s).\n", strerror(errno));
-        }
+        if (grace_seconds >= 0)
+            btpd_timer_add(&m_grace_timer,
+                (& (struct timespec){ grace_seconds, 0 }));
     }
 }
 
@@ -57,19 +55,23 @@ btpd_get_peer_id(void)
 }
 
 static void
-signal_cb(int signal, short type, void *arg)
+signal_handler(int signal)
 {
-    btpd_log(BTPD_L_BTPD, "Got signal %d.\n", signal);
-    btpd_shutdown(30);
+    m_signal = signal;
 }
 
 static void
 heartbeat_cb(int fd, short type, void *arg)
 {
-    btpd_ev_add(&m_heartbeat, (& (struct timeval) { 1, 0 }));
+    btpd_timer_add(&m_heartbeat, (& (struct timespec) { 1, 0 }));
     btpd_seconds++;
     net_on_tick();
     torrent_on_tick_all();
+    if (m_signal) {
+        btpd_log(BTPD_L_BTPD, "Got signal %d.\n", m_signal);
+        btpd_shutdown(30);
+        m_signal = 0;
+    }
     if (m_shutdown && torrent_count() == 0)
         btpd_exit(0);
 }
@@ -82,11 +84,21 @@ void addrinfo_init(void);
 void
 btpd_init(void)
 {
+    struct sigaction sa;
     unsigned long seed;
     uint8_t idcon[1024];
     struct timeval now;
     int n;
 
+    bzero(&sa, sizeof(sa));
+    sa.sa_handler = SIG_IGN;
+    sa.sa_flags = SA_RESTART;
+    sigfillset(&sa.sa_mask);
+    sigaction(SIGPIPE, &sa, NULL);
+    sa.sa_handler = signal_handler;
+    sigaction(SIGTERM, &sa, NULL);
+    sigaction(SIGINT, &sa, NULL);
+
     gettimeofday(&now, NULL);
     n = snprintf(idcon, sizeof(idcon), "%ld%ld%d", now.tv_sec, now.tv_usec,
         net_port);
@@ -111,14 +123,9 @@ btpd_init(void)
     tr_init();
     tlib_init();
 
-    signal(SIGPIPE, SIG_IGN);
-
-    signal_set(&m_sigint, SIGINT, signal_cb, NULL);
-    btpd_ev_add(&m_sigint, NULL);
-    signal_set(&m_sigterm, SIGTERM, signal_cb, NULL);
-    btpd_ev_add(&m_sigterm, NULL);
-    evtimer_set(&m_heartbeat, heartbeat_cb, NULL);
-    btpd_ev_add(&m_heartbeat, (& (struct timeval) { 1, 0 }));
+    timer_init(&m_grace_timer, grace_cb, NULL);
+    timer_init(&m_heartbeat, heartbeat_cb, NULL);
+    btpd_timer_add(&m_heartbeat, (& (struct timespec) { 1, 0 }));
 
     if (!empty_start)
         active_start();
diff --git a/btpd/btpd.h b/btpd/btpd.h
index 790518e..3c9377b 100644
--- a/btpd/btpd.h
+++ b/btpd/btpd.h
@@ -26,7 +26,7 @@
 #define DAEMON
 #include <btpd_if.h>
 #undef DAEMON
-#include <event.h>
+#include <evloop.h>
 #include <metainfo.h>
 #include <queue.h>
 #include <subr.h>
@@ -70,8 +70,13 @@ void *btpd_malloc(size_t size);
 __attribute__((malloc))
 void *btpd_calloc(size_t nmemb, size_t size);
 
-void btpd_ev_add(struct event *ev, struct timeval *tv);
-void btpd_ev_del(struct event *ev);
+void btpd_ev_new(struct fdev *ev, int fd, uint16_t flags, evloop_cb_t cb,
+    void *arg);
+void btpd_ev_del(struct fdev *ev);
+void btpd_ev_enable(struct fdev *ev, uint16_t flags);
+void btpd_ev_disable(struct fdev *ev, uint16_t flags);
+void btpd_timer_add(struct timeout *to, struct timespec *ts);
+void btpd_timer_del(struct timeout *to);
 
 void btpd_shutdown(int grace_seconds);
 int btpd_is_stopping(void);
diff --git a/btpd/cli_if.c b/btpd/cli_if.c
index 100c6b4..a026b9e 100644
--- a/btpd/cli_if.c
+++ b/btpd/cli_if.c
@@ -5,10 +5,10 @@
 
 struct cli {
     int sd;
-    struct event read;
+    struct fdev read;
 };
 
-static struct event m_cli_incoming;
+static struct fdev m_cli_incoming;
 
 static int
 write_buffer(struct cli *cli, struct iobuf *iob)
@@ -420,10 +420,10 @@ cli_read_cb(int sd, short type, void *arg)
         goto error;
 
     free(msg);
-    btpd_ev_add(&cli->read, NULL);
     return;
 
 error:
+    btpd_ev_del(&cli->read);
     close(cli->sd);
     free(cli);
     if (msg != NULL)
@@ -447,8 +447,7 @@ client_connection_cb(int sd, short type, void *arg)
 
     struct cli *cli = btpd_calloc(1, sizeof(*cli));
     cli->sd = nsd;
-    event_set(&cli->read, cli->sd, EV_READ, cli_read_cb, cli);
-    btpd_ev_add(&cli->read, NULL);
+    btpd_ev_new(&cli->read, cli->sd, EV_READ, cli_read_cb, cli);
 }
 
 void
@@ -478,7 +477,5 @@ ipc_init(void)
     listen(sd, 4);
     set_nonblocking(sd);
 
-    event_set(&m_cli_incoming, sd, EV_READ | EV_PERSIST,
-        client_connection_cb, NULL);
-    btpd_ev_add(&m_cli_incoming, NULL);
+    btpd_ev_new(&m_cli_incoming, sd, EV_READ, client_connection_cb, NULL);
 }
diff --git a/btpd/content.c b/btpd/content.c
index d29e22c..72bf4e5 100644
--- a/btpd/content.c
+++ b/btpd/content.c
@@ -53,7 +53,7 @@ BTPDQ_HEAD(std_tq, start_test_data);
 
 static struct std_tq m_startq = BTPDQ_HEAD_INITIALIZER(m_startq);
 
-static struct event m_workev;
+static struct timeout m_workev;
 
 #define READBUFLEN (1 << 14)
 
@@ -456,7 +456,7 @@ startup_test_run(void)
     if (std->start >= tp->npieces)
         startup_test_end(tp, 1);
     if (!BTPDQ_EMPTY(&m_startq))
-        event_add(&m_workev, (& (struct timeval) { 0, 0 }));
+        btpd_timer_add(&m_workev, (& (struct timespec) { 0, 0 }));
 }
 
 void
@@ -473,7 +473,7 @@ startup_test_begin(struct torrent *tp, struct file_time_size *fts)
         std->fts = fts;
         BTPDQ_INSERT_TAIL(&m_startq, std, entry);
         if (std == BTPDQ_FIRST(&m_startq))
-            event_add(&m_workev, (& (struct timeval) { 0, 0 }));
+            btpd_timer_add(&m_workev, (& (struct timespec) { 0, 0 }));
     } else {
         free(fts);
         startup_test_end(tp, 0);
@@ -539,5 +539,5 @@ cm_start(struct torrent *tp, int force_test)
 void
 cm_init(void)
 {
-    evtimer_set(&m_workev, worker_cb, NULL);
+    timer_init(&m_workev, worker_cb, NULL);
 }
diff --git a/btpd/http_tr_if.c b/btpd/http_tr_if.c
index 8e9dde2..e1a86ed 100644
--- a/btpd/http_tr_if.c
+++ b/btpd/http_tr_if.c
@@ -11,8 +11,7 @@ struct http_tr_req {
     struct torrent *tp;
     struct http_req *req;
     struct iobuf buf;
-    struct event rdev;
-    struct event wrev;
+    struct fdev ioev;
     nameconn_t nc;
     int sd;
     enum tr_event event;
@@ -22,8 +21,7 @@ static void
 http_tr_free(struct http_tr_req *treq)
 {
     if (treq->sd != -1) {
-        btpd_ev_del(&treq->rdev);
-        btpd_ev_del(&treq->wrev);
+        btpd_ev_del(&treq->ioev);
         close(treq->sd);
     }
     iobuf_free(&treq->buf);
@@ -143,19 +141,21 @@ http_cb(struct http_req *req, struct http_response *res, void *arg)
 }
 
 static void
-sd_wr_cb(int sd, short type, void *arg)
+sd_io_cb(int sd, short type, void *arg)
 {
     struct http_tr_req *treq = arg;
-    if (http_write(treq->req, sd) && http_want_write(treq->req))
-        btpd_ev_add(&treq->wrev, NULL);
-}
-
-static void
-sd_rd_cb(int sd, short type, void *arg)
-{
-    struct http_tr_req *treq = arg;
-    if (http_read(treq->req, sd) && http_want_read(treq->req))
-        btpd_ev_add(&treq->rdev, NULL);
+    switch (type) {
+    case EV_READ:
+        if (http_read(treq->req, sd) && !http_want_read(treq->req))
+            btpd_ev_disable(&treq->ioev, EV_READ);
+        break;
+    case EV_WRITE:
+        if (http_write(treq->req, sd) && !http_want_write(treq->req))
+            btpd_ev_disable(&treq->ioev, EV_WRITE);
+        break;
+    default:
+        abort();
+    }
 }
 
 static void
@@ -168,12 +168,10 @@ nc_cb(void *arg, int error, int sd)
         http_tr_free(treq);
     } else {
         treq->sd = sd;
-        event_set(&treq->wrev, sd, EV_WRITE, sd_wr_cb, treq);
-        event_set(&treq->rdev, sd, EV_READ, sd_rd_cb, treq);
-        if (http_want_read(treq->req))
-            btpd_ev_add(&treq->rdev, NULL);
-        if (http_want_write(treq->req))
-            btpd_ev_add(&treq->wrev, NULL);
+        uint16_t flags =
+            (http_want_read(treq->req) ? EV_READ : 0) |
+            (http_want_write(treq->req) ? EV_WRITE : 0);
+        btpd_ev_new(&treq->ioev, sd, flags, sd_io_cb, treq);
     }
 }
 
diff --git a/btpd/main.c b/btpd/main.c
index ea9df58..d4b5511 100644
--- a/btpd/main.c
+++ b/btpd/main.c
@@ -2,7 +2,6 @@
 
 #include <sys/file.h>
 #include <err.h>
-#include <evdns.h>
 #include <getopt.h>
 
 static void
@@ -222,19 +221,13 @@ args_done:
 
     setup_daemon(daemonize, dir, log);
 
-    event_init();
-
-    if ((errno = evdns_resolv_conf_parse(DNS_OPTION_NAMESERVERS,
-             "/etc/resolv.conf")) != 0) {
-        btpd_log(BTPD_L_ERROR,
-            "failed to setup dns from /etc/resolv.conf (%d).\n", errno);
-    }
+    evloop_init();
 
     btpd_init();
 
-    event_dispatch();
+    evloop();
 
-    btpd_err("Unexpected exit from libevent.\n");
+    btpd_err("Unexpected exit from evloop.\n");
 
     return 1;
 }
diff --git a/btpd/nameconn.c b/btpd/nameconn.c
index ba2f952..e4bde27 100644
--- a/btpd/nameconn.c
+++ b/btpd/nameconn.c
@@ -1,7 +1,7 @@
 #include "btpd.h"
 
 struct nameconn {
-    struct event write_ev;
+    struct fdev write_ev;
     void (*cb)(void *, int, int);
     void *arg;
     aictx_t ai_handle;
@@ -35,9 +35,11 @@ nc_write_cb(int sd, short type, void *arg)
     socklen_t errsiz = sizeof(int);
     if (getsockopt(nc->sd, SOL_SOCKET, SO_ERROR, &error, &errsiz) < 0)
         btpd_err("getsockopt error (%s).\n", strerror(errno));
-    if (error == 0)
+    if (error == 0) {
+        btpd_ev_del(&nc->write_ev);
         nc_done(nc, 0);
-    else {
+    } else {
+        btpd_ev_del(&nc->write_ev);
         close(nc->sd);
         nc->ai_cur = nc->ai_cur->ai_next;
         nc_connect(nc);
@@ -64,10 +66,9 @@ again:
     err = connect(nc->sd, ai->ai_addr, ai->ai_addrlen);
     if (err == 0)
         nc_done(nc, 0);
-    else if (err < 0 && errno == EINPROGRESS) {
-        event_set(&nc->write_ev, nc->sd, EV_WRITE, nc_write_cb, nc);
-        btpd_ev_add(&nc->write_ev, NULL);
-    } else {
+    else if (err < 0 && errno == EINPROGRESS)
+        btpd_ev_new(&nc->write_ev, nc->sd, EV_WRITE, nc_write_cb, nc);
+    else {
         close(nc->sd);
         nc->ai_cur = ai->ai_next;
         goto again;
diff --git a/btpd/net.c b/btpd/net.c
index 5829dc3..2ba247a 100644
--- a/btpd/net.c
+++ b/btpd/net.c
@@ -9,7 +9,7 @@ static unsigned long m_bw_bytes_out;
 static unsigned long m_rate_up;
 static unsigned long m_rate_dwn;
 
-static struct event m_net_incoming;
+static struct fdev m_net_incoming;
 
 unsigned net_npeers;
 
@@ -154,7 +154,6 @@ net_write(struct peer *p, unsigned long wmax)
     nwritten = writev(p->sd, iov, niov);
     if (nwritten < 0) {
         if (errno == EAGAIN) {
-            btpd_ev_add(&p->out_ev, NULL);
             p->t_wantwrite = btpd_seconds;
             return 0;
         } else {
@@ -194,10 +193,10 @@ net_write(struct peer *p, unsigned long wmax)
             bcount = 0;
         }
     }
-    if (!BTPDQ_EMPTY(&p->outq)) {
-        btpd_ev_add(&p->out_ev, NULL);
+    if (!BTPDQ_EMPTY(&p->outq))
         p->t_wantwrite = btpd_seconds;
-    }
+    else
+        btpd_ev_disable(&p->ioev, EV_WRITE);
     p->t_lastwrite = btpd_seconds;
 
     return nwritten;
@@ -435,7 +434,6 @@ net_read(struct peer *p, unsigned long rmax)
     }
 
 out:
-    btpd_ev_add(&p->in_ev, NULL);
     return nread > 0 ? nread : 0;
 }
 
@@ -557,12 +555,14 @@ net_bw_tick(void)
     if (net_bw_limit_in > 0) {
         while ((p = BTPDQ_FIRST(&net_bw_readq)) != NULL && m_bw_bytes_in > 0) {
             BTPDQ_REMOVE(&net_bw_readq, p, rq_entry);
+            btpd_ev_enable(&p->ioev, EV_READ);
             p->flags &= ~PF_ON_READQ;
             m_bw_bytes_in -= net_read(p, m_bw_bytes_in);
         }
     } else {
         while ((p = BTPDQ_FIRST(&net_bw_readq)) != NULL) {
             BTPDQ_REMOVE(&net_bw_readq, p, rq_entry);
+            btpd_ev_enable(&p->ioev, EV_READ);
             p->flags &= ~PF_ON_READQ;
             net_read(p, 0);
         }
@@ -572,12 +572,14 @@ net_bw_tick(void)
         while (((p = BTPDQ_FIRST(&net_bw_writeq)) != NULL
                    && m_bw_bytes_out > 0)) {
             BTPDQ_REMOVE(&net_bw_writeq, p, wq_entry);
+            btpd_ev_enable(&p->ioev, EV_WRITE);
             p->flags &= ~PF_ON_WRITEQ;
             m_bw_bytes_out -=  net_write(p, m_bw_bytes_out);
         }
     } else {
         while ((p = BTPDQ_FIRST(&net_bw_writeq)) != NULL) {
             BTPDQ_REMOVE(&net_bw_writeq, p, wq_entry);
+            btpd_ev_enable(&p->ioev, EV_WRITE);
             p->flags &= ~PF_ON_WRITEQ;
             net_write(p, 0);
         }
@@ -606,43 +608,56 @@ net_on_tick(void)
     net_bw_tick();
 }
 
-void
-net_read_cb(int sd, short type, void *arg)
+static void
+net_read_cb(struct peer *p)
 {
-    struct peer *p = (struct peer *)arg;
     if (net_bw_limit_in == 0)
         net_read(p, 0);
     else if (m_bw_bytes_in > 0)
         m_bw_bytes_in -= net_read(p, m_bw_bytes_in);
     else {
+        btpd_ev_disable(&p->ioev, EV_READ);
         p->flags |= PF_ON_READQ;
         BTPDQ_INSERT_TAIL(&net_bw_readq, p, rq_entry);
     }
 }
 
-void
-net_write_cb(int sd, short type, void *arg)
+static void
+net_write_cb(struct peer *p)
 {
-    struct peer *p = (struct peer *)arg;
     if (net_bw_limit_out == 0)
         net_write(p, 0);
     else if (m_bw_bytes_out > 0)
         m_bw_bytes_out -= net_write(p, m_bw_bytes_out);
     else {
+        btpd_ev_disable(&p->ioev, EV_WRITE);
         p->flags |= PF_ON_WRITEQ;
         BTPDQ_INSERT_TAIL(&net_bw_writeq, p, wq_entry);
     }
 }
 
 void
+net_io_cb(int sd, short type, void *arg)
+{
+    switch (type) {
+    case EV_READ:
+        net_read_cb(arg);
+        break;
+    case EV_WRITE:
+        net_write_cb(arg);
+        break;
+    default:
+        abort();
+    }
+}
+
+void
 net_init(void)
 {
     m_bw_bytes_out = net_bw_limit_out;
     m_bw_bytes_in = net_bw_limit_in;
 
     int safe_fds = getdtablesize() * 4 / 5;
-    if (strcmp(event_get_method(), "select") == 0)
-        safe_fds = min(safe_fds, FD_SETSIZE * 4 / 5);
     if (net_max_peers == 0 || net_max_peers > safe_fds)
         net_max_peers = safe_fds;
 
@@ -661,7 +676,5 @@ net_init(void)
     listen(sd, 10);
     set_nonblocking(sd);
 
-    event_set(&m_net_incoming, sd, EV_READ | EV_PERSIST,
-        net_connection_cb, NULL);
-    btpd_ev_add(&m_net_incoming, NULL);
+    btpd_ev_new(&m_net_incoming, sd, EV_READ, net_connection_cb, NULL);
 }
diff --git a/btpd/net.h b/btpd/net.h
index 16e5da0..194c119 100644
--- a/btpd/net.h
+++ b/btpd/net.h
@@ -31,8 +31,7 @@ int net_active(struct torrent *tp);
 
 int net_torrent_has_peer(struct net *n, const uint8_t *id);
 
-void net_read_cb(int sd, short type, void *arg);
-void net_write_cb(int sd, short type, void *arg);
+void net_io_cb(int sd, short type, void *arg);
 
 int net_connect2(struct sockaddr *sa, socklen_t salen, int *sd);
 int net_connect(const char *ip, int port, int *sd);
diff --git a/btpd/net_types.h b/btpd/net_types.h
index 8ef61e5..a4db2e6 100644
--- a/btpd/net_types.h
+++ b/btpd/net_types.h
@@ -52,8 +52,7 @@ struct peer {
     size_t outq_off;
     struct nb_tq outq;
 
-    struct event in_ev;
-    struct event out_ev;
+    struct fdev ioev;
 
     unsigned long rate_up, rate_dwn;
     unsigned long count_up, count_dwn;
diff --git a/btpd/peer.c b/btpd/peer.c
index 7af6c21..8f6f4be 100644
--- a/btpd/peer.c
+++ b/btpd/peer.c
@@ -23,8 +23,7 @@ peer_kill(struct peer *p)
     if (p->flags & PF_ON_WRITEQ)
         BTPDQ_REMOVE(&net_bw_writeq, p, wq_entry);
 
-    btpd_ev_del(&p->in_ev);
-    btpd_ev_del(&p->out_ev);
+    btpd_ev_del(&p->ioev);
     close(p->sd);
 
     nl = BTPDQ_FIRST(&p->outq);
@@ -59,7 +58,7 @@ peer_send(struct peer *p, struct net_buf *nb)
 
     if (BTPDQ_EMPTY(&p->outq)) {
         assert(p->outq_off == 0);
-        btpd_ev_add(&p->out_ev, NULL);
+        btpd_ev_enable(&p->ioev, EV_WRITE);
         p->t_wantwrite = btpd_seconds;
     }
     BTPDQ_INSERT_TAIL(&p->outq, nl, entry);
@@ -88,7 +87,7 @@ peer_unsend(struct peer *p, struct nb_link *nl)
                 BTPDQ_REMOVE(&net_bw_writeq, p, wq_entry);
                 p->flags &= ~PF_ON_WRITEQ;
             } else
-                btpd_ev_del(&p->out_ev);
+                btpd_ev_disable(&p->ioev, EV_WRITE);
         }
         return 1;
     } else
@@ -275,9 +274,7 @@ peer_create_common(int sd)
 
     peer_set_in_state(p, SHAKE_PSTR, 28);
 
-    event_set(&p->out_ev, p->sd, EV_WRITE, net_write_cb, p);
-    event_set(&p->in_ev, p->sd, EV_READ, net_read_cb, p);
-    btpd_ev_add(&p->in_ev, NULL);
+    btpd_ev_new(&p->ioev, p->sd, EV_READ, net_io_cb, p);
 
     BTPDQ_INSERT_TAIL(&net_unattached, p, p_entry);
     net_npeers++;
diff --git a/btpd/thread_cb.c b/btpd/thread_cb.c
index f9d10f5..ed9a005 100644
--- a/btpd/thread_cb.c
+++ b/btpd/thread_cb.c
@@ -15,7 +15,7 @@ struct td_cb {
 BTPDQ_HEAD(td_cb_tq, td_cb);
 
 static int m_td_rd, m_td_wr;
-static struct event m_td_ev;
+static struct fdev m_td_ev;
 static struct td_cb_tq m_td_cbs = BTPDQ_HEAD_INITIALIZER(m_td_cbs);
 static pthread_mutex_t m_td_lock;
 
@@ -82,6 +82,5 @@ td_init(void)
     if ((err = pthread_mutex_init(&m_td_lock, NULL)) != 0)
         btpd_err("Couldn't create mutex (%s).\n", strerror(err));
 
-    event_set(&m_td_ev, m_td_rd, EV_READ|EV_PERSIST, td_cb, NULL);
-    btpd_ev_add(&m_td_ev, NULL);
+    btpd_ev_new(&m_td_ev, m_td_rd, EV_READ, td_cb, NULL);
 }
diff --git a/btpd/tracker_req.c b/btpd/tracker_req.c
index f3acc1e..06e281d 100644
--- a/btpd/tracker_req.c
+++ b/btpd/tracker_req.c
@@ -2,8 +2,8 @@
 
 #define REQ_DELAY 1
 #define STOP_ERRORS 5
-#define REQ_TIMEOUT (& (struct timeval) { 120, 0 })
-#define RETRY_WAIT (& (struct timeval) { rand_between(35, 70), 0 })
+#define REQ_TIMEOUT (& (struct timespec) { 120, 0 })
+#define RETRY_WAIT (& (struct timespec) { rand_between(35, 70), 0 })
 
 long tr_key;
 
@@ -24,7 +24,7 @@ struct tracker {
     int tier, url;
     struct mi_announce *ann;
     void *req;
-    struct event timer;
+    struct timeout timer;
 };
 
 typedef struct _dummy *(*request_fun_t)(struct torrent *, enum tr_event,
@@ -97,7 +97,7 @@ static void
 tr_set_stopped(struct torrent *tp)
 {
     struct tracker *tr = tp->tr;
-    btpd_ev_del(&tr->timer);
+    btpd_timer_del(&tr->timer);
     tr->ttype = TIMER_NONE;
     if (tr->req != NULL)
         tr_cancel(tr);
@@ -116,8 +116,8 @@ tr_send(struct torrent *tp, enum tr_event event)
     if (m_tlast_req > btpd_seconds - REQ_DELAY) {
         m_tnext_req = max(m_tnext_req, m_tlast_req) + REQ_DELAY;
         tr->ttype = TIMER_RETRY;
-        btpd_ev_add(&tr->timer,
-            (& (struct timeval) { m_tnext_req - btpd_seconds, 0 }));
+        btpd_timer_add(&tr->timer,
+            (& (struct timespec) { m_tnext_req - btpd_seconds, 0 }));
         return;
     }
 
@@ -130,11 +130,11 @@ tr_send(struct torrent *tp, enum tr_event event)
         }
         next_url(tr);
         tr->ttype = TIMER_RETRY;
-        btpd_ev_add(&tr->timer, (& (struct timeval) { 5, 0 }));
+        btpd_timer_add(&tr->timer, (& (struct timespec) { 5, 0 }));
     } else {
         m_tlast_req = btpd_seconds;
         tr->ttype = TIMER_TIMEOUT;
-        btpd_ev_add(&tr->timer, REQ_TIMEOUT);
+        btpd_timer_add(&tr->timer, REQ_TIMEOUT);
     }
 }
 
@@ -151,11 +151,11 @@ tr_result(struct torrent *tp, enum tr_res res, int interval)
         tr->interval = interval;
         tr->nerrors = 0;
         tr->ttype = TIMER_INTERVAL;
-        btpd_ev_add(&tr->timer, (& (struct timeval) { tr->interval, 0}));
+        btpd_timer_add(&tr->timer, (& (struct timespec) { tr->interval, 0}));
     } else {
         tr->nerrors++;
         tr->ttype = TIMER_RETRY;
-        btpd_ev_add(&tr->timer, RETRY_WAIT);
+        btpd_timer_add(&tr->timer, RETRY_WAIT);
         next_url(tr);
     }
 }
@@ -193,7 +193,7 @@ tr_create(struct torrent *tp, const char *mi)
     tp->tr = btpd_calloc(1, sizeof(*tp->tr));
     if ((tp->tr->ann = mi_announce(mi)) == NULL)
         btpd_err("Out of memory.\n");
-    evtimer_set(&tp->tr->timer, timer_cb, tp);
+    timer_init(&tp->tr->timer, timer_cb, tp);
     return 0;
 }
 
@@ -202,7 +202,7 @@ tr_kill(struct torrent *tp)
 {
     struct tracker *tr = tp->tr;
     tp->tr = NULL;
-    btpd_ev_del(&tr->timer);
+    btpd_timer_del(&tr->timer);
     if (tr->req != NULL)
         tr_cancel(tr);
     mi_free_announce(tr->ann);
diff --git a/btpd/upload.c b/btpd/upload.c
index cd8fabf..1fb28ca 100644
--- a/btpd/upload.c
+++ b/btpd/upload.c
@@ -1,8 +1,8 @@
 #include "btpd.h"
 
-#define CHOKE_INTERVAL (& (struct timeval) { 10, 0 })
+#define CHOKE_INTERVAL (& (struct timespec) { 10, 0 })
 
-static struct event m_choke_timer;
+static struct timeout m_choke_timer;
 static unsigned m_npeers;
 static struct peer_tq m_peerq = BTPDQ_HEAD_INITIALIZER(m_peerq);
 static int m_max_uploads;
@@ -110,7 +110,7 @@ shuffle_optimists(void)
 static void
 choke_cb(int sd, short type, void *arg)
 {
-    btpd_ev_add(&m_choke_timer, CHOKE_INTERVAL);
+    btpd_timer_add(&m_choke_timer, CHOKE_INTERVAL);
     static int cb_count = 0;
     cb_count++;
     if (cb_count % 3 == 0)
@@ -190,6 +190,6 @@ ul_init(void)
             m_max_uploads = 5 + (net_bw_limit_out / (100 << 10));
     }
 
-    evtimer_set(&m_choke_timer, choke_cb, NULL);
-    btpd_ev_add(&m_choke_timer, CHOKE_INTERVAL);
+    timer_init(&m_choke_timer, choke_cb, NULL);
+    btpd_timer_add(&m_choke_timer, CHOKE_INTERVAL);
 }
diff --git a/btpd/util.c b/btpd/util.c
index b2f2b3d..c6b430e 100644
--- a/btpd/util.c
+++ b/btpd/util.c
@@ -22,19 +22,46 @@ btpd_calloc(size_t nmemb, size_t size)
 }
 
 void
-btpd_ev_add(struct event *ev, struct timeval *tv)
+btpd_ev_new(struct fdev *ev, int fd, uint16_t flags, evloop_cb_t cb, void *arg)
 {
-    if (event_add(ev, tv) != 0)
+    if (fdev_new(ev, fd, flags, cb, arg) != 0)
         btpd_err("Failed to add event (%s).\n", strerror(errno));
 }
 
 void
-btpd_ev_del(struct event *ev)
+btpd_ev_del(struct fdev *ev)
 {
-    if (event_del(ev) != 0)
+    if (fdev_del(ev) != 0)
         btpd_err("Failed to remove event (%s).\n", strerror(errno));
 }
 
+void
+btpd_ev_enable(struct fdev *ev, uint16_t flags)
+{
+    if (fdev_enable(ev, flags) != 0)
+        btpd_err("Failed to enable event (%s).\n", strerror(errno));
+}
+
+void
+btpd_ev_disable(struct fdev *ev, uint16_t flags)
+{
+    if (fdev_disable(ev, flags) != 0)
+        btpd_err("Failed to disable event (%s).\n", strerror(errno));
+}
+
+void
+btpd_timer_add(struct timeout *to, struct timespec *ts)
+{
+    if (timer_add(to, ts) != 0)
+        btpd_err("Failed to add timeout (%s).\n", strerror(errno));
+}
+
+void
+btpd_timer_del(struct timeout *to)
+{
+    timer_del(to);
+}
+
 static const char *
 logtype_str(uint32_t type)
 {