Path: blob/master/thirdparty/sdl/timer/unix/SDL_systimer.c
9905 views
/*1Simple DirectMedia Layer2Copyright (C) 1997-2025 Sam Lantinga <[email protected]>34This software is provided 'as-is', without any express or implied5warranty. In no event will the authors be held liable for any damages6arising from the use of this software.78Permission is granted to anyone to use this software for any purpose,9including commercial applications, and to alter it and redistribute it10freely, subject to the following restrictions:11121. The origin of this software must not be misrepresented; you must not13claim that you wrote the original software. If you use this software14in a product, an acknowledgment in the product documentation would be15appreciated but is not required.162. Altered source versions must be plainly marked as such, and must not be17misrepresented as being the original software.183. This notice may not be removed or altered from any source distribution.19*/20#include "SDL_internal.h"2122#ifdef SDL_TIMER_UNIX2324#include <stdio.h>25#include <sys/time.h>26#include <unistd.h>27#include <errno.h>2829#include "../SDL_timer_c.h"3031#ifdef SDL_PLATFORM_EMSCRIPTEN32#include <emscripten.h>33#endif3435/* The clock_gettime provides monotonous time, so we should use it if36it's available. The clock_gettime function is behind ifdef37for __USE_POSIX19930938Tommi Kyntola ([email protected]) 27/09/200539*/40/* Reworked monotonic clock to not assume the current system has one41as not all linux kernels provide a monotonic clock (yeah recent ones42probably do)43Also added macOS Monotonic clock support44Based on work in https://github.com/ThomasHabets/monotonic_clock45*/46#if defined(HAVE_NANOSLEEP) || defined(HAVE_CLOCK_GETTIME)47#include <time.h>48#endif49#ifdef SDL_PLATFORM_APPLE50#include <mach/mach_time.h>51#endif5253// Use CLOCK_MONOTONIC_RAW, if available, which is not subject to adjustment by NTP54#ifdef HAVE_CLOCK_GETTIME55#ifdef CLOCK_MONOTONIC_RAW56#define SDL_MONOTONIC_CLOCK CLOCK_MONOTONIC_RAW57#else58#define SDL_MONOTONIC_CLOCK CLOCK_MONOTONIC59#endif60#endif6162// The first ticks value of the application63#if !defined(HAVE_CLOCK_GETTIME) && defined(SDL_PLATFORM_APPLE)64mach_timebase_info_data_t mach_base_info;65#endif66static bool checked_monotonic_time = false;67static bool has_monotonic_time = false;6869static void CheckMonotonicTime(void)70{71#ifdef HAVE_CLOCK_GETTIME72struct timespec value;73if (clock_gettime(SDL_MONOTONIC_CLOCK, &value) == 0) {74has_monotonic_time = true;75}76#elif defined(SDL_PLATFORM_APPLE)77if (mach_timebase_info(&mach_base_info) == 0) {78has_monotonic_time = true;79}80#endif81checked_monotonic_time = true;82}8384Uint64 SDL_GetPerformanceCounter(void)85{86Uint64 ticks;8788if (!checked_monotonic_time) {89CheckMonotonicTime();90}9192if (has_monotonic_time) {93#ifdef HAVE_CLOCK_GETTIME94struct timespec now;9596clock_gettime(SDL_MONOTONIC_CLOCK, &now);97ticks = now.tv_sec;98ticks *= SDL_NS_PER_SECOND;99ticks += now.tv_nsec;100#elif defined(SDL_PLATFORM_APPLE)101ticks = mach_absolute_time();102#else103SDL_assert(false);104ticks = 0;105#endif106} else {107struct timeval now;108109gettimeofday(&now, NULL);110ticks = now.tv_sec;111ticks *= SDL_US_PER_SECOND;112ticks += now.tv_usec;113}114return ticks;115}116117Uint64 SDL_GetPerformanceFrequency(void)118{119if (!checked_monotonic_time) {120CheckMonotonicTime();121}122123if (has_monotonic_time) {124#ifdef HAVE_CLOCK_GETTIME125return SDL_NS_PER_SECOND;126#elif defined(SDL_PLATFORM_APPLE)127Uint64 freq = mach_base_info.denom;128freq *= SDL_NS_PER_SECOND;129freq /= mach_base_info.numer;130return freq;131#endif132}133134return SDL_US_PER_SECOND;135}136137void SDL_SYS_DelayNS(Uint64 ns)138{139int was_error;140141#ifdef HAVE_NANOSLEEP142struct timespec tv, remaining;143#else144struct timeval tv;145Uint64 then, now, elapsed;146#endif147148#ifdef SDL_PLATFORM_EMSCRIPTEN149if (emscripten_has_asyncify() && SDL_GetHintBoolean(SDL_HINT_EMSCRIPTEN_ASYNCIFY, true)) {150// pseudo-synchronous pause, used directly or through e.g. SDL_WaitEvent151emscripten_sleep(ns / SDL_NS_PER_MS);152return;153}154#endif155156// Set the timeout interval157#ifdef HAVE_NANOSLEEP158remaining.tv_sec = (time_t)(ns / SDL_NS_PER_SECOND);159remaining.tv_nsec = (long)(ns % SDL_NS_PER_SECOND);160#else161then = SDL_GetTicksNS();162#endif163do {164errno = 0;165166#ifdef HAVE_NANOSLEEP167tv.tv_sec = remaining.tv_sec;168tv.tv_nsec = remaining.tv_nsec;169was_error = nanosleep(&tv, &remaining);170#else171// Calculate the time interval left (in case of interrupt)172now = SDL_GetTicksNS();173elapsed = (now - then);174then = now;175if (elapsed >= ns) {176break;177}178ns -= elapsed;179tv.tv_sec = (ns / SDL_NS_PER_SECOND);180tv.tv_usec = SDL_NS_TO_US(ns % SDL_NS_PER_SECOND);181182was_error = select(0, NULL, NULL, NULL, &tv);183#endif // HAVE_NANOSLEEP184} while (was_error && (errno == EINTR));185}186187#endif // SDL_TIMER_UNIX188189190