2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2009 Sam Lantinga
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 #include "SDL_config.h"
24 #include "SDL_timer.h"
25 #include "SDL_timer_c.h"
26 #include "SDL_mutex.h"
27 #include "SDL_systimer.h"
29 /* #define DEBUG_TIMERS */
31 int SDL_timer_started = 0;
32 int SDL_timer_running = 0;
34 /* Data to handle a single periodic alarm */
35 Uint32 SDL_alarm_interval = 0;
36 SDL_TimerCallback SDL_alarm_callback;
38 /* Data used for a thread-based timer */
39 static int SDL_timer_threaded = 0;
43 SDL_NewTimerCallback cb;
46 struct _SDL_TimerID *next;
49 static SDL_TimerID SDL_timers = NULL;
50 static SDL_mutex *SDL_timer_mutex;
51 static volatile SDL_bool list_changed = SDL_FALSE;
53 /* Set whether or not the timer should use a thread.
54 This should not be called while the timer subsystem is running.
56 int SDL_SetTimerThreaded(int value)
60 if ( SDL_timer_started ) {
61 SDL_SetError("Timer already initialized");
65 SDL_timer_threaded = value;
70 int SDL_TimerInit(void)
75 if ( SDL_timer_started ) {
78 if ( ! SDL_timer_threaded ) {
79 retval = SDL_SYS_TimerInit();
81 if ( SDL_timer_threaded ) {
82 SDL_timer_mutex = SDL_CreateMutex();
85 SDL_timer_started = 1;
90 void SDL_TimerQuit(void)
92 SDL_SetTimer(0, NULL);
93 if ( SDL_timer_threaded < 2 ) {
96 if ( SDL_timer_threaded ) {
97 SDL_DestroyMutex(SDL_timer_mutex);
98 SDL_timer_mutex = NULL;
100 SDL_timer_started = 0;
101 SDL_timer_threaded = 0;
104 void SDL_ThreadedTimerCheck(void)
107 SDL_TimerID t, prev, next;
110 SDL_mutexP(SDL_timer_mutex);
111 list_changed = SDL_FALSE;
112 now = SDL_GetTicks();
113 for ( prev = NULL, t = SDL_timers; t; t = next ) {
115 ms = t->interval - SDL_TIMESLICE;
117 if ( (int)(now - t->last_alarm) > (int)ms ) {
118 struct _SDL_TimerID timer;
120 if ( (now - t->last_alarm) < t->interval ) {
121 t->last_alarm += t->interval;
126 printf("Executing timer %p (thread = %d)\n",
130 SDL_mutexV(SDL_timer_mutex);
131 ms = timer.cb(timer.interval, timer.param);
132 SDL_mutexP(SDL_timer_mutex);
133 if ( list_changed ) {
134 /* Abort, list of timers modified */
135 /* FIXME: what if ms was changed? */
138 if ( ms != t->interval ) {
140 t->interval = ROUND_RESOLUTION(ms);
142 /* Remove timer from the list */
144 printf("SDL: Removing timer %p\n", t);
157 /* Don't update prev if the timer has disappeared */
162 SDL_mutexV(SDL_timer_mutex);
165 static SDL_TimerID SDL_AddTimerInternal(Uint32 interval, SDL_NewTimerCallback callback, void *param)
168 t = (SDL_TimerID) SDL_malloc(sizeof(struct _SDL_TimerID));
170 t->interval = ROUND_RESOLUTION(interval);
173 t->last_alarm = SDL_GetTicks();
174 t->next = SDL_timers;
177 list_changed = SDL_TRUE;
180 printf("SDL_AddTimer(%d) = %08x num_timers = %d\n", interval, (Uint32)t, SDL_timer_running);
185 SDL_TimerID SDL_AddTimer(Uint32 interval, SDL_NewTimerCallback callback, void *param)
188 if ( ! SDL_timer_mutex ) {
189 if ( SDL_timer_started ) {
190 SDL_SetError("This platform doesn't support multiple timers");
192 SDL_SetError("You must call SDL_Init(SDL_INIT_TIMER) first");
196 if ( ! SDL_timer_threaded ) {
197 SDL_SetError("Multiple timers require threaded events!");
200 SDL_mutexP(SDL_timer_mutex);
201 t = SDL_AddTimerInternal(interval, callback, param);
202 SDL_mutexV(SDL_timer_mutex);
206 SDL_bool SDL_RemoveTimer(SDL_TimerID id)
208 SDL_TimerID t, prev = NULL;
212 SDL_mutexP(SDL_timer_mutex);
213 /* Look for id in the linked list of timers */
214 for (t = SDL_timers; t; prev=t, t = t->next ) {
217 prev->next = t->next;
219 SDL_timers = t->next;
224 list_changed = SDL_TRUE;
229 printf("SDL_RemoveTimer(%08x) = %d num_timers = %d thread = %d\n", (Uint32)id, removed, SDL_timer_running, SDL_ThreadID());
231 SDL_mutexV(SDL_timer_mutex);
235 /* Old style callback functions are wrapped through this */
236 static Uint32 SDLCALL callback_wrapper(Uint32 ms, void *param)
238 SDL_TimerCallback func = (SDL_TimerCallback) param;
242 int SDL_SetTimer(Uint32 ms, SDL_TimerCallback callback)
247 printf("SDL_SetTimer(%d)\n", ms);
251 if ( SDL_timer_threaded ) {
252 SDL_mutexP(SDL_timer_mutex);
254 if ( SDL_timer_running ) { /* Stop any currently running timer */
255 if ( SDL_timer_threaded ) {
256 while ( SDL_timers ) {
257 SDL_TimerID freeme = SDL_timers;
258 SDL_timers = SDL_timers->next;
261 SDL_timer_running = 0;
262 list_changed = SDL_TRUE;
265 SDL_timer_running = 0;
269 if ( SDL_timer_threaded ) {
270 if ( SDL_AddTimerInternal(ms, callback_wrapper, (void *)callback) == NULL ) {
274 SDL_timer_running = 1;
275 SDL_alarm_interval = ms;
276 SDL_alarm_callback = callback;
277 retval = SDL_SYS_StartTimer();
280 if ( SDL_timer_threaded ) {
281 SDL_mutexV(SDL_timer_mutex);