1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2021 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
67static struct timespec start_ts;
68#elif defined(__APPLE__)
69static uint64_t start_mach;
70mach_timebase_info_data_t mach_base_info;
71#endif
72static SDL_bool has_monotonic_time = SDL_FALSE;
73static struct timeval start_tv;
74static SDL_bool ticks_started = SDL_FALSE;
75
76void
77SDL_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
101void
102SDL_TicksQuit(void)
103{
104 ticks_started = SDL_FALSE;
105}
106
107Uint32
108SDL_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
136Uint64
137SDL_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
169Uint64
170SDL_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
190void
191SDL_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: */
243