]> granicus.if.org Git - libevent/commitdiff
make clock_monotonic work; do not use default timeout;
authorNiels Provos <provos@gmail.com>
Mon, 30 Jul 2007 22:41:00 +0000 (22:41 +0000)
committerNiels Provos <provos@gmail.com>
Mon, 30 Jul 2007 22:41:00 +0000 (22:41 +0000)
from Scott Lamb, plus some fixes from me.

svn:r371

configure.in
devpoll.c
epoll.c
event.c
event.h
http.c
kqueue.c
poll.c
rtsig.c

index 507090b39d56f2488448c5f45f08799b960251fa..1acfa842e7daae5137fdf02669353122e058f021 100644 (file)
@@ -37,6 +37,7 @@ AC_ARG_WITH(rtsig,
 dnl Checks for libraries.
 AC_CHECK_LIB(socket, socket)
 AC_CHECK_LIB(resolv, inet_aton)
+AC_CHECK_LIB(rt, clock_gettime)
 
 dnl Checks for header files.
 AC_HEADER_STDC
index 96582ab05fcaa79443ab77fea5ecdefbceb1df3c..d1327e55e1ff516ac7c3b2b924b2c4262ffe009d 100644 (file)
--- a/devpoll.c
+++ b/devpoll.c
@@ -218,12 +218,13 @@ devpoll_dispatch(struct event_base *base, void *arg, struct timeval *tv)
        struct pollfd *events = devpollop->events;
        struct dvpoll dvp;
        struct evdevpoll *evdp;
-       int i, res, timeout;
+       int i, res, timeout = -1;
 
        if (devpollop->nchanges)
                devpoll_commit(devpollop);
 
-       timeout = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000;
+       if (tv != NULL)
+               timeout = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000;
 
        dvp.dp_fds = devpollop->events;
        dvp.dp_nfds = devpollop->nevents;
diff --git a/epoll.c b/epoll.c
index 235977def1a92132b727df29f3487e99d6f4b6eb..2be06d6de95b1c141378a944cecd44a2180b520a 100644 (file)
--- a/epoll.c
+++ b/epoll.c
@@ -187,9 +187,11 @@ epoll_dispatch(struct event_base *base, void *arg, struct timeval *tv)
        struct epollop *epollop = arg;
        struct epoll_event *events = epollop->events;
        struct evepoll *evep;
-       int i, res, timeout;
+       int i, res, timeout = -1;
+
+       if (tv != NULL)
+               timeout = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000;
 
-       timeout = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000;
        res = epoll_wait(epollop->epfd, events, epollop->nevents, timeout);
 
        if (res == -1) {
diff --git a/event.c b/event.c
index 2048157d9f399cef9708c228dddfd69027076ece..ca59714a196bcf942ba10b5b870e43e9546a54f3 100644 (file)
--- a/event.c
+++ b/event.c
@@ -51,6 +51,7 @@
 #include <signal.h>
 #include <string.h>
 #include <assert.h>
+#include <time.h>
 
 #include "event.h"
 #include "event-internal.h"
@@ -113,6 +114,7 @@ const struct eventop *eventops[] = {
 /* Global state */
 struct event_base *current_base = NULL;
 extern struct event_base *evsignal_base;
+static int use_monotonic;
 
 /* Handle signals - This is a deprecated interface */
 int (*event_sigcb)(void);              /* Signal callback when gotsig is set */
@@ -125,7 +127,7 @@ static int  event_haveevents(struct event_base *);
 
 static void    event_process_active(struct event_base *);
 
-static int     timeout_next(struct event_base *, struct timeval *);
+static int     timeout_next(struct event_base *, struct timeval **);
 static void    timeout_process(struct event_base *);
 static void    timeout_correct(struct event_base *, struct timeval *);
 
@@ -143,25 +145,34 @@ compare(struct event *a, struct event *b)
        return (0);
 }
 
+static void
+detect_monotonic(void)
+{
+#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
+       struct timespec ts;
+
+       if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
+               use_monotonic = 1;
+#endif
+}
+
 static int
 gettime(struct timeval *tp)
 {
-#ifdef HAVE_CLOCK_GETTIME
+#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
        struct timespec ts;
 
-#ifdef HAVE_CLOCK_MONOTONIC      
-       if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)
-#else
-       if (clock_gettime(CLOCK_REALTIME, &ts) == -1)
-#endif
-               return (-1);
-       tp->tv_sec = ts.tv_sec;
-       tp->tv_usec = ts.tv_nsec / 1000;
-#else
-       gettimeofday(tp, NULL);
+       if (use_monotonic) {
+               if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)
+                       return (-1);
+
+               tp->tv_sec = ts.tv_sec;
+               tp->tv_usec = ts.tv_nsec / 1000;
+               return (0);
+       }
 #endif
 
-       return (0);
+       return (gettimeofday(tp, NULL));
 }
 
 RB_PROTOTYPE(event_tree, event, ev_timeout_node, compare);
