From: Niels Provos Date: Mon, 30 Jul 2007 22:41:00 +0000 (+0000) Subject: make clock_monotonic work; do not use default timeout; X-Git-Tag: release-2.0.1-alpha~610 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3ad6b47e03993f688e92fb202c89e3be984a8f56;p=libevent make clock_monotonic work; do not use default timeout; from Scott Lamb, plus some fixes from me. svn:r371 --- diff --git a/configure.in b/configure.in index 507090b3..1acfa842 100644 --- a/configure.in +++ b/configure.in @@ -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 diff --git a/devpoll.c b/devpoll.c index 96582ab0..d1327e55 100644 --- 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 235977de..2be06d6d 100644 --- 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 2048157d..ca59714a 100644 --- a/event.c +++ b/event.c @@ -51,6 +51,7 @@ #include #include #include +#include #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 65394db9..4c39939c 100644 --- 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 4256cfb5..d093da82 100644 --- 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); } diff --git a/kqueue.c b/kqueue.c index af2e0f16..c5478062 100644 --- 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 84885984..123d36a5 100644 --- 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 3267af94..e0e55afc 100644 --- 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;