SDL  2.0
SDL_timer.c File Reference
#include "../SDL_internal.h"
#include "SDL_timer.h"
#include "SDL_timer_c.h"
#include "SDL_atomic.h"
#include "SDL_cpuinfo.h"
#include "SDL_thread.h"
+ Include dependency graph for SDL_timer.c:

Go to the source code of this file.

Data Structures

struct  SDL_Timer
 
struct  SDL_TimerMap
 
struct  SDL_TimerData
 

Functions

static void SDL_AddTimerInternal (SDL_TimerData *data, SDL_Timer *timer)
 
static int SDL_TimerThread (void *_data)
 
int SDL_TimerInit (void)
 
void SDL_TimerQuit (void)
 
SDL_TimerID SDL_AddTimer (Uint32 interval, SDL_TimerCallback callback, void *param)
 Add a new timer to the pool of timers already running. More...
 
SDL_bool SDL_RemoveTimer (SDL_TimerID id)
 Remove a timer knowing its ID. More...
 

Variables

static SDL_TimerData SDL_timer_data
 

Function Documentation

SDL_TimerID SDL_AddTimer ( Uint32  interval,
SDL_TimerCallback  callback,
void param 
)

Add a new timer to the pool of timers already running.

Returns
A timer ID, or 0 when an error occurs.

Definition at line 288 of file SDL_timer.c.

References SDL_TimerData::active, callback(), SDL_Timer::callback, SDL_Timer::canceled, SDL_TimerData::freelist, SDL_Timer::interval, SDL_TimerData::lock, SDL_Timer::next, SDL_TimerMap::next, SDL_TimerData::nextID, SDL_Timer::param, SDL_TimerData::pending, SDL_Timer::scheduled, SDL_AtomicIncRef, SDL_AtomicLock, SDL_AtomicUnlock, SDL_FALSE, SDL_free(), SDL_GetTicks(), SDL_LockMutex, SDL_malloc, SDL_OutOfMemory, SDL_RemoveTimer(), SDL_SemPost, SDL_timer_data, SDL_TimerInit(), SDL_UnlockMutex, SDL_TimerData::sem, SDL_TimerMap::timer, SDL_Timer::timerID, SDL_TimerMap::timerID, SDL_TimerData::timermap, and SDL_TimerData::timermap_lock.

