#include "SDL_internal.h"
#ifdef SDL_TIMER_UNIX
#include <stdio.h>
#include <sys/time.h>
#include <unistd.h>
#include <errno.h>
#include "../SDL_timer_c.h"
#ifdef SDL_PLATFORM_EMSCRIPTEN
#include <emscripten.h>
#endif
#if defined(HAVE_NANOSLEEP) || defined(HAVE_CLOCK_GETTIME)
#include <time.h>
#endif
#ifdef SDL_PLATFORM_APPLE
#include <mach/mach_time.h>
#endif
#ifdef HAVE_CLOCK_GETTIME
#if defined(CLOCK_MONOTONIC_RAW) && !defined(__ANDROID__)
#define SDL_MONOTONIC_CLOCK CLOCK_MONOTONIC_RAW
#else
#define SDL_MONOTONIC_CLOCK CLOCK_MONOTONIC
#endif
#endif
#if !defined(HAVE_CLOCK_GETTIME) && defined(SDL_PLATFORM_APPLE)
mach_timebase_info_data_t mach_base_info;
#endif
static bool checked_monotonic_time = false;
static bool has_monotonic_time = false;
static void CheckMonotonicTime(void)
{
#ifdef HAVE_CLOCK_GETTIME
struct timespec value;
if (clock_gettime(SDL_MONOTONIC_CLOCK, &value) == 0) {
has_monotonic_time = true;
}
#elif defined(SDL_PLATFORM_APPLE)
if (mach_timebase_info(&mach_base_info) == 0) {
has_monotonic_time = true;
}
#endif
checked_monotonic_time = true;
}
Uint64 SDL_GetPerformanceCounter(void)
{
Uint64 ticks;
if (!checked_monotonic_time) {
CheckMonotonicTime();
}
if (has_monotonic_time) {
#ifdef HAVE_CLOCK_GETTIME
struct timespec now;
clock_gettime(SDL_MONOTONIC_CLOCK, &now);
ticks = now.tv_sec;
ticks *= SDL_NS_PER_SECOND;
ticks += now.tv_nsec;
#elif defined(SDL_PLATFORM_APPLE)
ticks = mach_absolute_time();
#else
SDL_assert(false);
ticks = 0;
#endif
} else {
struct timeval now;
gettimeofday(&now, NULL);
ticks = now.tv_sec;
ticks *= SDL_US_PER_SECOND;
ticks += now.tv_usec;
}
return ticks;
}
Uint64 SDL_GetPerformanceFrequency(void)
{
if (!checked_monotonic_time) {
CheckMonotonicTime();
}
if (has_monotonic_time) {
#ifdef HAVE_CLOCK_GETTIME
return SDL_NS_PER_SECOND;
#elif defined(SDL_PLATFORM_APPLE)
Uint64 freq = mach_base_info.denom;
freq *= SDL_NS_PER_SECOND;
freq /= mach_base_info.numer;
return freq;
#endif
}
return SDL_US_PER_SECOND;
}
void SDL_SYS_DelayNS(Uint64 ns)
{
int was_error;
#ifdef HAVE_NANOSLEEP
struct timespec tv, remaining;
#else
struct timeval tv;
Uint64 then, now, elapsed;
#endif
#ifdef SDL_PLATFORM_EMSCRIPTEN
if (emscripten_has_asyncify() && SDL_GetHintBoolean(SDL_HINT_EMSCRIPTEN_ASYNCIFY, true)) {
emscripten_sleep(ns / SDL_NS_PER_MS);
return;
}
#endif
#ifdef HAVE_NANOSLEEP
remaining.tv_sec = (time_t)(ns / SDL_NS_PER_SECOND);
remaining.tv_nsec = (long)(ns % SDL_NS_PER_SECOND);
#else
then = SDL_GetTicksNS();
#endif
do {
errno = 0;
#ifdef HAVE_NANOSLEEP
tv.tv_sec = remaining.tv_sec;
tv.tv_nsec = remaining.tv_nsec;
was_error = nanosleep(&tv, &remaining);
#else
now = SDL_GetTicksNS();
elapsed = (now - then);
then = now;
if (elapsed >= ns) {
break;
}
ns -= elapsed;
tv.tv_sec = (ns / SDL_NS_PER_SECOND);
tv.tv_usec = SDL_NS_TO_US(ns % SDL_NS_PER_SECOND);
was_error = select(0, NULL, NULL, NULL, &tv);
#endif } while (was_error && (errno == EINTR));
}
#endif