mirror of
https://github.com/libevent/libevent.git
synced 2025-01-31 09:12:55 +08:00
make clock_monotonic work; do not use default timeout;
from Scott Lamb, plus some fixes from me. svn:r371
This commit is contained in:
parent
d7918e7963
commit
3ad6b47e03
@ -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
|
||||||
|
@ -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;
|
||||||
|
4
epoll.c
4
epoll.c
@ -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
92
event.c
@ -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
|
||||||
|
2
event.h
2
event.h
@ -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
2
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",
|
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);
|
||||||
}
|
}
|
||||||
|
7
kqueue.c
7
kqueue.c
@ -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
9
poll.c
@ -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
32
rtsig.c
@ -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;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user