diff options
Diffstat (limited to 'apps/plugins/sdl/src/timer/SDL_timer.c')
-rw-r--r-- | apps/plugins/sdl/src/timer/SDL_timer.c | 285 |
1 files changed, 285 insertions, 0 deletions
diff --git a/apps/plugins/sdl/src/timer/SDL_timer.c b/apps/plugins/sdl/src/timer/SDL_timer.c new file mode 100644 index 0000000000..8d137e1a70 --- /dev/null +++ b/apps/plugins/sdl/src/timer/SDL_timer.c | |||
@@ -0,0 +1,285 @@ | |||
1 | /* | ||
2 | SDL - Simple DirectMedia Layer | ||
3 | Copyright (C) 1997-2012 Sam Lantinga | ||
4 | |||
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. | ||
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 | Lesser General Public License for more details. | ||
14 | |||
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 | ||
18 | |||
19 | Sam Lantinga | ||
20 | slouken@libsdl.org | ||
21 | */ | ||
22 | #include "SDL_config.h" | ||
23 | |||
24 | #include "SDL_timer.h" | ||
25 | #include "SDL_timer_c.h" | ||
26 | #include "SDL_mutex.h" | ||
27 | #include "SDL_systimer.h" | ||
28 | |||
29 | /* #define DEBUG_TIMERS */ | ||
30 | |||
31 | int SDL_timer_started = 0; | ||
32 | int SDL_timer_running = 0; | ||
33 | |||
34 | /* Data to handle a single periodic alarm */ | ||
35 | Uint32 SDL_alarm_interval = 0; | ||
36 | SDL_TimerCallback SDL_alarm_callback; | ||
37 | |||
38 | /* Data used for a thread-based timer */ | ||
39 | static int SDL_timer_threaded = 0; | ||
40 | |||
41 | struct _SDL_TimerID { | ||
42 | Uint32 interval; | ||
43 | SDL_NewTimerCallback cb; | ||
44 | void *param; | ||
45 | Uint32 last_alarm; | ||
46 | struct _SDL_TimerID *next; | ||
47 | }; | ||
48 | |||
49 | static SDL_TimerID SDL_timers = NULL; | ||
50 | static SDL_mutex *SDL_timer_mutex; | ||
51 | static volatile SDL_bool list_changed = SDL_FALSE; | ||
52 | |||
53 | /* Set whether or not the timer should use a thread. | ||
54 | This should not be called while the timer subsystem is running. | ||
55 | */ | ||
56 | int SDL_SetTimerThreaded(int value) | ||
57 | { | ||
58 | int retval; | ||
59 | |||
60 | if ( SDL_timer_started ) { | ||
61 | SDL_SetError("Timer already initialized"); | ||
62 | retval = -1; | ||
63 | } else { | ||
64 | retval = 0; | ||
65 | SDL_timer_threaded = value; | ||
66 | } | ||
67 | return retval; | ||
68 | } | ||
69 | |||
70 | int SDL_TimerInit(void) | ||
71 | { | ||
72 | int retval; | ||
73 | |||
74 | retval = 0; | ||
75 | if ( SDL_timer_started ) { | ||
76 | SDL_TimerQuit(); | ||
77 | } | ||
78 | if ( ! SDL_timer_threaded ) { | ||
79 | retval = SDL_SYS_TimerInit(); | ||
80 | } | ||
81 | if ( SDL_timer_threaded ) { | ||
82 | SDL_timer_mutex = SDL_CreateMutex(); | ||
83 | } | ||
84 | if ( retval == 0 ) { | ||
85 | SDL_timer_started = 1; | ||
86 | } | ||
87 | return(retval); | ||
88 | } | ||
89 | |||
90 | void SDL_TimerQuit(void) | ||
91 | { | ||
92 | SDL_SetTimer(0, NULL); | ||
93 | if ( SDL_timer_threaded < 2 ) { | ||
94 | SDL_SYS_TimerQuit(); | ||
95 | } | ||
96 | if ( SDL_timer_threaded ) { | ||
97 | SDL_DestroyMutex(SDL_timer_mutex); | ||
98 | SDL_timer_mutex = NULL; | ||
99 | } | ||
100 | SDL_timer_started = 0; | ||
101 | SDL_timer_threaded = 0; | ||
102 | } | ||
103 | |||
104 | void SDL_ThreadedTimerCheck(void) | ||
105 | { | ||
106 | Uint32 now, ms; | ||
107 | SDL_TimerID t, prev, next; | ||
108 | SDL_bool removed; | ||
109 | |||
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 ) { | ||
114 | removed = SDL_FALSE; | ||
115 | ms = t->interval - SDL_TIMESLICE; | ||
116 | next = t->next; | ||
117 | if ( (int)(now - t->last_alarm) > (int)ms ) { | ||
118 | struct _SDL_TimerID timer; | ||
119 | |||
120 | if ( (now - t->last_alarm) < t->interval ) { | ||
121 | t->last_alarm += t->interval; | ||
122 | } else { | ||
123 | t->last_alarm = now; | ||
124 | } | ||
125 | #ifdef DEBUG_TIMERS | ||
126 | printf("Executing timer %p (thread = %d)\n", | ||
127 | t, SDL_ThreadID()); | ||
128 | #endif | ||
129 | timer = *t; | ||
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? */ | ||
136 | break; | ||
137 | } | ||
138 | if ( ms != t->interval ) { | ||
139 | if ( ms ) { | ||
140 | t->interval = ROUND_RESOLUTION(ms); | ||
141 | } else { | ||
142 | /* Remove timer from the list */ | ||
143 | #ifdef DEBUG_TIMERS | ||
144 | printf("SDL: Removing timer %p\n", t); | ||
145 | #endif | ||
146 | if ( prev ) { | ||
147 | prev->next = next; | ||
148 | } else { | ||
149 | SDL_timers = next; | ||
150 | } | ||
151 | SDL_free(t); | ||
152 | --SDL_timer_running; | ||
153 | removed = SDL_TRUE; | ||
154 | } | ||
155 | } | ||
156 | } | ||
157 | /* Don't update prev if the timer has disappeared */ | ||
158 | if ( ! removed ) { | ||
159 | prev = t; | ||
160 | } | ||
161 | } | ||
162 | SDL_mutexV(SDL_timer_mutex); | ||
163 | } | ||
164 | |||
165 | static SDL_TimerID SDL_AddTimerInternal(Uint32 interval, SDL_NewTimerCallback callback, void *param) | ||
166 | { | ||
167 | SDL_TimerID t; | ||
168 | t = (SDL_TimerID) SDL_malloc(sizeof(struct _SDL_TimerID)); | ||
169 | if ( t ) { | ||
170 | t->interval = ROUND_RESOLUTION(interval); | ||
171 | t->cb = callback; | ||
172 | t->param = param; | ||
173 | t->last_alarm = SDL_GetTicks(); | ||
174 | t->next = SDL_timers; | ||
175 | SDL_timers = t; | ||
176 | ++SDL_timer_running; | ||
177 | list_changed = SDL_TRUE; | ||
178 | } | ||
179 | #ifdef DEBUG_TIMERS | ||
180 | printf("SDL_AddTimer(%d) = %08x num_timers = %d\n", interval, (Uint32)t, SDL_timer_running); | ||
181 | #endif | ||
182 | return t; | ||
183 | } | ||
184 | |||
185 | SDL_TimerID SDL_AddTimer(Uint32 interval, SDL_NewTimerCallback callback, void *param) | ||
186 | { | ||
187 | SDL_TimerID t; | ||
188 | if ( ! SDL_timer_mutex ) { | ||
189 | if ( SDL_timer_started ) { | ||
190 | SDL_SetError("This platform doesn't support multiple timers"); | ||
191 | } else { | ||
192 | SDL_SetError("You must call SDL_Init(SDL_INIT_TIMER) first"); | ||
193 | } | ||
194 | return NULL; | ||
195 | } | ||
196 | if ( ! SDL_timer_threaded ) { | ||
197 | SDL_SetError("Multiple timers require threaded events!"); | ||
198 | return NULL; | ||
199 | } | ||
200 | SDL_mutexP(SDL_timer_mutex); | ||
201 | t = SDL_AddTimerInternal(interval, callback, param); | ||
202 | SDL_mutexV(SDL_timer_mutex); | ||
203 | return t; | ||
204 | } | ||
205 | |||
206 | SDL_bool SDL_RemoveTimer(SDL_TimerID id) | ||
207 | { | ||
208 | SDL_TimerID t, prev = NULL; | ||
209 | SDL_bool removed; | ||
210 | |||
211 | removed = SDL_FALSE; | ||
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 ) { | ||
215 | if ( t == id ) { | ||
216 | if(prev) { | ||
217 | prev->next = t->next; | ||
218 | } else { | ||
219 | SDL_timers = t->next; | ||
220 | } | ||
221 | SDL_free(t); | ||
222 | --SDL_timer_running; | ||
223 | removed = SDL_TRUE; | ||
224 | list_changed = SDL_TRUE; | ||
225 | break; | ||
226 | } | ||
227 | } | ||
228 | #ifdef DEBUG_TIMERS | ||
229 | printf("SDL_RemoveTimer(%08x) = %d num_timers = %d thread = %d\n", (Uint32)id, removed, SDL_timer_running, SDL_ThreadID()); | ||
230 | #endif | ||
231 | SDL_mutexV(SDL_timer_mutex); | ||
232 | return removed; | ||
233 | } | ||
234 | |||
235 | /* Old style callback functions are wrapped through this */ | ||
236 | static Uint32 SDLCALL callback_wrapper(Uint32 ms, void *param) | ||
237 | { | ||
238 | SDL_TimerCallback func = (SDL_TimerCallback) param; | ||
239 | return (*func)(ms); | ||
240 | } | ||
241 | |||
242 | int SDL_SetTimer(Uint32 ms, SDL_TimerCallback callback) | ||
243 | { | ||
244 | int retval; | ||
245 | |||
246 | #ifdef DEBUG_TIMERS | ||
247 | printf("SDL_SetTimer(%d)\n", ms); | ||
248 | #endif | ||
249 | retval = 0; | ||
250 | |||
251 | if ( SDL_timer_threaded ) { | ||
252 | SDL_mutexP(SDL_timer_mutex); | ||
253 | } | ||
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; | ||
259 | SDL_free(freeme); | ||
260 | } | ||
261 | SDL_timer_running = 0; | ||
262 | list_changed = SDL_TRUE; | ||
263 | } else { | ||
264 | SDL_SYS_StopTimer(); | ||
265 | SDL_timer_running = 0; | ||
266 | } | ||
267 | } | ||
268 | if ( ms ) { | ||
269 | if ( SDL_timer_threaded ) { | ||
270 | if ( SDL_AddTimerInternal(ms, callback_wrapper, (void *)callback) == NULL ) { | ||
271 | retval = -1; | ||
272 | } | ||
273 | } else { | ||
274 | SDL_timer_running = 1; | ||
275 | SDL_alarm_interval = ms; | ||
276 | SDL_alarm_callback = callback; | ||
277 | retval = SDL_SYS_StartTimer(); | ||
278 | } | ||
279 | } | ||
280 | if ( SDL_timer_threaded ) { | ||
281 | SDL_mutexV(SDL_timer_mutex); | ||
282 | } | ||
283 | |||
284 | return retval; | ||
285 | } | ||