@@ -180,6 +191,8 @@ event_init(void)
 
        event_sigcb = NULL;
        event_gotsig = 0;
+
+       detect_monotonic();
        gettime(&base->event_tv);
        
        RB_INIT(&base->timetree);
@@ -374,6 +387,7 @@ event_base_loop(struct event_base *base, int flags)
        const struct eventop *evsel = base->evsel;
        void *evbase = base->evbase;
        struct timeval tv;
+       struct timeval *tv_p;
        int res, done;
 
        if(!TAILQ_EMPTY(&base->sig.signalqueue))
@@ -402,21 +416,18 @@ event_base_loop(struct event_base *base, int flags)
                        }
                }
 
-               /* Check if time is running backwards */
-               gettime(&tv);
-               if (timercmp(&tv, &base->event_tv, <)) {
-                       struct timeval off;
-                       event_debug(("%s: time is running backwards, corrected",
-                                   __func__));
-                       timersub(&base->event_tv, &tv, &off);
-                       timeout_correct(base, &off);
-               }
-               base->event_tv = tv;
+               timeout_correct(base, &tv);
 
-               if (!base->event_count_active && !(flags & EVLOOP_NONBLOCK))
-                       timeout_next(base, &tv);
-               else
+               tv_p = &tv;
+               if (!base->event_count_active && !(flags & EVLOOP_NONBLOCK)) {
+                       timeout_next(base, &tv_p);
+               } else {
+                       /* 
+                        * if we have active events, we just poll new events
+                        * without waiting.
+                        */
                        timerclear(&tv);
+               }
                
                /* If we have no events, we just exit */
                if (!event_haveevents(base)) {
@@ -424,7 +435,7 @@ event_base_loop(struct event_base *base, int flags)
                        return (1);
                }
 
-               res = evsel->dispatch(base, evbase, &tv);
+               res = evsel->dispatch(base, evbase, tv_p);
 
 
                if (res == -1)
@@ -725,16 +736,16 @@ event_active(struct event *ev, int res, short ncalls)
        event_queue_insert(ev->ev_base, ev, EVLIST_ACTIVE);
 }
 
-int
-timeout_next(struct event_base *base, struct timeval *tv)
+static int
+timeout_next(struct event_base *base, struct timeval **tv_p)
 {
-       struct timeval dflt = TIMEOUT_DEFAULT;
-
        struct timeval now;
        struct event *ev;
+       struct timeval *tv = *tv_p;
 
        if ((ev = RB_MIN(event_tree, &base->timetree)) == NULL) {
-               *tv = dflt;
+               /* if no time-based events are active wait for I/O */
+               *tv_p = NULL;
                return (0);
        }
 
@@ -755,17 +766,38 @@ timeout_next(struct event_base *base, struct timeval *tv)
        return (0);
 }
 
+/*
+ * Determines if the time is running backwards by comparing the current
+ * time against the last time we checked.  Not needed when using clock
+ * monotonic.
+ */
+
 static void
