Mercurial > sdl-ios-xcode
comparison src/timer/unix/SDL_systimer.c @ 5113:481dabb098ef
Improved timer implementation
The new timer model is formalized as using a separate thread to handle timer callbacks. This was the case on almost every platform before, but it's now a requirement, and simplifies the implementation and makes it perform consistently across platforms.
Goals:
* Minimize timer thread blocking
* Dispatch timers as accurately as possible
* SDL_AddTimer() and SDL_RemoveTimer() are completely threadsafe
* SDL_RemoveTimer() doesn't crash with a timer that's expired or removed
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Thu, 27 Jan 2011 14:45:06 -0800 |
parents | 54cbc34229f4 |
children | b530ef003506 |
comparison
equal
deleted
inserted
replaced
5112:0846f18eb625 | 5113:481dabb098ef |
---|---|
23 | 23 |
24 #ifdef SDL_TIMER_UNIX | 24 #ifdef SDL_TIMER_UNIX |
25 | 25 |
26 #include <stdio.h> | 26 #include <stdio.h> |
27 #include <sys/time.h> | 27 #include <sys/time.h> |
28 #include <signal.h> | |
29 #include <unistd.h> | 28 #include <unistd.h> |
30 #include <string.h> | |
31 #include <errno.h> | 29 #include <errno.h> |
32 | 30 |
33 #include "SDL_timer.h" | 31 #include "SDL_timer.h" |
34 #include "../SDL_systimer.h" | |
35 #include "../SDL_timer_c.h" | |
36 | 32 |
37 /* The clock_gettime provides monotonous time, so we should use it if | 33 /* The clock_gettime provides monotonous time, so we should use it if |
38 it's available. The clock_gettime function is behind ifdef | 34 it's available. The clock_gettime function is behind ifdef |
39 for __USE_POSIX199309 | 35 for __USE_POSIX199309 |
40 Tommi Kyntola (tommi.kyntola@ray.fi) 27/09/2005 | 36 Tommi Kyntola (tommi.kyntola@ray.fi) 27/09/2005 |
41 */ | 37 */ |
42 #if HAVE_NANOSLEEP || HAVE_CLOCK_GETTIME | 38 #if HAVE_NANOSLEEP || HAVE_CLOCK_GETTIME |
43 #include <time.h> | 39 #include <time.h> |
44 #endif | |
45 | |
46 #if SDL_THREADS_DISABLED | |
47 #define USE_ITIMER | |
48 #endif | 40 #endif |
49 | 41 |
50 /* The first ticks value of the application */ | 42 /* The first ticks value of the application */ |
51 #ifdef HAVE_CLOCK_GETTIME | 43 #ifdef HAVE_CLOCK_GETTIME |
52 static struct timespec start; | 44 static struct timespec start; |
129 was_error = select(0, NULL, NULL, NULL, &tv); | 121 was_error = select(0, NULL, NULL, NULL, &tv); |
130 #endif /* HAVE_NANOSLEEP */ | 122 #endif /* HAVE_NANOSLEEP */ |
131 } while (was_error && (errno == EINTR)); | 123 } while (was_error && (errno == EINTR)); |
132 } | 124 } |
133 | 125 |
134 #ifdef USE_ITIMER | 126 #endif /* SDL_TIMER_UNIX */ |
135 | 127 |
136 static void | |
137 HandleAlarm(int sig) | |
138 { | |
139 Uint32 ms; | |
140 | |
141 if (SDL_alarm_callback) { | |
142 ms = (*SDL_alarm_callback) (SDL_alarm_interval); | |
143 if (ms != SDL_alarm_interval) { | |
144 SDL_SetTimer(ms, SDL_alarm_callback); | |
145 } | |
146 } | |
147 } | |
148 | |
149 int | |
150 SDL_SYS_TimerInit(void) | |
151 { | |
152 struct sigaction action; | |
153 | |
154 /* Set the alarm handler (Linux specific) */ | |
155 SDL_memset(&action, 0, sizeof(action)); | |
156 action.sa_handler = HandleAlarm; | |
157 action.sa_flags = SA_RESTART; | |
158 sigemptyset(&action.sa_mask); | |
159 sigaction(SIGALRM, &action, NULL); | |
160 return (0); | |
161 } | |
162 | |
163 void | |
164 SDL_SYS_TimerQuit(void) | |
165 { | |
166 SDL_SetTimer(0, NULL); | |
167 } | |
168 | |
169 int | |
170 SDL_SYS_StartTimer(void) | |
171 { | |
172 struct itimerval timer; | |
173 | |
174 timer.it_value.tv_sec = (SDL_alarm_interval / 1000); | |
175 timer.it_value.tv_usec = (SDL_alarm_interval % 1000) * 1000; | |
176 timer.it_interval.tv_sec = (SDL_alarm_interval / 1000); | |
177 timer.it_interval.tv_usec = (SDL_alarm_interval % 1000) * 1000; | |
178 setitimer(ITIMER_REAL, &timer, NULL); | |
179 return (0); | |
180 } | |
181 | |
182 void | |
183 SDL_SYS_StopTimer(void) | |
184 { | |
185 struct itimerval timer; | |
186 | |
187 SDL_memset(&timer, 0, (sizeof timer)); | |
188 setitimer(ITIMER_REAL, &timer, NULL); | |
189 } | |
190 | |
191 #else /* USE_ITIMER */ | |
192 | |
193 #include "SDL_thread.h" | |
194 | |
195 /* Data to handle a single periodic alarm */ | |
196 static int timer_alive = 0; | |
197 static SDL_Thread *timer = NULL; | |
198 | |
199 static int | |
200 RunTimer(void *unused) | |
201 { | |
202 while (timer_alive) { | |
203 if (SDL_timer_running) { | |
204 SDL_ThreadedTimerCheck(); | |
205 } | |
206 SDL_Delay(1); | |
207 } | |
208 return (0); | |
209 } | |
210 | |
211 /* This is only called if the event thread is not running */ | |
212 int | |
213 SDL_SYS_TimerInit(void) | |
214 { | |
215 timer_alive = 1; | |
216 timer = SDL_CreateThread(RunTimer, NULL); | |
217 if (timer == NULL) | |
218 return (-1); | |
219 return (SDL_SetTimerThreaded(1)); | |
220 } | |
221 | |
222 void | |
223 SDL_SYS_TimerQuit(void) | |
224 { | |
225 timer_alive = 0; | |
226 if (timer) { | |
227 SDL_WaitThread(timer, NULL); | |
228 timer = NULL; | |
229 } | |
230 } | |
231 | |
232 int | |
233 SDL_SYS_StartTimer(void) | |
234 { | |
235 SDL_SetError("Internal logic error: Linux uses threaded timer"); | |
236 return (-1); | |
237 } | |
238 | |
239 void | |
240 SDL_SYS_StopTimer(void) | |
241 { | |
242 return; | |
243 } | |
244 | |
245 #endif /* USE_ITIMER */ | |
246 | |
247 #endif /* SDL_TIMER_UNIX */ | |
248 /* vi: set ts=4 sw=4 expandtab: */ | 128 /* vi: set ts=4 sw=4 expandtab: */ |