From: Ben Pfaff Date: Mon, 19 Dec 2011 22:28:42 +0000 (-0800) Subject: poll-loop: Track the poll timeout as an absolute, not a relative time. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cee03df4f53a9629f1f18b6c9948362f55a3ae27;p=openvswitch poll-loop: Track the poll timeout as an absolute, not a relative time. This is a necessary prerequisite for allowing time to be "fast forwarded" in unit tests, to keep tests that depend on the passage of time from running in real time. Without this change, a code sequence like this: poll_timer_wait(1000); ...fast forward time 5 seconds... poll_block(); would still sleep for a second, because the poll_loop module would still have a relative timeout of 1000 ms. Signed-off-by: Ben Pfaff --- diff --git a/lib/poll-loop.c b/lib/poll-loop.c index 5ff70d9f..76fbc1d2 100644 --- a/lib/poll-loop.c +++ b/lib/poll-loop.c @@ -55,9 +55,10 @@ struct poll_waiter { /* All active poll waiters. */ static struct list waiters = LIST_INITIALIZER(&waiters); -/* Max time to wait in next call to poll_block(), in milliseconds, or -1 to +/* Time at which to wake up the next call to poll_block(), in milliseconds as + * returned by time_msec(), LLONG_MIN to wake up immediately, or LLONG_MAX to * wait forever. */ -static int timeout = -1; +static long long int timeout_when = LLONG_MAX; /* Location where waiter created. */ static const char *timeout_where; @@ -82,16 +83,6 @@ poll_fd_wait(int fd, short int events, const char *where) return new_waiter(fd, events, where); } -/* The caller must ensure that 'msec' is not negative. */ -static void -poll_timer_wait__(int msec, const char *where) -{ - if (timeout < 0 || msec < timeout) { - timeout = msec; - timeout_where = where; - } -} - /* Causes the following call to poll_block() to block for no more than 'msec' * milliseconds. If 'msec' is nonpositive, the following call to poll_block() * will not block at all. @@ -105,14 +96,25 @@ poll_timer_wait__(int msec, const char *where) void poll_timer_wait(long long int msec, const char *where) { - poll_timer_wait__((msec < 0 ? 0 - : msec > INT_MAX ? INT_MAX - : msec), - where); + long long int now = time_msec(); + long long int when; + + if (msec <= 0) { + /* Wake up immediately. */ + when = LLONG_MIN; + } else if ((unsigned long long int) now + msec <= LLONG_MAX) { + /* Normal case. */ + when = now + msec; + } else { + /* now + msec would overflow. */ + when = LLONG_MAX; + } + + poll_timer_wait_until(when, where); } /* Causes the following call to poll_block() to wake up when the current time, - * as returned by time_msec(), reaches 'msec' or later. If 'msec' is earlier + * as returned by time_msec(), reaches 'when' or later. If 'when' is earlier * than the current time, the following call to poll_block() will not block at * all. * @@ -123,13 +125,12 @@ poll_timer_wait(long long int msec, const char *where) * Ordinarily the 'where' argument is supplied automatically; see poll-loop.h * for more information. */ void -poll_timer_wait_until(long long int msec, const char *where) +poll_timer_wait_until(long long int when, const char *where) { - long long int now = time_msec(); - poll_timer_wait__((msec <= now ? 0 - : msec < now + INT_MAX ? msec - now - : INT_MAX), - where); + if (when < timeout_when) { + timeout_when = when; + timeout_where = where; + } } /* Causes the following call to poll_block() to wake up immediately, without @@ -215,6 +216,7 @@ poll_block(void) struct poll_waiter *pw, *next; int n_waiters, n_pollfds; + int elapsed; int retval; /* Register fatal signal events before actually doing any real work for @@ -236,15 +238,15 @@ poll_block(void) n_pollfds++; } - if (!timeout) { + if (timeout_when == LLONG_MIN) { COVERAGE_INC(poll_zero_timeout); } - retval = time_poll(pollfds, n_pollfds, timeout); + retval = time_poll(pollfds, n_pollfds, timeout_when, &elapsed); if (retval < 0) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); VLOG_ERR_RL(&rl, "poll: %s", strerror(-retval)); } else if (!retval) { - log_wakeup(timeout_where, NULL, timeout); + log_wakeup(timeout_where, NULL, elapsed); } LIST_FOR_EACH_SAFE (pw, next, node, &waiters) { @@ -254,7 +256,7 @@ poll_block(void) poll_cancel(pw); } - timeout = -1; + timeout_when = LLONG_MAX; timeout_where = NULL; /* Handle any pending signals before doing anything else. */ diff --git a/lib/timeval.c b/lib/timeval.c index 88a6679e..bc7411fb 100644 --- a/lib/timeval.c +++ b/lib/timeval.c @@ -268,17 +268,22 @@ time_alarm(unsigned int secs) } /* Like poll(), except: + * + * - The timeout is specified as an absolute time, as defined by + * time_msec(), instead of a duration. * * - On error, returns a negative error code (instead of setting errno). * * - If interrupted by a signal, retries automatically until the original - * 'timeout' expires. (Because of this property, this function will + * timeout is reached. (Because of this property, this function will * never return -EINTR.) * * - As a side effect, refreshes the current time (like time_refresh()). - */ + * + * Stores the number of milliseconds elapsed during poll in '*elapsed'. */ int -time_poll(struct pollfd *pollfds, int n_pollfds, int timeout) +time_poll(struct pollfd *pollfds, int n_pollfds, long long int timeout_when, + int *elapsed) { static long long int last_wakeup; long long int start; @@ -292,12 +297,15 @@ time_poll(struct pollfd *pollfds, int n_pollfds, int timeout) start = time_msec(); blocked = false; for (;;) { + long long int now = time_msec(); int time_left; - if (timeout > 0) { - long long int elapsed = time_msec() - start; - time_left = timeout >= elapsed ? timeout - elapsed : 0; + + if (now >= timeout_when) { + time_left = 0; + } else if ((unsigned long long int) timeout_when - now > INT_MAX) { + time_left = INT_MAX; } else { - time_left = timeout; + time_left = timeout_when - now; } retval = poll(pollfds, n_pollfds, time_left); @@ -319,6 +327,7 @@ time_poll(struct pollfd *pollfds, int n_pollfds, int timeout) } last_wakeup = time_msec(); refresh_rusage(); + *elapsed = last_wakeup - start; return retval; } diff --git a/lib/timeval.h b/lib/timeval.h index 517524c6..e57f7ac7 100644 --- a/lib/timeval.h +++ b/lib/timeval.h @@ -55,7 +55,8 @@ long long int time_wall_msec(void); void time_timespec(struct timespec *); void time_wall_timespec(struct timespec *); void time_alarm(unsigned int secs); -int time_poll(struct pollfd *, int n_pollfds, int timeout); +int time_poll(struct pollfd *, int n_pollfds, long long int timeout_when, + int *elapsed); long long int timespec_to_msec(const struct timespec *); long long int timeval_to_msec(const struct timeval *);