-timeout_correct(struct event_base *base, struct timeval *off)
+timeout_correct(struct event_base *base, struct timeval *tv)
 {
        struct event *ev;
+       struct timeval off;
+
+       if (use_monotonic)
+               return;
+
+       /* Check if time is running backwards */
+       gettime(tv);
+       if (timercmp(tv, &base->event_tv, >=)) {
+               base->event_tv = *tv;
+               return;
+       }
+
+       event_debug(("%s: time is running backwards, corrected",
+                   __func__));
+       timersub(&base->event_tv, tv, &off);
 
        /*
         * We can modify the key element of the node without destroying
         * the key, beause we apply it to all in the right order.
         */
        RB_FOREACH(ev, event_tree, &base->timetree)
-               timersub(&ev->ev_timeout, off, &ev->ev_timeout);
+               timersub(&ev->ev_timeout, &off, &ev->ev_timeout);
 }
 
 void
diff --git a/event.h b/event.h
index 65394db99147d927be0c7e3509ac2a590199e6eb..4c39939cc501951d3fad6c80fb8b71107b1b53b6 100644 (file)
--- a/event.h
+++ b/event.h
@@ -141,8 +141,6 @@ struct eventop {
        void (*dealloc)(struct event_base *, void *);
 };
 
-#define TIMEOUT_DEFAULT        {5, 0}
-
 void *event_init(void);
 int event_dispatch(void);
 int event_base_dispatch(struct event_base *);
diff --git a/http.c b/http.c
index 4256cfb556b2f473f11d275dd3fec1c4de552121..d093da82067ced8e7ca2c9a8d5ff6f73e2946337 100644 (file)
--- a/http.c
+++ b/http.c
@@ -1247,7 +1247,7 @@ evhttp_get_body_length(struct evhttp_request *req)
                
        event_debug(("%s: bytes to read: %d (in buffer %d)\n",
                __func__, req->ntoread,
-               EVBUFFER_LENGTH(evcon->input_buffer)));
+               EVBUFFER_LENGTH(req->evcon->input_buffer)));
 
        return (0);
 }
index af2e0f167d0c67d133f565b8283c0e44f5897d70..c547806298da683c9e21330dc106416cf6df7549 100644 (file)
--- a/kqueue.c
+++ b/kqueue.c
@@ -212,13 +212,16 @@ kq_dispatch(struct event_base *base, void *arg, struct timeval *tv)
        struct kevent *changes = kqop->changes;
        struct kevent *events = kqop->events;
        struct event *ev;
-       struct timespec ts;
+       struct timespec ts, *ts_p = NULL;
        int i, res;
 
