mirror of
https://github.com/freebsd/freebsd-src.git
synced 2024-12-03 10:29:15 +00:00
b50261e21f
MFC after: 2 weeks Merge commit '5223d1d95fddcef6f9a36e264a5800bd907ade8b' into main
622 lines
18 KiB
C
622 lines
18 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>
|
|
|
|
/** evutil_usleep_() */
|
|
#if defined(_WIN32)
|
|
#elif defined(EVENT__HAVE_NANOSLEEP)
|
|
#elif defined(EVENT__HAVE_USLEEP)
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
#include "event2/util.h"
|
|
#include "util-internal.h"
|
|
#include "log-internal.h"
|
|
#include "mm-internal.h"
|
|
|
|
#ifndef EVENT__HAVE_GETTIMEOFDAY
|
|
/* No gettimeofday; this must be windows. */
|
|
|
|
typedef void (WINAPI *GetSystemTimePreciseAsFileTime_fn_t) (LPFILETIME);
|
|
|
|
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;
|
|
|
|
static GetSystemTimePreciseAsFileTime_fn_t GetSystemTimePreciseAsFileTime_fn = NULL;
|
|
static int check_precise = 1;
|
|
|
|
if (EVUTIL_UNLIKELY(check_precise)) {
|
|
HMODULE h = evutil_load_windows_system_library_(TEXT("kernel32.dll"));
|
|
if (h != NULL)
|
|
GetSystemTimePreciseAsFileTime_fn =
|
|
(GetSystemTimePreciseAsFileTime_fn_t)
|
|
GetProcAddress(h, "GetSystemTimePreciseAsFileTime");
|
|
check_precise = 0;
|
|
}
|
|
|
|
if (GetSystemTimePreciseAsFileTime_fn != NULL)
|
|
GetSystemTimePreciseAsFileTime_fn(&ft.ft_ft);
|
|
else
|
|
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);
|
|
}
|
|
|
|
/*
|
|
Replacement for usleep on platforms that don't have one. Not guaranteed to
|
|
be any more finegrained than 1 msec.
|
|
*/
|
|
void
|
|
evutil_usleep_(const struct timeval *tv)
|
|
{
|
|
if (!tv)
|
|
return;
|
|
#if defined(_WIN32)
|
|
{
|
|
__int64 usec;
|
|
LARGE_INTEGER li;
|
|
HANDLE timer;
|
|
|
|
usec = tv->tv_sec * 1000000LL + tv->tv_usec;
|
|
if (!usec)
|
|
return;
|
|
|
|
li.QuadPart = -10LL * usec;
|
|
timer = CreateWaitableTimer(NULL, TRUE, NULL);
|
|
if (!timer)
|
|
return;
|
|
|
|
SetWaitableTimer(timer, &li, 0, NULL, NULL, 0);
|
|
WaitForSingleObject(timer, INFINITE);
|
|
CloseHandle(timer);
|
|
}
|
|
#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
|
|
{
|
|
struct timeval tv2 = *tv;
|
|
select(0, NULL, NULL, NULL, &tv2);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
int
|
|
evutil_date_rfc1123(char *date, const size_t datelen, const struct tm *tm)
|
|
{
|
|
static const char *DAYS[] =
|
|
{ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
|
|
static const char *MONTHS[] =
|
|
{ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
|
|
|
|
time_t t = time(NULL);
|
|
|
|
#if defined(EVENT__HAVE__GMTIME64_S) || !defined(_WIN32)
|
|
struct tm sys;
|
|
#endif
|
|
|
|
/* If `tm` is null, set system's current time. */
|
|
if (tm == NULL) {
|
|
#if !defined(_WIN32)
|
|
gmtime_r(&t, &sys);
|
|
tm = &sys;
|
|
/** detect _gmtime64()/_gmtime64_s() */
|
|
#elif defined(EVENT__HAVE__GMTIME64_S)
|
|
errno_t err;
|
|
err = _gmtime64_s(&sys, &t);
|
|
if (err) {
|
|
event_errx(1, "Invalid argument to _gmtime64_s");
|
|
} else {
|
|
tm = &sys;
|
|
}
|
|
#elif defined(EVENT__HAVE__GMTIME64)
|
|
tm = _gmtime64(&t);
|
|
#else
|
|
tm = gmtime(&t);
|
|
#endif
|
|
}
|
|
|
|
return evutil_snprintf(
|
|
date, datelen, "%s, %02d %s %4d %02d:%02d:%02d GMT",
|
|
DAYS[tm->tm_wday], tm->tm_mday, MONTHS[tm->tm_mon],
|
|
1900 + tm->tm_year, tm->tm_hour, tm->tm_min, tm->tm_sec);
|
|
}
|
|
|
|
/*
|
|
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;
|
|
}
|
|
|
|
/*
|
|
Allocate a new struct evutil_monotonic_timer
|
|
*/
|
|
struct evutil_monotonic_timer *
|
|
evutil_monotonic_timer_new(void)
|
|
{
|
|
struct evutil_monotonic_timer *p = NULL;
|
|
|
|
p = mm_malloc(sizeof(*p));
|
|
if (!p) goto done;
|
|
|
|
memset(p, 0, sizeof(*p));
|
|
|
|
done:
|
|
return p;
|
|
}
|
|
|
|
/*
|
|
Free a struct evutil_monotonic_timer
|
|
*/
|
|
void
|
|
evutil_monotonic_timer_free(struct evutil_monotonic_timer *timer)
|
|
{
|
|
if (timer) {
|
|
mm_free(timer);
|
|
}
|
|
}
|
|
|
|
/*
|
|
Set up a struct evutil_monotonic_timer for initial use
|
|
*/
|
|
int
|
|
evutil_configure_monotonic_time(struct evutil_monotonic_timer *timer,
|
|
int flags)
|
|
{
|
|
return evutil_configure_monotonic_time_(timer, flags);
|
|
}
|
|
|
|
/*
|
|
Query the current monotonic time
|
|
*/
|
|
int
|
|
evutil_gettime_monotonic(struct evutil_monotonic_timer *timer,
|
|
struct timeval *tp)
|
|
{
|
|
return evutil_gettime_monotonic_(timer, tp);
|
|
}
|
|
|
|
|
|
#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 flags)
|
|
{
|
|
/* 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. */
|
|
#ifdef CLOCK_MONOTONIC_COARSE
|
|
const int precise = flags & EV_MONOT_PRECISE;
|
|
#endif
|
|
const int fallback = flags & EV_MONOT_FALLBACK;
|
|
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. */
|
|
event_errx(1,"I didn't expect CLOCK_MONOTONIC_COARSE to be < 0");
|
|
}
|
|
if (! precise && ! fallback) {
|
|
if (clock_gettime(CLOCK_MONOTONIC_COARSE, &ts) == 0) {
|
|
base->monotonic_clock = CLOCK_MONOTONIC_COARSE;
|
|
return 0;
|
|
}
|
|
}
|
|
#endif
|
|
if (!fallback && clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
|
|
base->monotonic_clock = CLOCK_MONOTONIC;
|
|
return 0;
|
|
}
|
|
|
|
if (CLOCK_MONOTONIC < 0) {
|
|
event_errx(1,"I didn't expect CLOCK_MONOTONIC to be < 0");
|
|
}
|
|
|
|
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 flags)
|
|
{
|
|
const int fallback = flags & EV_MONOT_FALLBACK;
|
|
struct mach_timebase_info mi;
|
|
memset(base, 0, sizeof(*base));
|
|
/* OSX has mach_absolute_time() */
|
|
if (!fallback &&
|
|
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 of the issues here.
|
|
|
|
There's GetTickCount64() on Vista and later, 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. Apparently, you can coax
|
|
another 14 bits out of it, giving you 2231 years before rollover.
|
|
|
|
The less said about timeGetTime() the better.
|
|
|
|
"We don't care. We don't have to. We're the Phone Company."
|
|
-- Lily Tomlin, SNL
|
|
|
|
Our strategy, if precise timers are turned off, is to just use the best
|
|
GetTickCount equivalent available. If we've been asked for precise timing,
|
|
then we mostly[2] assume that GetTickCount is monotonic, and correct
|
|
GetPerformanceCounter to approximate it.
|
|
|
|
[1] http://www.python.org/dev/peps/pep-0418
|
|
[2] Of course, we feed the Windows stuff into adjust_monotonic_time()
|
|
anyway, just in case it isn't.
|
|
|
|
*/
|
|
/*
|
|
Parts of our logic in the win32 timer code here are closely based on
|
|
BitTorrent's libUTP library. That code is subject to the following
|
|
license:
|
|
|
|
Copyright (c) 2010 BitTorrent, Inc.
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a
|
|
copy of this software and associated documentation files (the
|
|
"Software"), to deal in the Software without restriction, including
|
|
without limitation the rights to use, copy, modify, merge, publish,
|
|
distribute, sublicense, and/or sell copies of the Software, and to
|
|
permit persons to whom the Software is furnished to do so, subject to
|
|
the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included
|
|
in all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
|
|
static ev_uint64_t
|
|
evutil_GetTickCount_(struct evutil_monotonic_timer *base)
|
|
{
|
|
if (base->GetTickCount64_fn) {
|
|
/* Let's just use GetTickCount64 if we can. */
|
|
return base->GetTickCount64_fn();
|
|
} else if (base->GetTickCount_fn) {
|
|
/* Greg Hazel assures me that this works, that BitTorrent has
|
|
* done it for years, and this it won't turn around and
|
|
* bite us. He says they found it on some game programmers'
|
|
* forum some time around 2007.
|
|
*/
|
|
ev_uint64_t v = base->GetTickCount_fn();
|
|
return (DWORD)v | ((v >> 18) & 0xFFFFFFFF00000000);
|
|
} else {
|
|
/* Here's the fallback implementation. We have to use
|
|
* GetTickCount() with its given signature, so we only get
|
|
* 32 bits worth of milliseconds, which will roll ove every
|
|
* 49 days or so. */
|
|
DWORD ticks = GetTickCount();
|
|
if (ticks < base->last_tick_count) {
|
|
base->adjust_tick_count += ((ev_uint64_t)1) << 32;
|
|
}
|
|
base->last_tick_count = ticks;
|
|
return ticks + base->adjust_tick_count;
|
|
}
|
|
}
|
|
|
|
int
|
|
evutil_configure_monotonic_time_(struct evutil_monotonic_timer *base,
|
|
int flags)
|
|
{
|
|
const int precise = flags & EV_MONOT_PRECISE;
|
|
const int fallback = flags & EV_MONOT_FALLBACK;
|
|
HANDLE h;
|
|
memset(base, 0, sizeof(*base));
|
|
|
|
h = evutil_load_windows_system_library_(TEXT("kernel32.dll"));
|
|
if (h != NULL && !fallback) {
|
|
base->GetTickCount64_fn = (ev_GetTickCount_func)GetProcAddress(h, "GetTickCount64");
|
|
base->GetTickCount_fn = (ev_GetTickCount_func)GetProcAddress(h, "GetTickCount");
|
|
}
|
|
|
|
base->first_tick = base->last_tick_count = evutil_GetTickCount_(base);
|
|
if (precise && !fallback) {
|
|
LARGE_INTEGER freq;
|
|
if (QueryPerformanceFrequency(&freq)) {
|
|
LARGE_INTEGER counter;
|
|
QueryPerformanceCounter(&counter);
|
|
base->first_counter = counter.QuadPart;
|
|
base->usec_per_count = 1.0e6 / freq.QuadPart;
|
|
base->use_performance_counter = 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static inline ev_int64_t
|
|
abs64(ev_int64_t i)
|
|
{
|
|
return i < 0 ? -i : i;
|
|
}
|
|
|
|
|
|
int
|
|
evutil_gettime_monotonic_(struct evutil_monotonic_timer *base,
|
|
struct timeval *tp)
|
|
{
|
|
ev_uint64_t ticks = evutil_GetTickCount_(base);
|
|
if (base->use_performance_counter) {
|
|
/* Here's a trick we took from BitTorrent's libutp, at Greg
|
|
* Hazel's recommendation. We use QueryPerformanceCounter for
|
|
* our high-resolution timer, but use GetTickCount*() to keep
|
|
* it sane, and adjust_monotonic_time() to keep it monotonic.
|
|
*/
|
|
LARGE_INTEGER counter;
|
|
ev_int64_t counter_elapsed, counter_usec_elapsed, ticks_elapsed;
|
|
QueryPerformanceCounter(&counter);
|
|
counter_elapsed = (ev_int64_t)
|
|
(counter.QuadPart - base->first_counter);
|
|
ticks_elapsed = ticks - base->first_tick;
|
|
/* TODO: This may upset VC6. If you need this to work with
|
|
* VC6, please supply an appropriate patch. */
|
|
counter_usec_elapsed = (ev_int64_t)
|
|
(counter_elapsed * base->usec_per_count);
|
|
|
|
if (abs64(ticks_elapsed*1000 - counter_usec_elapsed) > 1000000) {
|
|
/* It appears that the QueryPerformanceCounter()
|
|
* result is more than 1 second away from
|
|
* GetTickCount() result. Let's adjust it to be as
|
|
* accurate as we can; adjust_monotnonic_time() below
|
|
* will keep it monotonic. */
|
|
counter_usec_elapsed = ticks_elapsed * 1000;
|
|
base->first_counter = (ev_uint64_t) (counter.QuadPart - counter_usec_elapsed / base->usec_per_count);
|
|
}
|
|
tp->tv_sec = (time_t) (counter_usec_elapsed / 1000000);
|
|
tp->tv_usec = counter_usec_elapsed % 1000000;
|
|
|
|
} else {
|
|
/* We're just using GetTickCount(). */
|
|
tp->tv_sec = (time_t) (ticks / 1000);
|
|
tp->tv_usec = (ticks % 1000) * 1000;
|
|
}
|
|
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
|