sdl

FORK: Simple Directmedia Layer
git clone https://git.neptards.moe/neptards/sdl.git
Log | Files | Refs

SDL_systimer.c (6088B)


      1 /*
      2   Simple DirectMedia Layer
      3   Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
      4 
      5   This software is provided 'as-is', without any express or implied
      6   warranty.  In no event will the authors be held liable for any damages
      7   arising from the use of this software.
      8 
      9   Permission is granted to anyone to use this software for any purpose,
     10   including commercial applications, and to alter it and redistribute it
     11   freely, subject to the following restrictions:
     12 
     13   1. The origin of this software must not be misrepresented; you must not
     14      claim that you wrote the original software. If you use this software
     15      in a product, an acknowledgment in the product documentation would be
     16      appreciated but is not required.
     17   2. Altered source versions must be plainly marked as such, and must not be
     18      misrepresented as being the original software.
     19   3. This notice may not be removed or altered from any source distribution.
     20 */
     21 #include "../../SDL_internal.h"
     22 
     23 #ifdef SDL_TIMER_UNIX
     24 
     25 #include <stdio.h>
     26 #include <sys/time.h>
     27 #include <unistd.h>
     28 #include <errno.h>
     29 
     30 #include "SDL_timer.h"
     31 #include "SDL_hints.h"
     32 #include "../SDL_timer_c.h"
     33 
     34 #ifdef __EMSCRIPTEN__
     35 #include <emscripten.h>
     36 #endif
     37 
     38 /* The clock_gettime provides monotonous time, so we should use it if
     39    it's available. The clock_gettime function is behind ifdef
     40    for __USE_POSIX199309
     41    Tommi Kyntola (tommi.kyntola@ray.fi) 27/09/2005
     42 */
     43 /* Reworked monotonic clock to not assume the current system has one
     44    as not all linux kernels provide a monotonic clock (yeah recent ones
     45    probably do)
     46    Also added OS X Monotonic clock support
     47    Based on work in https://github.com/ThomasHabets/monotonic_clock
     48  */
     49 #if HAVE_NANOSLEEP || HAVE_CLOCK_GETTIME
     50 #include <time.h>
     51 #endif
     52 #ifdef __APPLE__
     53 #include <mach/mach_time.h>
     54 #endif
     55 
     56 /* Use CLOCK_MONOTONIC_RAW, if available, which is not subject to adjustment by NTP */
     57 #if HAVE_CLOCK_GETTIME
     58 #ifdef CLOCK_MONOTONIC_RAW
     59 #define SDL_MONOTONIC_CLOCK CLOCK_MONOTONIC_RAW
     60 #else
     61 #define SDL_MONOTONIC_CLOCK CLOCK_MONOTONIC
     62 #endif
     63 #endif
     64 
     65 /* The first ticks value of the application */
     66 #if HAVE_CLOCK_GETTIME
     67 static struct timespec start_ts;
     68 #elif defined(__APPLE__)
     69 static uint64_t start_mach;
     70 mach_timebase_info_data_t mach_base_info;
     71 #endif
     72 static SDL_bool has_monotonic_time = SDL_FALSE;
     73 static struct timeval start_tv;
     74 static SDL_bool ticks_started = SDL_FALSE;
     75 
     76 void
     77 SDL_TicksInit(void)
     78 {
     79     if (ticks_started) {
     80         return;
     81     }
     82     ticks_started = SDL_TRUE;
     83 
     84     /* Set first ticks value */
     85 #if HAVE_CLOCK_GETTIME
     86     if (clock_gettime(SDL_MONOTONIC_CLOCK, &start_ts) == 0) {
     87         has_monotonic_time = SDL_TRUE;
     88     } else
     89 #elif defined(__APPLE__)
     90     kern_return_t ret = mach_timebase_info(&mach_base_info);
     91     if (ret == 0) {
     92         has_monotonic_time = SDL_TRUE;
     93         start_mach = mach_absolute_time();
     94     } else
     95 #endif
     96     {
     97         gettimeofday(&start_tv, NULL);
     98     }
     99 }
    100 
    101 void
    102 SDL_TicksQuit(void)
    103 {
    104     ticks_started = SDL_FALSE;
    105 }
    106 
    107 Uint32
    108 SDL_GetTicks(void)
    109 {
    110     Uint32 ticks;
    111     if (!ticks_started) {
    112         SDL_TicksInit();
    113     }
    114 
    115     if (has_monotonic_time) {
    116 #if HAVE_CLOCK_GETTIME
    117         struct timespec now;
    118         clock_gettime(SDL_MONOTONIC_CLOCK, &now);
    119         ticks = (Uint32)((now.tv_sec - start_ts.tv_sec) * 1000 + (now.tv_nsec - start_ts.tv_nsec) / 1000000);
    120 #elif defined(__APPLE__)
    121         uint64_t now = mach_absolute_time();
    122         ticks = (Uint32)((((now - start_mach) * mach_base_info.numer) / mach_base_info.denom) / 1000000);
    123 #else
    124         SDL_assert(SDL_FALSE);
    125         ticks = 0;
    126 #endif
    127     } else {
    128         struct timeval now;
    129 
    130         gettimeofday(&now, NULL);
    131         ticks = (Uint32)((now.tv_sec - start_tv.tv_sec) * 1000 + (now.tv_usec - start_tv.tv_usec) / 1000);
    132     }
    133     return (ticks);
    134 }
    135 
    136 Uint64
    137 SDL_GetPerformanceCounter(void)
    138 {
    139     Uint64 ticks;
    140     if (!ticks_started) {
    141         SDL_TicksInit();
    142     }
    143 
    144     if (has_monotonic_time) {
    145 #if HAVE_CLOCK_GETTIME
    146         struct timespec now;
    147 
    148         clock_gettime(SDL_MONOTONIC_CLOCK, &now);
    149         ticks = now.tv_sec;
    150         ticks *= 1000000000;
    151         ticks += now.tv_nsec;
    152 #elif defined(__APPLE__)
    153         ticks = mach_absolute_time();
    154 #else
    155         SDL_assert(SDL_FALSE);
    156         ticks = 0;
    157 #endif
    158     } else {
    159         struct timeval now;
    160 
    161         gettimeofday(&now, NULL);
    162         ticks = now.tv_sec;
    163         ticks *= 1000000;
    164         ticks += now.tv_usec;
    165     }
    166     return (ticks);
    167 }
    168 
    169 Uint64
    170 SDL_GetPerformanceFrequency(void)
    171 {
    172     if (!ticks_started) {
    173         SDL_TicksInit();
    174     }
    175 
    176     if (has_monotonic_time) {
    177 #if HAVE_CLOCK_GETTIME
    178         return 1000000000;
    179 #elif defined(__APPLE__)
    180         Uint64 freq = mach_base_info.denom;
    181         freq *= 1000000000;
    182         freq /= mach_base_info.numer;
    183         return freq;
    184 #endif
    185     } 
    186         
    187     return 1000000;
    188 }
    189 
    190 void
    191 SDL_Delay(Uint32 ms)
    192 {
    193 #ifdef __EMSCRIPTEN__
    194     if (emscripten_has_asyncify() && SDL_GetHintBoolean(SDL_HINT_EMSCRIPTEN_ASYNCIFY, SDL_TRUE)) {
    195         /* pseudo-synchronous pause, used directly or through e.g. SDL_WaitEvent */
    196         emscripten_sleep(ms);
    197         return;
    198     }
    199 #endif
    200     int was_error;
    201 
    202 #if HAVE_NANOSLEEP
    203     struct timespec elapsed, tv;
    204 #else
    205     struct timeval tv;
    206     Uint32 then, now, elapsed;
    207 #endif
    208 
    209     /* Set the timeout interval */
    210 #if HAVE_NANOSLEEP
    211     elapsed.tv_sec = ms / 1000;
    212     elapsed.tv_nsec = (ms % 1000) * 1000000;
    213 #else
    214     then = SDL_GetTicks();
    215 #endif
    216     do {
    217         errno = 0;
    218 
    219 #if HAVE_NANOSLEEP
    220         tv.tv_sec = elapsed.tv_sec;
    221         tv.tv_nsec = elapsed.tv_nsec;
    222         was_error = nanosleep(&tv, &elapsed);
    223 #else
    224         /* Calculate the time interval left (in case of interrupt) */
    225         now = SDL_GetTicks();
    226         elapsed = (now - then);
    227         then = now;
    228         if (elapsed >= ms) {
    229             break;
    230         }
    231         ms -= elapsed;
    232         tv.tv_sec = ms / 1000;
    233         tv.tv_usec = (ms % 1000) * 1000;
    234 
    235         was_error = select(0, NULL, NULL, NULL, &tv);
    236 #endif /* HAVE_NANOSLEEP */
    237     } while (was_error && (errno == EINTR));
    238 }
    239 
    240 #endif /* SDL_TIMER_UNIX */
    241 
    242 /* vi: set ts=4 sw=4 expandtab: */