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.
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

View File

@ -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;

View File

@ -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) {

100
event.c
View File

@ -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

View File

@ -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 *);

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",
__func__, req->ntoread,
EVBUFFER_LENGTH(evcon->input_buffer)));
EVBUFFER_LENGTH(req->evcon->input_buffer)));
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 *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) {

9
poll.c
View File

@ -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) {

36
rtsig.c
View File

@ -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;