from Scott Lamb, plus some fixes from me.
svn:r371
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
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;
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) {
#include <signal.h>
#include <string.h>
#include <assert.h>
+#include <time.h>
#include "event.h"
#include "event-internal.h"
/* 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 */
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 *);
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);
event_sigcb = NULL;
event_gotsig = 0;
+
+ detect_monotonic();
gettime(&base->event_tv);
RB_INIT(&base->timetree);
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))
}
}
- /* 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)) {
return (1);
}
- res = evsel->dispatch(base, evbase, &tv);
+ res = evsel->dispatch(base, evbase, tv_p);
if (res == -1)
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);
}
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
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 *);
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);
}
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) {
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) {
*/
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;
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);
ts->tv_sec = 0;
ts->tv_nsec = 0;
+ *ts_p = ts;
} else {
res = poll(op->poll, op->cur, 0);
}
} else if (res) {
ts->tv_sec = 0;
ts->tv_nsec = 0;
+ *ts_p = ts;
}
i = 0;
* 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)
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;
} else {
ts->tv_sec = 0;
ts->tv_nsec = 0;
+ *ts_p = ts;
if (1 == do_siginfo_dispatch(base, op, &info))
return (1);
}
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)
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;