make clock_monotonic work; do not use default timeout;

from Scott Lamb, plus some fixes from me.


svn:r371
This commit is contained in:
Niels Provos 2007-07-30 22:41:00 +00:00
parent d7918e7963
commit 3ad6b47e03
9 changed files with 111 additions and 59 deletions

View File

@ -37,6 +37,7 @@ AC_ARG_WITH(rtsig,
dnl Checks for libraries. dnl Checks for libraries.
AC_CHECK_LIB(socket, socket) AC_CHECK_LIB(socket, socket)
AC_CHECK_LIB(resolv, inet_aton) AC_CHECK_LIB(resolv, inet_aton)
AC_CHECK_LIB(rt, clock_gettime)
dnl Checks for header files. dnl Checks for header files.
AC_HEADER_STDC AC_HEADER_STDC

View File

@ -218,11 +218,12 @@ devpoll_dispatch(struct event_base *base, void *arg, struct timeval *tv)
struct pollfd *events = devpollop->events; struct pollfd *events = devpollop->events;
struct dvpoll dvp; struct dvpoll dvp;
struct evdevpoll *evdp; struct evdevpoll *evdp;
int i, res, timeout; int i, res, timeout = -1;
if (devpollop->nchanges) if (devpollop->nchanges)
devpoll_commit(devpollop); devpoll_commit(devpollop);
if (tv != NULL)
timeout = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000; timeout = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000;
dvp.dp_fds = devpollop->events; dvp.dp_fds = devpollop->events;

View File

@ -187,9 +187,11 @@ epoll_dispatch(struct event_base *base, void *arg, struct timeval *tv)
struct epollop *epollop = arg; struct epollop *epollop = arg;
struct epoll_event *events = epollop->events; struct epoll_event *events = epollop->events;
struct evepoll *evep; 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); res = epoll_wait(epollop->epfd, events, epollop->nevents, timeout);
if (res == -1) { if (res == -1) {

92
event.c
View File

@ -51,6 +51,7 @@
#include <signal.h> #include <signal.h>
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
#include <time.h>
#include "event.h" #include "event.h"
#include "event-internal.h" #include "event-internal.h"
@ -113,6 +114,7 @@ const struct eventop *eventops[] = {
/* Global state */ /* Global state */
struct event_base *current_base = NULL; struct event_base *current_base = NULL;
extern struct event_base *evsignal_base; extern struct event_base *evsignal_base;
static int use_monotonic;
/* Handle signals - This is a deprecated interface */ /* Handle signals - This is a deprecated interface */
int (*event_sigcb)(void); /* Signal callback when gotsig is set */ 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 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_process(struct event_base *);
static void timeout_correct(struct event_base *, struct timeval *); static void timeout_correct(struct event_base *, struct timeval *);
@ -143,25 +145,34 @@ compare(struct event *a, struct event *b)
return (0); 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 static int
gettime(struct timeval *tp) gettime(struct timeval *tp)
{ {
#ifdef HAVE_CLOCK_GETTIME #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
struct timespec ts; struct timespec ts;
#ifdef HAVE_CLOCK_MONOTONIC if (use_monotonic) {
if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)
#else
if (clock_gettime(CLOCK_REALTIME, &ts) == -1)
#endif
return (-1); return (-1);
tp->tv_sec = ts.tv_sec; tp->tv_sec = ts.tv_sec;
tp->tv_usec = ts.tv_nsec / 1000; tp->tv_usec = ts.tv_nsec / 1000;
#else return (0);
gettimeofday(tp, NULL); }
#endif #endif
return (0); return (gettimeofday(tp, NULL));
} }
RB_PROTOTYPE(event_tree, event, ev_timeout_node, compare); RB_PROTOTYPE(event_tree, event, ev_timeout_node, compare);
@ -180,6 +191,8 @@ event_init(void)
event_sigcb = NULL; event_sigcb = NULL;
event_gotsig = 0; event_gotsig = 0;
detect_monotonic();
gettime(&base->event_tv); gettime(&base->event_tv);
RB_INIT(&base->timetree); RB_INIT(&base->timetree);
@ -374,6 +387,7 @@ event_base_loop(struct event_base *base, int flags)
const struct eventop *evsel = base->evsel; const struct eventop *evsel = base->evsel;
void *evbase = base->evbase; void *evbase = base->evbase;
struct timeval tv; struct timeval tv;
struct timeval *tv_p;
int res, done; int res, done;
if(!TAILQ_EMPTY(&base->sig.signalqueue)) 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 */ timeout_correct(base, &tv);
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;
if (!base->event_count_active && !(flags & EVLOOP_NONBLOCK)) tv_p = &tv;
timeout_next(base, &tv); if (!base->event_count_active && !(flags & EVLOOP_NONBLOCK)) {
else timeout_next(base, &tv_p);
} else {
/*
* if we have active events, we just poll new events
* without waiting.
*/
timerclear(&tv); timerclear(&tv);
}
/* If we have no events, we just exit */ /* If we have no events, we just exit */
if (!event_haveevents(base)) { if (!event_haveevents(base)) {
@ -424,7 +435,7 @@ event_base_loop(struct event_base *base, int flags)
return (1); return (1);
} }
res = evsel->dispatch(base, evbase, &tv); res = evsel->dispatch(base, evbase, tv_p);
if (res == -1) 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); event_queue_insert(ev->ev_base, ev, EVLIST_ACTIVE);
} }
int static int
timeout_next(struct event_base *base, struct timeval *tv) timeout_next(struct event_base *base, struct timeval **tv_p)
{ {
struct timeval dflt = TIMEOUT_DEFAULT;
struct timeval now; struct timeval now;
struct event *ev; struct event *ev;
struct timeval *tv = *tv_p;
if ((ev = RB_MIN(event_tree, &base->timetree)) == NULL) { 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); return (0);
} }
@ -755,17 +766,38 @@ timeout_next(struct event_base *base, struct timeval *tv)
return (0); 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 static void
timeout_correct(struct event_base *base, struct timeval *off) timeout_correct(struct event_base *base, struct timeval *tv)
{ {
struct event *ev; 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 * We can modify the key element of the node without destroying
* the key, beause we apply it to all in the right order. * the key, beause we apply it to all in the right order.
*/ */
RB_FOREACH(ev, event_tree, &base->timetree) RB_FOREACH(ev, event_tree, &base->timetree)
timersub(&ev->ev_timeout, off, &ev->ev_timeout); timersub(&ev->ev_timeout, &off, &ev->ev_timeout);
} }
void void

