mirror of
https://github.com/libevent/libevent.git
synced 2025-01-09 00:56:20 +08:00
f5e4eb05e5
Now, event.c can always assume that we have a monotonic timer; this makes event.c easier to write.
369 lines
10 KiB
C
369 lines
10 KiB
C
/*
|
|
* Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. The name of the author may not be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include "event2/event-config.h"
|
|
#include "evconfig-private.h"
|
|
|
|
#ifdef _WIN32
|
|
#include <winsock2.h>
|
|
#define WIN32_LEAN_AND_MEAN
|
|
#include <windows.h>
|
|
#undef WIN32_LEAN_AND_MEAN
|
|
#endif
|
|
|
|
#include <sys/types.h>
|
|
#ifdef EVENT__HAVE_STDLIB_H
|
|
#include <stdlib.h>
|
|
#endif
|
|
#include <errno.h>
|
|
#include <limits.h>
|
|
#ifndef EVENT__HAVE_GETTIMEOFDAY
|
|
#include <sys/timeb.h>
|
|
#endif
|
|
#if !defined(EVENT__HAVE_NANOSLEEP) && !defined(EVENT_HAVE_USLEEP) && \
|
|
!defined(_WIN32)
|
|
#include <sys/select.h>
|
|
#endif
|
|
#include <time.h>
|
|
#include <sys/stat.h>
|
|
#include <string.h>
|
|
|
|
#include "event2/util.h"
|
|
#include "util-internal.h"
|
|
#include "log-internal.h"
|
|
|
|
#ifndef EVENT__HAVE_GETTIMEOFDAY
|
|
/* No gettimeofday; this must be windows. */
|
|
int
|
|
evutil_gettimeofday(struct timeval *tv, struct timezone *tz)
|
|
{
|
|
#ifdef _MSC_VER
|
|
#define U64_LITERAL(n) n##ui64
|
|
#else
|
|
#define U64_LITERAL(n) n##llu
|
|
#endif
|
|
|
|
/* Conversion logic taken from Tor, which in turn took it
|
|
* from Perl. GetSystemTimeAsFileTime returns its value as
|
|
* an unaligned (!) 64-bit value containing the number of
|
|
* 100-nanosecond intervals since 1 January 1601 UTC. */
|
|
#define EPOCH_BIAS U64_LITERAL(116444736000000000)
|
|
#define UNITS_PER_SEC U64_LITERAL(10000000)
|
|
#define USEC_PER_SEC U64_LITERAL(1000000)
|
|
#define UNITS_PER_USEC U64_LITERAL(10)
|
|
union {
|
|
FILETIME ft_ft;
|
|
ev_uint64_t ft_64;
|
|
} ft;
|
|
|
|
if (tv == NULL)
|
|
return -1;
|
|
|
|
GetSystemTimeAsFileTime(&ft.ft_ft);
|
|
|
|
if (EVUTIL_UNLIKELY(ft.ft_64 < EPOCH_BIAS)) {
|
|
/* Time before the unix epoch. */
|
|
return -1;
|
|
}
|
|
ft.ft_64 -= EPOCH_BIAS;
|
|
tv->tv_sec = (long) (ft.ft_64 / UNITS_PER_SEC);
|
|
tv->tv_usec = (long) ((ft.ft_64 / UNITS_PER_USEC) % USEC_PER_SEC);
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
#define MAX_SECONDS_IN_MSEC_LONG \
|
|
(((LONG_MAX) - 999) / 1000)
|
|
|
|
long
|
|
evutil_tv_to_msec_(const struct timeval *tv)
|
|
{
|
|
if (tv->tv_usec > 1000000 || tv->tv_sec > MAX_SECONDS_IN_MSEC_LONG)
|
|
return -1;
|
|
|
|
return (tv->tv_sec * 1000) + ((tv->tv_usec + 999) / 1000);
|
|
}
|
|
|
|
void
|
|
evutil_usleep_(const struct timeval *tv)
|
|
{
|
|
if (!tv)
|
|
return;
|
|
#if defined(_WIN32)
|
|
{
|
|
long msec = evutil_tv_to_msec_(tv);
|
|
Sleep((DWORD)msec);
|
|
}
|
|
#elif defined(EVENT__HAVE_NANOSLEEP)
|
|
{
|
|
struct timespec ts;
|
|
ts.tv_sec = tv->tv_sec;
|
|
ts.tv_nsec = tv->tv_usec*1000;
|
|
nanosleep(&ts, NULL);
|
|
}
|
|
#elif defined(EVENT__HAVE_USLEEP)
|
|
/* Some systems don't like to usleep more than 999999 usec */
|
|
sleep(tv->tv_sec);
|
|
usleep(tv->tv_usec);
|
|
#else
|
|
select(0, NULL, NULL, NULL, tv);
|
|
#endif
|
|
}
|
|
|
|
|
|
/*
|
|
This function assumes it's called repeatedly with a
|
|
not-actually-so-monotonic time source whose outputs are in 'tv'. It
|
|
implements a trivial ratcheting mechanism so that the values never go
|
|
backwards.
|
|
*/
|
|
static void
|
|
adjust_monotonic_time(struct evutil_monotonic_timer *base,
|
|
struct timeval *tv)
|
|
{
|
|
evutil_timeradd(tv, &base->adjust_monotonic_clock, tv);
|
|
|
|
if (evutil_timercmp(tv, &base->last_time, <)) {
|
|
/* Guess it wasn't monotonic after all. */
|
|
struct timeval adjust;
|
|
evutil_timersub(&base->last_time, tv, &adjust);
|
|
evutil_timeradd(&adjust, &base->adjust_monotonic_clock,
|
|
&base->adjust_monotonic_clock);
|
|
*tv = base->last_time;
|
|
}
|
|
base->last_time = *tv;
|
|
}
|
|
|
|
#if defined(HAVE_POSIX_MONOTONIC)
|
|
/* =====
|
|
The POSIX clock_gettime() interface provides a few ways to get at a
|
|
monotonic clock. CLOCK_MONOTONIC is most widely supported. Linux also
|
|
provides a CLOCK_MONOTONIC_COARSE with accuracy of about 1-4 msec.
|
|
|
|
On all platforms I'm aware of, CLOCK_MONOTONIC really is monotonic.
|
|
Platforms don't agree about whether it should jump on a sleep/resume.
|
|
*/
|
|
|
|
int
|
|
evutil_configure_monotonic_time_(struct evutil_monotonic_timer *base,
|
|
int precise)
|
|
{
|
|
/* CLOCK_MONOTONIC exists on FreeBSD, Linux, and Solaris. You need to
|
|
* check for it at runtime, because some older kernel versions won't
|
|
* have it working. */
|
|
struct timespec ts;
|
|
#ifdef CLOCK_MONOTONIC_COARSE
|
|
#if CLOCK_MONOTONIC_COARSE < 0
|
|
/* Technically speaking, nothing keeps CLOCK_* from being negative (as
|
|
* far as I know). This check and the one below make sure that it's
|
|
* safe for us to use -1 as an "unset" value. */
|
|
#error "I didn't expect CLOCK_MONOTONIC_COARSE to be < 0"
|
|
#endif
|
|
if (! precise) {
|
|
if (clock_gettime(CLOCK_MONOTONIC_COARSE, &ts) == 0) {
|
|
base->monotonic_clock = CLOCK_MONOTONIC_COARSE;
|
|
return 0;
|
|
}
|
|
}
|
|
#endif
|
|
if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
|
|
base->monotonic_clock = CLOCK_MONOTONIC;
|
|
return 0;
|
|
}
|
|
|
|
#if CLOCK_MONOTONIC < 0
|
|
#error "I didn't expect CLOCK_MONOTONIC to be < 0"
|
|
#endif
|
|
|
|
base->monotonic_clock = -1;
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
evutil_gettime_monotonic_(struct evutil_monotonic_timer *base,
|
|
struct timeval *tp)
|
|
{
|
|
struct timespec ts;
|
|
|
|
if (base->monotonic_clock < 0) {
|
|
if (evutil_gettimeofday(tp, NULL) < 0)
|
|
return -1;
|
|
adjust_monotonic_time(base, tp);
|
|
return 0;
|
|
}
|
|
|
|
if (clock_gettime(base->monotonic_clock, &ts) == -1)
|
|
return -1;
|
|
tp->tv_sec = ts.tv_sec;
|
|
tp->tv_usec = ts.tv_nsec / 1000;
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
#if defined(HAVE_MACH_MONOTONIC)
|
|
/* ======
|
|
Apple is a little late to the POSIX party. And why not? Instead of
|
|
clock_gettime(), they provide mach_absolute_time(). Its units are not
|
|
fixed; we need to use mach_timebase_info() to get the right functions to
|
|
convert its units into nanoseconds.
|
|
|
|
To all appearances, mach_absolute_time() seems to be honest-to-goodness
|
|
monotonic. Whether it stops during sleep or not is unspecified in
|
|
principle, and dependent on CPU architecture in practice.
|
|
*/
|
|
|
|
int
|
|
evutil_configure_monotonic_time_(struct evutil_monotonic_timer *base,
|
|
int precise)
|
|
{
|
|
struct mach_timebase_info mi;
|
|
memset(base, 0, sizeof(*base));
|
|
/* OSX has mach_absolute_time() */
|
|
if (mach_timebase_info(&mi) == 0 && mach_absolute_time() != 0) {
|
|
/* mach_timebase_info tells us how to convert
|
|
* mach_absolute_time() into nanoseconds, but we
|
|
* want to use microseconds instead. */
|
|
mi.denom *= 1000;
|
|
memcpy(&base->mach_timebase_units, &mi, sizeof(mi));
|
|
} else {
|
|
base->mach_timebase_units.numer = 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
evutil_gettime_monotonic_(struct evutil_monotonic_timer *base,
|
|
struct timeval *tp)
|
|
{
|
|
ev_uint64_t abstime, usec;
|
|
if (base->mach_timebase_units.numer == 0) {
|
|
if (evutil_gettimeofday(tp, NULL) < 0)
|
|
return -1;
|
|
adjust_monotonic_time(base, tp);
|
|
return 0;
|
|
}
|
|
|
|
abstime = mach_absolute_time();
|
|
usec = (abstime * base->mach_timebase_units.numer)
|
|
/ (base->mach_timebase_units.denom);
|
|
tp->tv_sec = usec / 1000000;
|
|
tp->tv_usec = usec % 1000000;
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
#if defined(HAVE_WIN32_MONOTONIC)
|
|
/* =====
|
|
Turn we now to Windows. Want monontonic time on Windows?
|
|
|
|
Windows has QueryPerformanceCounter(), which gives time most high-
|
|
resolution time. It's a pity it's not so monotonic in practice; it's
|
|
also got some fun bugs, especially with older Windowses, under
|
|
virtualizations, with funny hardware, on multiprocessor systems, and so
|
|
on. PEP418 [1] has a nice roundup here.
|
|
|
|
There's GetTickCount64(), which gives a number of 1-msec ticks since
|
|
startup. The accuracy here might be as bad as 10-20 msec, I hear.
|
|
There's an undocumented function (NtSetTimerResolution) that allegedly
|
|
increases the accuracy. Good luck!
|
|
|
|
There's also GetTickCount(), which is only 32 bits, but seems to be
|
|
supported on pre-Vista versions of Windows.
|
|
|
|
The less said about timeGetTime() the better.
|
|
|
|
"We don't care. We don't have to. We're the Phone Company."
|
|
-- Lily Tomlin, SNL
|
|
|
|
|
|
[1] http://www.python.org/dev/peps/pep-0418
|
|
*/
|
|
int
|
|
evutil_configure_monotonic_time_(struct evutil_monotonic_timer *base,
|
|
int precise)
|
|
{
|
|
memset(base, 0, sizeof(*base));
|
|
base->last_tick_count = GetTickCount();
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
evutil_gettime_monotonic_(struct evutil_monotonic_timer *base,
|
|
struct timeval *tp)
|
|
{
|
|
/* TODO: Support GetTickCount64. */
|
|
/* TODO: Support alternate timer backends if the user asked
|
|
* for a high-precision timer. QueryPerformanceCounter is
|
|
* possibly a good idea, but it is also supposed to have
|
|
* reliability issues under various circumstances. */
|
|
DWORD ticks = GetTickCount();
|
|
if (ticks < base->last_tick_count) {
|
|
/* The 32-bit timer rolled over. Let's assume it only
|
|
* happened once. Add 2**32 msec to adjust_tick_count. */
|
|
const struct timeval tv_rollover = { 4294967, 296000 };
|
|
evutil_timeradd(&tv_rollover, &base->adjust_tick_count, &base->adjust_tick_count);
|
|
}
|
|
base->last_tick_count = ticks;
|
|
tp->tv_sec = ticks / 1000;
|
|
tp->tv_usec = (ticks % 1000) * 1000;
|
|
evutil_timeradd(tp, &base->adjust_tick_count, tp);
|
|
|
|
adjust_monotonic_time(base, tp);
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
#if defined(HAVE_FALLBACK_MONOTONIC)
|
|
/* =====
|
|
And if none of the other options work, let's just use gettimeofday(), and
|
|
ratchet it forward so that it acts like a monotonic timer, whether it
|
|
wants to or not.
|
|
*/
|
|
|
|
int
|
|
evutil_configure_monotonic_time_(struct evutil_monotonic_timer *base,
|
|
int precise)
|
|
{
|
|
memset(base, 0, sizeof(*base));
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
evutil_gettime_monotonic_(struct evutil_monotonic_timer *base,
|
|
struct timeval *tp)
|
|
{
|
|
if (evutil_gettimeofday(tp, NULL) < 0)
|
|
return -1;
|
|
adjust_monotonic_time(base, tp);
|
|
return 0;
|
|
|
|
}
|
|
#endif
|