Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/sdl/timer/unix/SDL_systimer.c
9905 views
1
/*
2
Simple DirectMedia Layer
3
Copyright (C) 1997-2025 Sam Lantinga <[email protected]>
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_c.h"
31
32
#ifdef SDL_PLATFORM_EMSCRIPTEN
33
#include <emscripten.h>
34
#endif
35
36
/* The clock_gettime provides monotonous time, so we should use it if
37
it's available. The clock_gettime function is behind ifdef
38
for __USE_POSIX199309
39
Tommi Kyntola ([email protected]) 27/09/2005
40
*/
41
/* Reworked monotonic clock to not assume the current system has one
42
as not all linux kernels provide a monotonic clock (yeah recent ones
43
probably do)
44
Also added macOS Monotonic clock support
45
Based on work in https://github.com/ThomasHabets/monotonic_clock
46
*/
47
#if defined(HAVE_NANOSLEEP) || defined(HAVE_CLOCK_GETTIME)
48
#include <time.h>
49
#endif
50
#ifdef SDL_PLATFORM_APPLE
51
#include <mach/mach_time.h>
52
#endif
53
54
// Use CLOCK_MONOTONIC_RAW, if available, which is not subject to adjustment by NTP
55
#ifdef HAVE_CLOCK_GETTIME
56
#ifdef CLOCK_MONOTONIC_RAW
57
#define SDL_MONOTONIC_CLOCK CLOCK_MONOTONIC_RAW
58
#else
59
#define SDL_MONOTONIC_CLOCK CLOCK_MONOTONIC
60
#endif
61
#endif
62
63
// The first ticks value of the application
64
#if !defined(HAVE_CLOCK_GETTIME) && defined(SDL_PLATFORM_APPLE)
65
mach_timebase_info_data_t mach_base_info;
66
#endif
67
static bool checked_monotonic_time = false;
68
static bool has_monotonic_time = false;
69
70
static void CheckMonotonicTime(void)
71
{
72
#ifdef HAVE_CLOCK_GETTIME
73
struct timespec value;
74
if (clock_gettime(SDL_MONOTONIC_CLOCK, &value) == 0) {
75
has_monotonic_time = true;
76
}
77
#elif defined(SDL_PLATFORM_APPLE)
78
if (mach_timebase_info(&mach_base_info) == 0) {
79
has_monotonic_time = true;
80
}
81
#endif
82
checked_monotonic_time = true;
83
}
84
85
Uint64 SDL_GetPerformanceCounter(void)
86
{
87
Uint64 ticks;
88
89
if (!checked_monotonic_time) {
90
CheckMonotonicTime();
91
}
92
93
if (has_monotonic_time) {
94
#ifdef HAVE_CLOCK_GETTIME
95
struct timespec now;
96
97
clock_gettime(SDL_MONOTONIC_CLOCK, &now);
98
ticks = now.tv_sec;
99
ticks *= SDL_NS_PER_SECOND;
100
ticks += now.tv_nsec;
101
#elif defined(SDL_PLATFORM_APPLE)
102
ticks = mach_absolute_time();
103
#else
104
SDL_assert(false);
105
ticks = 0;
106
#endif
107
} else {
108
struct timeval now;
109
110
gettimeofday(&now, NULL);
111
ticks = now.tv_sec;
112
ticks *= SDL_US_PER_SECOND;
113
ticks += now.tv_usec;
114
}
115
return ticks;
116
}
117
118
Uint64 SDL_GetPerformanceFrequency(void)
119
{
120
if (!checked_monotonic_time) {
121
CheckMonotonicTime();
122
}
123
124
if (has_monotonic_time) {
125
#ifdef HAVE_CLOCK_GETTIME
126
return SDL_NS_PER_SECOND;
127
#elif defined(SDL_PLATFORM_APPLE)
128
Uint64 freq = mach_base_info.denom;
129
freq *= SDL_NS_PER_SECOND;
130
freq /= mach_base_info.numer;
131
return freq;
132
#endif
133
}
134
135
return SDL_US_PER_SECOND;
136
}
137
138
void SDL_SYS_DelayNS(Uint64 ns)
139
{
140
int was_error;
141
142
#ifdef HAVE_NANOSLEEP
143
struct timespec tv, remaining;
144
#else
145
struct timeval tv;
146
Uint64 then, now, elapsed;
147
#endif
148
149
#ifdef SDL_PLATFORM_EMSCRIPTEN
150
if (emscripten_has_asyncify() && SDL_GetHintBoolean(SDL_HINT_EMSCRIPTEN_ASYNCIFY, true)) {
151
// pseudo-synchronous pause, used directly or through e.g. SDL_WaitEvent
152
emscripten_sleep(ns / SDL_NS_PER_MS);
153
return;
154
}
155
#endif
156
157
// Set the timeout interval
158
#ifdef HAVE_NANOSLEEP
159
remaining.tv_sec = (time_t)(ns / SDL_NS_PER_SECOND);
160
remaining.tv_nsec = (long)(ns % SDL_NS_PER_SECOND);
161
#else
162
then = SDL_GetTicksNS();
163
#endif
164
do {
165
errno = 0;
166
167
#ifdef HAVE_NANOSLEEP
168
tv.tv_sec = remaining.tv_sec;
169
tv.tv_nsec = remaining.tv_nsec;
170
was_error = nanosleep(&tv, &remaining);
171
#else
172
// Calculate the time interval left (in case of interrupt)
173
now = SDL_GetTicksNS();
174
elapsed = (now - then);
175
then = now;
176
if (elapsed >= ns) {
177
break;
178
}
179
ns -= elapsed;
180
tv.tv_sec = (ns / SDL_NS_PER_SECOND);
181
tv.tv_usec = SDL_NS_TO_US(ns % SDL_NS_PER_SECOND);
182
183
was_error = select(0, NULL, NULL, NULL, &tv);
184
#endif // HAVE_NANOSLEEP
185
} while (was_error && (errno == EINTR));
186
}
187
188
#endif // SDL_TIMER_UNIX
189
190