Mercurial > sdl-ios-xcode
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 } |