289 {
291  SDL_Timer *timer;
292  SDL_TimerMap *entry;
293 
294  if (!data->active) {
295  int status = 0;
296 
297  SDL_AtomicLock(&data->lock);
298  if (!data->active) {
299  status = SDL_TimerInit();
300  }
301  SDL_AtomicUnlock(&data->lock);
302 
303  if (status < 0) {
304  return 0;
305  }
306  }
307 
308  SDL_AtomicLock(&data->lock);
309  timer = data->freelist;
310  if (timer) {
311  data->freelist = timer->next;
312  }
313  SDL_AtomicUnlock(&data->lock);
314 
315  if (timer) {
316  SDL_RemoveTimer(timer->timerID);
317  } else {
318  timer = (SDL_Timer *)SDL_malloc(sizeof(*timer));
319  if (!timer) {
320  SDL_OutOfMemory();
321  return 0;
322  }
323  }
324  timer->timerID = SDL_AtomicIncRef(&data->nextID);
325  timer->callback = callback;
326  timer->param = param;
327  timer->interval = interval;
328  timer->scheduled = SDL_GetTicks() + interval;
329  timer->canceled = SDL_FALSE;
330 
331  entry = (SDL_TimerMap *)SDL_malloc(sizeof(*entry));
332  if (!entry) {
333  SDL_free(timer);
334  SDL_OutOfMemory();
335  return 0;
336  }
337  entry->timer = timer;
338  entry->timerID = timer->timerID;
339 
341  entry->next = data->timermap;
342  data->timermap = entry;
344 
345  /* Add the timer to the pending list for the timer thread */
346  SDL_AtomicLock(&data->lock);
347  timer->next = data->pending;
348  data->pending = timer;
349  SDL_AtomicUnlock(&data->lock);
350 
351  /* Wake up the timer thread if necessary */
352  SDL_SemPost(data->sem);
353 
354  return entry->timerID;
355 }
#define SDL_LockMutex
SDL_Timer * timer
Definition: SDL_timer.c:45
volatile SDL_bool canceled
Definition: SDL_timer.c:38
SDL_TimerMap * timermap
Definition: SDL_timer.c:54
#define SDL_AtomicLock
Uint32 interval
Definition: SDL_timer.c:36
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1967
int SDL_TimerInit(void)
Definition: SDL_timer.c:206
SDL_atomic_t nextID
Definition: SDL_timer.c:53
volatile SDL_bool active
Definition: SDL_timer.c:65
GLfloat param
#define SDL_SemPost
#define SDL_AtomicUnlock
SDL_bool SDL_RemoveTimer(SDL_TimerID id)
Remove a timer knowing its ID.
Definition: SDL_timer.c:358
SDL_Timer *volatile freelist
Definition: SDL_timer.c:64
struct _SDL_Timer * next
Definition: SDL_timer.c:39
Uint32 SDL_GetTicks(void)
Get the number of milliseconds since the SDL library initialization.
Uint32 scheduled
Definition: SDL_timer.c:37
void SDL_free(void *mem)
SDL_TimerCallback callback
Definition: SDL_timer.c:34
int timerID
Definition: SDL_timer.c:33
static Uint32 callback(Uint32 interval, void *param)
Definition: testtimer.c:34
SDL_sem * sem
Definition: SDL_timer.c:62
#define SDL_AtomicIncRef(a)
Increment an atomic variable used as a reference count.
Definition: SDL_atomic.h:225
struct _SDL_TimerMap * next
Definition: SDL_timer.c:46
void * param
Definition: SDL_timer.c:35
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
SDL_mutex * timermap_lock
Definition: SDL_timer.c:55
SDL_Timer *volatile pending
Definition: SDL_timer.c:63
static SDL_TimerData SDL_timer_data
Definition: SDL_timer.c:71
#define SDL_UnlockMutex
#define SDL_malloc
SDL_SpinLock lock
Definition: SDL_timer.c:61
static void SDL_AddTimerInternal ( SDL_TimerData data,
SDL_Timer timer 
)
static

Definition at line 80 of file SDL_timer.c.

References SDL_Timer::next, NULL, SDL_Timer::scheduled, and SDL_TimerData::timers.

Referenced by SDL_TimerThread().

81 {
82  SDL_Timer *prev, *curr;
83 
84  prev = NULL;
85  for (curr = data->timers; curr; prev = curr, curr = curr->next) {
86  if ((Sint32)(timer->scheduled-curr->scheduled) < 0) {
87  break;
88  }
89  }
90 
91  /* Insert the timer here! */
92  if (prev) {
93  prev->next = timer;
94  } else {
95  data->timers = timer;
96  }
97  timer->next = curr;
98 }
struct _SDL_Timer * next
Definition: SDL_timer.c:39
Uint32 scheduled
Definition: SDL_timer.c:37
int32_t Sint32
A signed 32-bit integer type.
Definition: SDL_stdinc.h:151
#define NULL
Definition: begin_code.h:143
SDL_Timer * timers
Definition: SDL_timer.c:68
SDL_bool SDL_RemoveTimer ( SDL_TimerID  id)

Remove a timer knowing its ID.

Returns
A boolean value indicating success or failure.
Warning
It is not safe to remove a timer multiple times.

Definition at line 358 of file SDL_timer.c.

References SDL_Timer::canceled, SDL_TimerMap::next, NULL, SDL_FALSE, SDL_free(), SDL_LockMutex, SDL_timer_data, SDL_TRUE, SDL_UnlockMutex, SDL_TimerMap::timer, SDL_TimerMap::timerID, SDL_TimerData::timermap, and SDL_TimerData::timermap_lock.

