comparison src/timer/SDL_timer.c @ 1:cf2af46e9e2a

Changes since SDL 1.2.0 release
author Sam Lantinga <slouken@lokigames.com>
date Thu, 26 Apr 2001 16:50:19 +0000
parents
children e8157fcb3114
comparison
equal deleted inserted replaced
0:74212992fb08 1:cf2af46e9e2a
1 /*
2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997, 1998 Sam Lantinga
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
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 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with this library; if not, write to the Free
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
19 Sam Lantinga
20 5635-34 Springhouse Dr.
21 Pleasanton, CA 94588 (USA)
22 slouken@devolution.com
23 */
24
25 #ifdef SAVE_RCSID
26 static char rcsid =
27 "@(#) $Id$";
28 #endif
29
30 #include <stdlib.h>
31 #include <stdio.h> /* For the definition of NULL */
32
33 #include "SDL_error.h"
34 #include "SDL_timer.h"
35 #include "SDL_timer_c.h"
36 #include "SDL_mutex.h"
37 #include "SDL_systimer.h"
38
39 /* #define DEBUG_TIMERS */
40
41 int SDL_timer_started = 0;
42 int SDL_timer_running = 0;
43
44 /* Data to handle a single periodic alarm */
45 Uint32 SDL_alarm_interval = 0;
46 SDL_TimerCallback SDL_alarm_callback;
47
48 static SDL_bool list_changed = SDL_FALSE;
49
50 /* Data used for a thread-based timer */
51 static int SDL_timer_threaded = 0;
52
53 struct _SDL_TimerID {
54 Uint32 interval;
55 SDL_NewTimerCallback cb;
56 void *param;
57 Uint32 last_alarm;
58 struct _SDL_TimerID *next;
59 };
60
61 static SDL_TimerID SDL_timers = NULL;
62 static Uint32 num_timers = 0;
63 static SDL_mutex *SDL_timer_mutex;
64
65 /* Set whether or not the timer should use a thread.
66 This should not be called while the timer subsystem is running.
67 */
68 int SDL_SetTimerThreaded(int value)
69 {
70 int retval;
71
72 if ( SDL_timer_started ) {
73 SDL_SetError("Timer already initialized");
74 retval = -1;
75 } else {
76 retval = 0;
77 SDL_timer_threaded = value;
78 }
79 return retval;
80 }
81
82 int SDL_TimerInit(void)
83 {
84 int retval;
85
86 SDL_timer_running = 0;
87 SDL_SetTimer(0, NULL);
88 retval = 0;
89 if ( ! SDL_timer_threaded ) {
90 retval = SDL_SYS_TimerInit();
91 }
92 if ( SDL_timer_threaded ) {
93 SDL_timer_mutex = SDL_CreateMutex();
94 }
95 SDL_timer_started = 1;
96 return(retval);
97 }
98
99 void SDL_TimerQuit(void)
100 {
101 SDL_SetTimer(0, NULL);
102 if ( SDL_timer_threaded < 2 ) {
103 SDL_SYS_TimerQuit();
104 }
105 if ( SDL_timer_threaded ) {
106 SDL_DestroyMutex(SDL_timer_mutex);
107 }
108 SDL_timer_started = 0;
109 SDL_timer_threaded = 0;
110 }
111
112 void SDL_ThreadedTimerCheck(void)
113 {
114 Uint32 now, ms;
115 SDL_TimerID t, prev, next;
116 int removed;
117
118 now = SDL_GetTicks();
119
120 SDL_mutexP(SDL_timer_mutex);
121 for ( prev = NULL, t = SDL_timers; t; t = next ) {
122 removed = 0;
123 ms = t->interval - SDL_TIMESLICE;
124 next = t->next;
125 if ( (t->last_alarm < now) && ((now - t->last_alarm) > ms) ) {
126 if ( (now - t->last_alarm) < t->interval ) {
127 t->last_alarm += t->interval;
128 } else {
129 t->last_alarm = now;
130 }
131 list_changed = SDL_FALSE;
132 #ifdef DEBUG_TIMERS
133 printf("Executing timer %p (thread = %d)\n",
134 t, SDL_ThreadID());
135 #endif
136 SDL_mutexV(SDL_timer_mutex);
137 ms = t->cb(t->interval, t->param);
138 SDL_mutexP(SDL_timer_mutex);
139 if ( list_changed ) {
140 /* Abort, list of timers has been modified */
141 break;
142 }
143 if ( ms != t->interval ) {
144 if ( ms ) {
145 t->interval = ROUND_RESOLUTION(ms);
146 } else { /* Remove the timer from the linked list */
147 #ifdef DEBUG_TIMERS
148 printf("SDL: Removing timer %p\n", t);
149 #endif
150 if ( prev ) {
151 prev->next = next;
152 } else {
153 SDL_timers = next;
154 }
155 free(t);
156 -- num_timers;
157 removed = 1;
158 }
159 }
160 }
161 /* Don't update prev if the timer has disappeared */
162 if ( ! removed ) {
163 prev = t;
164 }
165 }
166 SDL_mutexV(SDL_timer_mutex);
167 }
168
169 SDL_TimerID SDL_AddTimer(Uint32 interval, SDL_NewTimerCallback callback, void *param)
170 {
171 SDL_TimerID t;
172 if ( ! SDL_timer_mutex ) {
173 if ( SDL_timer_started ) {
174 SDL_SetError("This platform doesn't support multiple timers");
175 } else {
176 SDL_SetError("You must call SDL_Init(SDL_INIT_TIMER) first");
177 }
178 return NULL;
179 }
180 if ( ! SDL_timer_threaded ) {
181 SDL_SetError("Multiple timers require threaded events!");
182 return NULL;
183 }
184 SDL_mutexP(SDL_timer_mutex);
185 t = (SDL_TimerID) malloc(sizeof(struct _SDL_TimerID));
186 if ( t ) {
187 t->interval = ROUND_RESOLUTION(interval);
188 t->cb = callback;
189 t->param = param;
190 t->last_alarm = SDL_GetTicks();
191 t->next = SDL_timers;
192 SDL_timers = t;
193 ++ num_timers;
194 list_changed = SDL_TRUE;
195 SDL_timer_running = 1;
196 }
197 #ifdef DEBUG_TIMERS
198 printf("SDL_AddTimer(%d) = %08x num_timers = %d\n", interval, (Uint32)t, num_timers);
199 #endif
200 SDL_mutexV(SDL_timer_mutex);
201 return t;
202 }
203
204 SDL_bool SDL_RemoveTimer(SDL_TimerID id)
205 {
206 SDL_TimerID t, prev = NULL;
207 SDL_bool removed;
208
209 removed = SDL_FALSE;
210 SDL_mutexP(SDL_timer_mutex);
211 /* Look for id in the linked list of timers */
212 for (t = SDL_timers; t; prev=t, t = t->next ) {
213 if ( t == id ) {
214 if(prev) {
215 prev->next = t->next;
216 } else {
217 SDL_timers = t->next;
218 }
219 free(t);
220 -- num_timers;
221 removed = SDL_TRUE;
222 list_changed = SDL_TRUE;
223 break;
224 }
225 }
226 #ifdef DEBUG_TIMERS
227 printf("SDL_RemoveTimer(%08x) = %d num_timers = %d thread = %d\n", (Uint32)id, removed, num_timers, SDL_ThreadID());
228 #endif
229 SDL_mutexV(SDL_timer_mutex);
230 return removed;
231 }
232
233 static void SDL_RemoveAllTimers(SDL_TimerID t)
234 {
235 SDL_TimerID freeme;
236
237 /* Changed to non-recursive implementation.
238 The recursive implementation is elegant, but subject to
239 stack overflow if there are lots and lots of timers.
240 */
241 while ( t ) {
242 freeme = t;
243 t = t->next;
244 free(freeme);
245 }
246 }
247
248 /* Old style callback functions are wrapped through this */
249 static Uint32 callback_wrapper(Uint32 ms, void *param)
250 {
251 SDL_TimerCallback func = (SDL_TimerCallback) param;
252 return (*func)(ms);
253 }
254
255 int SDL_SetTimer(Uint32 ms, SDL_TimerCallback callback)
256 {
257 int retval;
258
259 #ifdef DEBUG_TIMERS
260 printf("SDL_SetTimer(%d)\n", ms);
261 #endif
262 retval = 0;
263 if ( SDL_timer_running ) { /* Stop any currently running timer */
264 SDL_timer_running = 0;
265 if ( SDL_timer_threaded ) {
266 SDL_mutexP(SDL_timer_mutex);
267 SDL_RemoveAllTimers(SDL_timers);
268 SDL_timers = NULL;
269 SDL_mutexV(SDL_timer_mutex);
270 } else {
271 SDL_SYS_StopTimer();
272 }
273 }
274 if ( ms ) {
275 if ( SDL_timer_threaded ) {
276 retval = (SDL_AddTimer(ms, callback_wrapper,
277 (void *)callback) != NULL);
278 } else {
279 SDL_timer_running = 1;
280 SDL_alarm_interval = ms;
281 SDL_alarm_callback = callback;
282 retval = SDL_SYS_StartTimer();
283 }
284 }
285 return retval;
286 }