View File

@ -141,8 +141,6 @@ struct eventop {
void (*dealloc)(struct event_base *, void *); void (*dealloc)(struct event_base *, void *);
}; };
#define TIMEOUT_DEFAULT {5, 0}
void *event_init(void); void *event_init(void);
int event_dispatch(void); int event_dispatch(void);
int event_base_dispatch(struct event_base *); int event_base_dispatch(struct event_base *);

2
http.c
View File

@ -1247,7 +1247,7 @@ evhttp_get_body_length(struct evhttp_request *req)
event_debug(("%s: bytes to read: %d (in buffer %d)\n", event_debug(("%s: bytes to read: %d (in buffer %d)\n",
__func__, req->ntoread, __func__, req->ntoread,
EVBUFFER_LENGTH(evcon->input_buffer))); EVBUFFER_LENGTH(req->evcon->input_buffer)));
return (0); return (0);
} }

View File

@ -212,13 +212,16 @@ kq_dispatch(struct event_base *base, void *arg, struct timeval *tv)
struct kevent *changes = kqop->changes; struct kevent *changes = kqop->changes;
struct kevent *events = kqop->events; struct kevent *events = kqop->events;
struct event *ev; struct event *ev;
struct timespec ts; struct timespec ts, *ts_p = NULL;
int i, res; int i, res;
if (tv != NULL) {
TIMEVAL_TO_TIMESPEC(tv, &ts); TIMEVAL_TO_TIMESPEC(tv, &ts);
ts_p = &ts;
}
res = kevent(kqop->kq, changes, kqop->nchanges, res = kevent(kqop->kq, changes, kqop->nchanges,
events, kqop->nevents, &ts); events, kqop->nevents, ts_p);
kqop->nchanges = 0; kqop->nchanges = 0;
if (res == -1) { if (res == -1) {
if (errno != EINTR) { if (errno != EINTR) {

9
poll.c
View File

@ -148,13 +148,16 @@ poll_check_ok(struct pollop *pop)
int int
poll_dispatch(struct event_base *base, void *arg, struct timeval *tv) 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; struct pollop *pop = arg;
poll_check_ok(pop); 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; nfds = pop->nfds;
res = poll(pop->event_set, nfds, sec); res = poll(pop->event_set, nfds, msec);
if (res == -1) { if (res == -1) {
if (errno != EINTR) { if (errno != EINTR) {

32
rtsig.c
View File

@ -750,7 +750,7 @@ rtsig_recalc(struct event_base *base, void *arg, int max)
*/ */
static inline int 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 res = 0;
int i = 0; int i = 0;
@ -758,7 +758,11 @@ do_poll(struct rtsigop *op, struct timespec *ts)
if (op->cur > 1) { if (op->cur > 1) {
/* non-empty poll set (modulo the signalfd) */ /* non-empty poll set (modulo the signalfd) */
if (op->nonsock) { 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); sigprocmask(SIG_UNBLOCK, &(op->sigs), NULL);
@ -768,6 +772,7 @@ do_poll(struct rtsigop *op, struct timespec *ts)
ts->tv_sec = 0; ts->tv_sec = 0;
ts->tv_nsec = 0; ts->tv_nsec = 0;
*ts_p = ts;
} else { } else {
res = poll(op->poll, op->cur, 0); res = poll(op->poll, op->cur, 0);
} }
@ -777,6 +782,7 @@ do_poll(struct rtsigop *op, struct timespec *ts)
} else if (res) { } else if (res) {
ts->tv_sec = 0; ts->tv_sec = 0;
ts->tv_nsec = 0; ts->tv_nsec = 0;
*ts_p = ts;
} }
i = 0; i = 0;
@ -894,17 +900,18 @@ do_siginfo_dispatch(struct event_base *base, struct rtsigop *op,
* return -1 on error * return -1 on error
*/ */
static inline int static inline int
do_sigwait(struct event_base *base, struct rtsigop *op, struct timespec *ts, do_sigwait(struct event_base *base, struct rtsigop *op,
sigset_t *sigs) struct timespec *ts, struct timespec **ts_p, sigset_t *sigs)
{ {
for (;;) { for (;;) {
siginfo_t info; siginfo_t info;
int signum; int signum;
signum = sigtimedwait(sigs, &info, ts); signum = sigtimedwait(sigs, &info, *ts_p);
ts->tv_sec = 0; ts->tv_sec = 0;
ts->tv_nsec = 0; ts->tv_nsec = 0;
*ts_p = ts;
if (signum == -1) { if (signum == -1) {
if (errno == EAGAIN || errno == EINTR) if (errno == EAGAIN || errno == EINTR)
@ -920,7 +927,7 @@ do_sigwait(struct event_base *base, struct rtsigop *op, struct timespec *ts,
static inline int static inline int
do_signals_from_socket(struct event_base *base, struct rtsigop *op, 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; int fd = op->signal_recv_fd;
siginfo_t info; siginfo_t info;
@ -937,6 +944,7 @@ do_signals_from_socket(struct event_base *base, struct rtsigop *op,
} else { } else {
ts->tv_sec = 0; ts->tv_sec = 0;
ts->tv_nsec = 0; ts->tv_nsec = 0;
*ts_p = ts;
if (1 == do_siginfo_dispatch(base, op, &info)) if (1 == do_siginfo_dispatch(base, op, &info))
return (1); return (1);
} }
@ -948,17 +956,21 @@ int
rtsig_dispatch(struct event_base *base, void *arg, struct timeval *tv) rtsig_dispatch(struct event_base *base, void *arg, struct timeval *tv)
{ {
struct rtsigop *op = (struct rtsigop *) arg; struct rtsigop *op = (struct rtsigop *) arg;
struct timespec ts; struct timespec ts, *ts_p = NULL;
int res; int res;
sigset_t sigs; sigset_t sigs;
if (tv != NULL) {
ts.tv_sec = tv->tv_sec; ts.tv_sec = tv->tv_sec;
ts.tv_nsec = tv->tv_usec * 1000; ts.tv_nsec = tv->tv_usec * 1000;
*ts_p = ts;
}
poll_for_level: 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) if (res == 1)
goto poll_for_level; goto poll_for_level;
else if (res == -1) else if (res == -1)
@ -973,7 +985,7 @@ rtsig_dispatch(struct event_base *base, void *arg, struct timeval *tv)
signotset(&sigs); signotset(&sigs);
sigorset(&sigs, &sigs, &op->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) if (res == 1)
goto poll_for_level; goto poll_for_level;