Referenced by SDL_AddTimer().

359 {
361  SDL_TimerMap *prev, *entry;
362  SDL_bool canceled = SDL_FALSE;
363 
364  /* Find the timer */
366  prev = NULL;
367  for (entry = data->timermap; entry; prev = entry, entry = entry->next) {
368  if (entry->timerID == id) {
369  if (prev) {
370  prev->next = entry->next;
371  } else {
372  data->timermap = entry->next;
373  }
374  break;
375  }
376  }
378 
379  if (entry) {
380  if (!entry->timer->canceled) {
381  entry->timer->canceled = SDL_TRUE;
382  canceled = SDL_TRUE;
383  }
384  SDL_free(entry);
385  }
386  return canceled;
387 }
#define SDL_LockMutex
SDL_Timer * timer
Definition: SDL_timer.c:45
volatile SDL_bool canceled
Definition: SDL_timer.c:38
SDL_TimerMap * timermap
Definition: SDL_timer.c:54
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1967
SDL_bool
Definition: SDL_stdinc.h:126
void SDL_free(void *mem)
struct _SDL_TimerMap * next
Definition: SDL_timer.c:46
#define NULL
Definition: begin_code.h:143
SDL_mutex * timermap_lock
Definition: SDL_timer.c:55
static SDL_TimerData SDL_timer_data
Definition: SDL_timer.c:71
#define SDL_UnlockMutex
int SDL_TimerInit ( void  )

Definition at line 206 of file SDL_timer.c.

References SDL_TimerData::active, SDL_TimerData::nextID, NULL, SDL_AtomicSet, SDL_CreateMutex, SDL_CreateSemaphore, SDL_CreateThread, SDL_DestroyMutex, SDL_timer_data, SDL_TimerQuit(), SDL_TimerThread(), SDL_TRUE, SDL_TimerData::sem, SDL_TimerData::thread, and SDL_TimerData::timermap_lock.

Referenced by SDL_AddTimer(), and SDL_InitSubSystem().

207 {
209 
210  if (!data->active) {
211  const char *name = "SDLTimer";
212  data->timermap_lock = SDL_CreateMutex();
213  if (!data->timermap_lock) {
214  return -1;
215  }
216 
217  data->sem = SDL_CreateSemaphore(0);
218  if (!data->sem) {
220  return -1;
221  }
222 
223  data->active = SDL_TRUE;
224  /* !!! FIXME: this is nasty. */
225 #if defined(__WIN32__) && !defined(HAVE_LIBC)
226 #undef SDL_CreateThread
227 #if SDL_DYNAMIC_API
228  data->thread = SDL_CreateThread_REAL(SDL_TimerThread, name, data, NULL, NULL);
229 #else
230  data->thread = SDL_CreateThread(SDL_TimerThread, name, data, NULL, NULL);
231 #endif
232 #else
233  data->thread = SDL_CreateThread(SDL_TimerThread, name, data);
234 #endif
235  if (!data->thread) {
236  SDL_TimerQuit();
237  return -1;
238  }
239 
240  SDL_AtomicSet(&data->nextID, 1);
241  }
242  return 0;
243 }
static int SDL_TimerThread(void *_data)
Definition: SDL_timer.c:101
void SDL_TimerQuit(void)
Definition: SDL_timer.c:246
#define SDL_CreateSemaphore
#define SDL_CreateMutex
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1967
SDL_Thread * thread
Definition: SDL_timer.c:52
GLuint const GLchar * name
SDL_atomic_t nextID
Definition: SDL_timer.c:53
volatile SDL_bool active
Definition: SDL_timer.c:65
SDL_sem * sem
Definition: SDL_timer.c:62
#define SDL_CreateThread
#define NULL
Definition: begin_code.h:143
SDL_mutex * timermap_lock
Definition: SDL_timer.c:55
#define SDL_DestroyMutex
static SDL_TimerData SDL_timer_data
Definition: SDL_timer.c:71
#define SDL_AtomicSet
void SDL_TimerQuit ( void  )

