SDL_systimer.c (5520B)
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2014 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_assert.h" 32 33/* The clock_gettime provides monotonous time, so we should use it if 34 it's available. The clock_gettime function is behind ifdef 35 for __USE_POSIX199309 36 Tommi Kyntola (tommi.kyntola@ray.fi) 27/09/2005 37*/ 38/* Reworked monotonic clock to not assume the current system has one 39 as not all linux kernels provide a monotonic clock (yeah recent ones 40 probably do) 41 Also added OS X Monotonic clock support 42 Based on work in https://github.com/ThomasHabets/monotonic_clock 43 */ 44#if HAVE_NANOSLEEP || HAVE_CLOCK_GETTIME 45#include <time.h> 46#endif 47#ifdef __APPLE__ 48#include <mach/mach_time.h> 49#endif 50 51/* The first ticks value of the application */ 52#if HAVE_CLOCK_GETTIME 53static struct timespec start_ts; 54#elif defined(__APPLE__) 55static uint64_t start_mach; 56mach_timebase_info_data_t mach_base_info; 57#endif 58static SDL_bool has_monotonic_time = SDL_FALSE; 59static struct timeval start_tv; 60static SDL_bool ticks_started = SDL_FALSE; 61 62void 63SDL_TicksInit(void) 64{ 65 if (ticks_started) { 66 return; 67 } 68 ticks_started = SDL_TRUE; 69 70 /* Set first ticks value */ 71#if HAVE_CLOCK_GETTIME 72 if (clock_gettime(CLOCK_MONOTONIC, &start_ts) == 0) { 73 has_monotonic_time = SDL_TRUE; 74 } else 75#elif defined(__APPLE__) 76 kern_return_t ret = mach_timebase_info(&mach_base_info); 77 if (ret == 0) { 78 has_monotonic_time = SDL_TRUE; 79 start_mach = mach_absolute_time(); 80 } else 81#endif 82 { 83 gettimeofday(&start_tv, NULL); 84 } 85} 86 87void 88SDL_TicksQuit(void) 89{ 90 ticks_started = SDL_FALSE; 91} 92 93Uint32 94SDL_GetTicks(void) 95{ 96 Uint32 ticks; 97 if (!ticks_started) { 98 SDL_TicksInit(); 99 } 100 101 if (has_monotonic_time) { 102#if HAVE_CLOCK_GETTIME 103 struct timespec now; 104 clock_gettime(CLOCK_MONOTONIC, &now); 105 ticks = (now.tv_sec - start_ts.tv_sec) * 1000 + (now.tv_nsec - 106 start_ts.tv_nsec) / 1000000; 107#elif defined(__APPLE__) 108 uint64_t now = mach_absolute_time(); 109 ticks = (Uint32)((((now - start_mach) * mach_base_info.numer) / mach_base_info.denom) / 1000000); 110#else 111 SDL_assert(SDL_FALSE); 112 ticks = 0; 113#endif 114 } else { 115 struct timeval now; 116 117 gettimeofday(&now, NULL); 118 ticks = (Uint32)((now.tv_sec - start_tv.tv_sec) * 1000 + (now.tv_usec - start_tv.tv_usec) / 1000); 119 } 120 return (ticks); 121} 122 123Uint64 124SDL_GetPerformanceCounter(void) 125{ 126 Uint64 ticks; 127 if (!ticks_started) { 128 SDL_TicksInit(); 129 } 130 131 if (has_monotonic_time) { 132#if HAVE_CLOCK_GETTIME 133 struct timespec now; 134 135 clock_gettime(CLOCK_MONOTONIC, &now); 136 ticks = now.tv_sec; 137 ticks *= 1000000000; 138 ticks += now.tv_nsec; 139#elif defined(__APPLE__) 140 ticks = mach_absolute_time(); 141#else 142 SDL_assert(SDL_FALSE); 143 ticks = 0; 144#endif 145 } else { 146 struct timeval now; 147 148 gettimeofday(&now, NULL); 149 ticks = now.tv_sec; 150 ticks *= 1000000; 151 ticks += now.tv_usec; 152 } 153 return (ticks); 154} 155 156Uint64 157SDL_GetPerformanceFrequency(void) 158{ 159 if (!ticks_started) { 160 SDL_TicksInit(); 161 } 162 163 if (has_monotonic_time) { 164#if HAVE_CLOCK_GETTIME 165 return 1000000000; 166#elif defined(__APPLE__) 167 Uint64 freq = mach_base_info.denom; 168 freq *= 1000000000; 169 freq /= mach_base_info.numer; 170 return freq; 171#endif 172 } 173 174 return 1000000; 175} 176 177void 178SDL_Delay(Uint32 ms) 179{ 180 int was_error; 181 182#if HAVE_NANOSLEEP 183 struct timespec elapsed, tv; 184#else 185 struct timeval tv; 186 Uint32 then, now, elapsed; 187#endif 188 189 /* Set the timeout interval */ 190#if HAVE_NANOSLEEP 191 elapsed.tv_sec = ms / 1000; 192 elapsed.tv_nsec = (ms % 1000) * 1000000; 193#else 194 then = SDL_GetTicks(); 195#endif 196 do { 197 errno = 0; 198 199#if HAVE_NANOSLEEP 200 tv.tv_sec = elapsed.tv_sec; 201 tv.tv_nsec = elapsed.tv_nsec; 202 was_error = nanosleep(&tv, &elapsed); 203#else 204 /* Calculate the time interval left (in case of interrupt) */ 205 now = SDL_GetTicks(); 206 elapsed = (now - then); 207 then = now; 208 if (elapsed >= ms) { 209 break; 210 } 211 ms -= elapsed; 212 tv.tv_sec = ms / 1000; 213 tv.tv_usec = (ms % 1000) * 1000; 214 215 was_error = select(0, NULL, NULL, NULL, &tv); 216#endif /* HAVE_NANOSLEEP */ 217 } while (was_error && (errno == EINTR)); 218} 219 220#endif /* SDL_TIMER_UNIX */ 221 222/* vi: set ts=4 sw=4 expandtab: */