-       TIMEVAL_TO_TIMESPEC(tv, &ts);
+       if (tv != NULL) {
+               TIMEVAL_TO_TIMESPEC(tv, &ts);
+               ts_p = &ts;
+       }
 
        res = kevent(kqop->kq, changes, kqop->nchanges,
-           events, kqop->nevents, &ts);
+           events, kqop->nevents, ts_p);
        kqop->nchanges = 0;
        if (res == -1) {
                if (errno != EINTR) {
diff --git a/poll.c b/poll.c
index 84885984ff07ecf64ea354a79952b8fc355257e2..123d36a56023b269c8b8f84ab597849cde59ad43 100644 (file)
--- a/poll.c
+++ b/poll.c
@@ -148,13 +148,16 @@ poll_check_ok(struct pollop *pop)
 int
 poll_dispatch(struct event_base *base, void *arg, struct timeval *tv)
 {
-       int res, i, sec, nfds;
+       int res, i, msec = -1, nfds;
        struct pollop *pop = arg;
 
        poll_check_ok(pop);
-       sec = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000;
+
+       if (tv != NULL)
+               msec = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000;
+
        nfds = pop->nfds;
-       res = poll(pop->event_set, nfds, sec);
+       res = poll(pop->event_set, nfds, msec);
 
        if (res == -1) {
                if (errno != EINTR) {
diff --git a/rtsig.c b/rtsig.c
index 3267af9441205aa645451bf16045957bbbbe27f7..e0e55afc30a534af0dafd1b00e3b012cbf94b61c 100644 (file)
--- a/rtsig.c
+++ b/rtsig.c
@@ -750,7 +750,7 @@ rtsig_recalc(struct event_base *base, void *arg, int max)
  */
 
 static inline int
-do_poll(struct rtsigop *op, struct timespec *ts)
+do_poll(struct rtsigop *op, struct timespec *ts, struct timespec **ts_p)
 {
        int res = 0;
        int i = 0;
@@ -758,7 +758,11 @@ do_poll(struct rtsigop *op, struct timespec *ts)
        if (op->cur > 1) {
                /* non-empty poll set (modulo the signalfd) */
                if (op->nonsock) {
-                       int timeout = ts->tv_nsec / 1000000 + ts->tv_sec * 1000;
+                       int timeout = -1;
+                       
+                       if (*ts_p != NULL)
+                               timeout = (*ts_p)->tv_nsec / 1000000
+                                         + (*ts_p)->tv_sec * 1000;
                        
                        sigprocmask(SIG_UNBLOCK, &(op->sigs), NULL);
 
@@ -768,6 +772,7 @@ do_poll(struct rtsigop *op, struct timespec *ts)
                        
                        ts->tv_sec = 0;
                        ts->tv_nsec = 0;
+                       *ts_p = ts;
                } else {
                        res = poll(op->poll, op->cur, 0);
                }
@@ -777,6 +782,7 @@ do_poll(struct rtsigop *op, struct timespec *ts)
                } else if (res) {
                        ts->tv_sec = 0;
                        ts->tv_nsec = 0;
+                       *ts_p = ts;
                }
 
                i = 0;
@@ -894,17 +900,18 @@ do_siginfo_dispatch(struct event_base *base, struct rtsigop *op,
  * return -1 on error
  */
 static inline int
-do_sigwait(struct event_base *base, struct rtsigop *op, struct timespec *ts,
-    sigset_t *sigs)
+do_sigwait(struct event_base *base, struct rtsigop *op,
+    struct timespec *ts, struct timespec **ts_p, sigset_t *sigs)
 {
        for (;;) {
                siginfo_t info;
                int signum;
 
-               signum = sigtimedwait(sigs, &info, ts);
+               signum = sigtimedwait(sigs, &info, *ts_p);
 
                ts->tv_sec = 0;
                ts->tv_nsec = 0;
+               *ts_p = ts;
 
                if (signum == -1) {
                        if (errno == EAGAIN || errno == EINTR)
@@ -920,7 +927,7 @@ do_sigwait(struct event_base *base, struct rtsigop *op, struct timespec *ts,
 
 static inline int
 do_signals_from_socket(struct event_base *base, struct rtsigop *op,
-    struct timespec *ts)
+    struct timespec *ts, struct timespec **ts_p)
 {
        int fd = op->signal_recv_fd;
        siginfo_t info;
@@ -937,6 +944,7 @@ do_signals_from_socket(struct event_base *base, struct rtsigop *op,
                } else {
                        ts->tv_sec = 0;
                        ts->tv_nsec = 0;
+                       *ts_p = ts;
                        if (1 == do_siginfo_dispatch(base, op, &info))
                                return (1);
                }
@@ -948,17 +956,21 @@ int
 rtsig_dispatch(struct event_base *base, void *arg, struct timeval *tv)
 {
        struct rtsigop *op = (struct rtsigop *) arg;
-       struct timespec ts;
+       struct timespec ts, *ts_p = NULL;
        int res;
        sigset_t sigs;
 
-       ts.tv_sec = tv->tv_sec;
-       ts.tv_nsec = tv->tv_usec * 1000;
+       if (tv != NULL) {
+               ts.tv_sec = tv->tv_sec;
+               ts.tv_nsec = tv->tv_usec * 1000;
+               *ts_p = ts;
+       }
 
  poll_for_level:
-       res = do_poll(op, &ts); /* ts can be modified in do_XXX() */
+       /* ts and ts_p can be modified in do_XXX() */
+       res = do_poll(op, &ts, &ts_p);
 
-       res = do_signals_from_socket(base, op, &ts);
+       res = do_signals_from_socket(base, op, &ts, &ts_p);
        if (res == 1)
                goto poll_for_level;
        else if (res == -1)
@@ -973,7 +985,7 @@ rtsig_dispatch(struct event_base *base, void *arg, struct timeval *tv)
        signotset(&sigs);
        sigorset(&sigs, &sigs, &op->sigs);
 
-       res = do_sigwait(base, op, &ts, &sigs);
+       res = do_sigwait(base, op, &ts, &ts_p, &sigs);
 
        if (res == 1)
                goto poll_for_level;