Definition at line 246 of file SDL_timer.c.

References SDL_TimerData::active, SDL_TimerData::freelist, SDL_Timer::next, SDL_TimerMap::next, NULL, SDL_DestroyMutex, SDL_DestroySemaphore, SDL_FALSE, SDL_free(), SDL_SemPost, SDL_timer_data, SDL_WaitThread, SDL_TimerData::sem, SDL_TimerData::thread, SDL_TimerData::timermap, SDL_TimerData::timermap_lock, and SDL_TimerData::timers.

Referenced by SDL_QuitSubSystem(), and SDL_TimerInit().

247 {
249  SDL_Timer *timer;
250  SDL_TimerMap *entry;
251 
252  if (data->active) {
253  data->active = SDL_FALSE;
254 
255  /* Shutdown the timer thread */
256  if (data->thread) {
257  SDL_SemPost(data->sem);
258  SDL_WaitThread(data->thread, NULL);
259  data->thread = NULL;
260  }
261 
262  SDL_DestroySemaphore(data->sem);
263  data->sem = NULL;
264 
265  /* Clean up the timer entries */
266  while (data->timers) {
267  timer = data->timers;
268  data->timers = timer->next;
269  SDL_free(timer);
270  }
271  while (data->freelist) {
272  timer = data->freelist;
273  data->freelist = timer->next;
274  SDL_free(timer);
275  }
276  while (data->timermap) {
277  entry = data->timermap;
278  data->timermap = entry->next;
279  SDL_free(entry);
280  }
281 
283  data->timermap_lock = NULL;
284  }
285 }
SDL_TimerMap * timermap
Definition: SDL_timer.c:54
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1967
SDL_Thread * thread
Definition: SDL_timer.c:52
volatile SDL_bool active
Definition: SDL_timer.c:65
#define SDL_SemPost
SDL_Timer *volatile freelist
Definition: SDL_timer.c:64
struct _SDL_Timer * next
Definition: SDL_timer.c:39
void SDL_free(void *mem)
SDL_sem * sem
Definition: SDL_timer.c:62
struct _SDL_TimerMap * next
Definition: SDL_timer.c:46
#define NULL
Definition: begin_code.h:143
SDL_mutex * timermap_lock
Definition: SDL_timer.c:55
#define SDL_DestroyMutex
#define SDL_DestroySemaphore
static SDL_TimerData SDL_timer_data
Definition: SDL_timer.c:71
SDL_Timer * timers
Definition: SDL_timer.c:68
#define SDL_WaitThread
static int SDL_TimerThread ( void _data)
static

Definition at line 101 of file SDL_timer.c.

References SDL_TimerData::active, SDL_Timer::callback, SDL_Timer::canceled, SDL_TimerData::freelist, SDL_Timer::interval, SDL_TimerData::lock, SDL_Timer::next, NULL, SDL_Timer::param, SDL_TimerData::pending, SDL_Timer::scheduled, SDL_AddTimerInternal(), SDL_AtomicLock, SDL_AtomicUnlock, SDL_GetTicks(), SDL_MUTEX_MAXWAIT, SDL_SemWaitTimeout, SDL_TRUE, SDL_TimerData::sem, and SDL_TimerData::timers.

Referenced by SDL_TimerInit().

