#ifndef __DISPATCH_SHIMS_TIME__
#define __DISPATCH_SHIMS_TIME__
#ifndef __DISPATCH_INDIRECT__
#error "Please #include <dispatch/dispatch.h> instead of this file directly."
#endif
#if TARGET_OS_WIN32
static inline unsigned int
sleep(unsigned int seconds)
{
Sleep(seconds * 1000); return 0;
}
#endif
typedef enum {
DISPATCH_CLOCK_UPTIME,
DISPATCH_CLOCK_MONOTONIC,
DISPATCH_CLOCK_WALL,
#define DISPATCH_CLOCK_COUNT (DISPATCH_CLOCK_WALL + 1)
} dispatch_clock_t;
void _dispatch_time_init(void);
#if defined(__i386__) || defined(__x86_64__) || !HAVE_MACH_ABSOLUTE_TIME
#define DISPATCH_TIME_UNIT_USES_NANOSECONDS 1
#else
#define DISPATCH_TIME_UNIT_USES_NANOSECONDS 0
#endif
#if DISPATCH_TIME_UNIT_USES_NANOSECONDS
DISPATCH_ALWAYS_INLINE
static inline uint64_t
_dispatch_time_mach2nano(uint64_t machtime)
{
return machtime;
}
DISPATCH_ALWAYS_INLINE
static inline uint64_t
_dispatch_time_nano2mach(uint64_t nsec)
{
return nsec;
}
#else
#define DISPATCH_USE_HOST_TIME 1
extern uint64_t (*_dispatch_host_time_mach2nano)(uint64_t machtime);
extern uint64_t (*_dispatch_host_time_nano2mach)(uint64_t nsec);
static inline uint64_t
_dispatch_time_mach2nano(uint64_t machtime)
{
return _dispatch_host_time_mach2nano(machtime);
}
static inline uint64_t
_dispatch_time_nano2mach(uint64_t nsec)
{
return _dispatch_host_time_nano2mach(nsec);
}
#endif // DISPATCH_USE_HOST_TIME
#define _dispatch_timespec_to_nano(ts) \
((uint64_t)(ts).tv_sec * NSEC_PER_SEC + (uint64_t)(ts).tv_nsec)
#define _dispatch_timeval_to_nano(tv) \
((uint64_t)(tv).tv_sec * NSEC_PER_SEC + \
(uint64_t)(tv).tv_usec * NSEC_PER_USEC)
static inline uint64_t
_dispatch_get_nanoseconds(void)
{
dispatch_static_assert(sizeof(NSEC_PER_SEC) == 8);
dispatch_static_assert(sizeof(USEC_PER_SEC) == 8);
#if TARGET_OS_MAC
return clock_gettime_nsec_np(CLOCK_REALTIME);
#elif HAVE_DECL_CLOCK_REALTIME
struct timespec ts;
dispatch_assume_zero(clock_gettime(CLOCK_REALTIME, &ts));
return _dispatch_timespec_to_nano(ts);
#elif TARGET_OS_WIN32
FILETIME ft;
ULARGE_INTEGER li;
GetSystemTimeAsFileTime(&ft);
li.LowPart = ft.dwLowDateTime;
li.HighPart = ft.dwHighDateTime;
return li.QuadPart * 100ull;
#else
struct timeval tv;
dispatch_assert_zero(gettimeofday(&tv, NULL));
return _dispatch_timeval_to_nano(tv);
#endif
}
static inline uint64_t
_dispatch_uptime(void)
{
#if HAVE_MACH_ABSOLUTE_TIME
return mach_absolute_time();
#elif defined(__linux__)
struct timespec ts;
dispatch_assume_zero(clock_gettime(CLOCK_MONOTONIC, &ts));
return _dispatch_timespec_to_nano(ts);
#elif HAVE_DECL_CLOCK_UPTIME
struct timespec ts;
dispatch_assume_zero(clock_gettime(CLOCK_UPTIME, &ts));
return _dispatch_timespec_to_nano(ts);
#elif TARGET_OS_WIN32
LARGE_INTEGER now;
return QueryPerformanceCounter(&now) ? now.QuadPart : 0;
#else
#error platform needs to implement _dispatch_uptime()
#endif
}
static inline uint64_t
_dispatch_monotonic_time(void)
{
#if HAVE_MACH_ABSOLUTE_TIME
return mach_continuous_time();
#elif defined(__linux__)
struct timespec ts;
dispatch_assume_zero(clock_gettime(CLOCK_BOOTTIME, &ts));
return _dispatch_timespec_to_nano(ts);
#elif HAVE_DECL_CLOCK_MONOTONIC
struct timespec ts;
dispatch_assume_zero(clock_gettime(CLOCK_MONOTONIC, &ts));
return _dispatch_timespec_to_nano(ts);
#elif TARGET_OS_WIN32
LARGE_INTEGER now;
return QueryPerformanceCounter(&now) ? now.QuadPart : 0;
#else
#error platform needs to implement _dispatch_monotonic_time()
#endif
}
DISPATCH_ALWAYS_INLINE
static inline uint64_t
_dispatch_approximate_time(void)
{
#if HAVE_MACH_APPROXIMATE_TIME
return mach_approximate_time();
#elif defined(__linux__)
struct timespec ts;
dispatch_assume_zero(clock_gettime(CLOCK_MONOTONIC_COARSE, &ts));
return _dispatch_timespec_to_nano(ts);
#elif HAVE_DECL_CLOCK_UPTIME_FAST
struct timespec ts;
dispatch_assume_zero(clock_gettime(CLOCK_UPTIME_FAST, &ts));
return _dispatch_timespec_to_nano(ts);
#else
return _dispatch_uptime();
#endif
}
DISPATCH_ALWAYS_INLINE
static inline uint64_t
_dispatch_time_now(dispatch_clock_t clock)
{
switch (clock) {
case DISPATCH_CLOCK_UPTIME:
return _dispatch_uptime();
case DISPATCH_CLOCK_MONOTONIC:
return _dispatch_monotonic_time();
case DISPATCH_CLOCK_WALL:
return _dispatch_get_nanoseconds();
}
__builtin_unreachable();
}
typedef struct {
uint64_t nows[DISPATCH_CLOCK_COUNT];
} dispatch_clock_now_cache_s, *dispatch_clock_now_cache_t;
DISPATCH_ALWAYS_INLINE
static inline uint64_t
_dispatch_time_now_cached(dispatch_clock_t clock,
dispatch_clock_now_cache_t cache)
{
if (likely(cache->nows[clock])) {
return cache->nows[clock];
}
#if TARGET_OS_MAC
struct timespec ts;
mach_get_times(&cache->nows[DISPATCH_CLOCK_UPTIME],
&cache->nows[DISPATCH_CLOCK_MONOTONIC], &ts);
cache->nows[DISPATCH_CLOCK_WALL] = _dispatch_timespec_to_nano(ts);
#else
cache->nows[clock] = _dispatch_time_now(clock);
#endif
return cache->nows[clock];
}
#define DISPATCH_UP_OR_MONOTONIC_TIME_MASK (1ULL << 63)
#define DISPATCH_WALLTIME_MASK (1ULL << 62)
#define DISPATCH_TIME_MAX_VALUE (DISPATCH_WALLTIME_MASK - 1)
DISPATCH_ALWAYS_INLINE
static inline void
_dispatch_time_to_clock_and_value(dispatch_time_t time,
dispatch_clock_t *clock, uint64_t *value)
{
uint64_t actual_value;
if ((int64_t)time < 0) {
if (time & DISPATCH_WALLTIME_MASK) {
*clock = DISPATCH_CLOCK_WALL;
actual_value = time == DISPATCH_WALLTIME_NOW ?
_dispatch_get_nanoseconds() : (uint64_t)-time;
} else {
*clock = DISPATCH_CLOCK_MONOTONIC;
actual_value = time & ~DISPATCH_UP_OR_MONOTONIC_TIME_MASK;
}
} else {
*clock = DISPATCH_CLOCK_UPTIME;
actual_value = time;
}
*value = actual_value > DISPATCH_TIME_MAX_VALUE ? DISPATCH_TIME_FOREVER
: actual_value;
}
DISPATCH_ALWAYS_INLINE
static inline dispatch_time_t
_dispatch_clock_and_value_to_time(dispatch_clock_t clock, uint64_t value)
{
if (value >= DISPATCH_TIME_MAX_VALUE) {
return DISPATCH_TIME_FOREVER;
}
switch (clock) {
case DISPATCH_CLOCK_WALL:
return -value;
case DISPATCH_CLOCK_UPTIME:
return value;
case DISPATCH_CLOCK_MONOTONIC:
return value | DISPATCH_UP_OR_MONOTONIC_TIME_MASK;
}
__builtin_unreachable();
}
#endif // __DISPATCH_SHIMS_TIME__