102 {
103  SDL_TimerData *data = (SDL_TimerData *)_data;
104  SDL_Timer *pending;
105  SDL_Timer *current;
106  SDL_Timer *freelist_head = NULL;
107  SDL_Timer *freelist_tail = NULL;
108  Uint32 tick, now, interval, delay;
109 
110  /* Threaded timer loop:
111  * 1. Queue timers added by other threads
112  * 2. Handle any timers that should dispatch this cycle
113  * 3. Wait until next dispatch time or new timer arrives
114  */
115  for ( ; ; ) {
116  /* Pending and freelist maintenance */
117  SDL_AtomicLock(&data->lock);
118  {
119  /* Get any timers ready to be queued */
120  pending = data->pending;
121  data->pending = NULL;
122 
123  /* Make any unused timer structures available */
124  if (freelist_head) {
125  freelist_tail->next = data->freelist;
126  data->freelist = freelist_head;
127  }
128  }
129  SDL_AtomicUnlock(&data->lock);
130 
131  /* Sort the pending timers into our list */
132  while (pending) {
133  current = pending;
134  pending = pending->next;
135  SDL_AddTimerInternal(data, current);
136  }
137  freelist_head = NULL;
138  freelist_tail = NULL;
139 
140  /* Check to see if we're still running, after maintenance */
141  if (!data->active) {
142  break;
143  }
144 
145  /* Initial delay if there are no timers */
146  delay = SDL_MUTEX_MAXWAIT;
147 
148  tick = SDL_GetTicks();
149 
150  /* Process all the pending timers for this tick */
151  while (data->timers) {
152  current = data->timers;
153 
154  if ((Sint32)(tick-current->scheduled) < 0) {
155  /* Scheduled for the future, wait a bit */
156  delay = (current->scheduled - tick);
157  break;
158  }
159 
160  /* We're going to do something with this timer */
161  data->timers = current->next;
162 
163  if (current->canceled) {
164  interval = 0;
165  } else {
166  interval = current->callback(current->interval, current->param);
167  }
168 
169  if (interval > 0) {
170  /* Reschedule this timer */
171  current->scheduled = tick + interval;
172  SDL_AddTimerInternal(data, current);
173  } else {
174  if (!freelist_head) {
175  freelist_head = current;
176  }
177  if (freelist_tail) {
178  freelist_tail->next = current;
179  }
180  freelist_tail = current;
181 
182  current->canceled = SDL_TRUE;
183  }
184  }
185 
186  /* Adjust the delay based on processing time */
187  now = SDL_GetTicks();
188  interval = (now - tick);
189  if (interval > delay) {
190  delay = 0;
191  } else {
192  delay -= interval;
193  }
194 
195  /* Note that each time a timer is added, this will return
196  immediately, but we process the timers added all at once.
197  That's okay, it just means we run through the loop a few
198  extra times.
199  */
200  SDL_SemWaitTimeout(data->sem, delay);
201  }
202  return 0;
203 }
volatile SDL_bool canceled
Definition: SDL_timer.c:38
uint32_t Uint32
An unsigned 32-bit integer type.
Definition: SDL_stdinc.h:155
#define SDL_AtomicLock
Uint32 interval
Definition: SDL_timer.c:36
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1967
volatile SDL_bool active
Definition: SDL_timer.c:65
#define SDL_AtomicUnlock
SDL_Timer *volatile freelist
Definition: SDL_timer.c:64
#define SDL_SemWaitTimeout
struct _SDL_Timer * next
Definition: SDL_timer.c:39
#define SDL_MUTEX_MAXWAIT
Definition: SDL_mutex.h:49
Uint32 SDL_GetTicks(void)
Get the number of milliseconds since the SDL library initialization.
Uint32 scheduled
Definition: SDL_timer.c:37
SDL_TimerCallback callback
Definition: SDL_timer.c:34
int32_t Sint32
A signed 32-bit integer type.
Definition: SDL_stdinc.h:151
SDL_sem * sem
Definition: SDL_timer.c:62
#define NULL
Definition: begin_code.h:143
void * param
Definition: SDL_timer.c:35
static void SDL_AddTimerInternal(SDL_TimerData *data, SDL_Timer *timer)
Definition: SDL_timer.c:80
SDL_Timer *volatile pending
Definition: SDL_timer.c:63
SDL_SpinLock lock
Definition: SDL_timer.c:61
SDL_Timer * timers
Definition: SDL_timer.c:68

Variable Documentation

SDL_TimerData SDL_timer_data
static

Definition at line 71 of file SDL_timer.c.

Referenced by SDL_AddTimer(), SDL_RemoveTimer(), SDL_TimerInit(), and SDL_TimerQuit().