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.

{
SDL_TimerData *data = &SDL_timer_data;
SDL_Timer *timer;
SDL_TimerMap *entry;
if (!data->active) {
int status = 0;
SDL_AtomicLock(&data->lock);
if (!data->active) {
status = SDL_TimerInit();
}
SDL_AtomicUnlock(&data->lock);
if (status < 0) {
return 0;
}
}
SDL_AtomicLock(&data->lock);
timer = data->freelist;
if (timer) {
data->freelist = timer->next;
}
SDL_AtomicUnlock(&data->lock);
if (timer) {
SDL_RemoveTimer(timer->timerID);
} else {
timer = (SDL_Timer *)SDL_malloc(sizeof(*timer));
if (!timer) {
SDL_OutOfMemory();
return 0;
}
}
timer->timerID = SDL_AtomicIncRef(&data->nextID);
timer->callback = callback;
timer->param = param;
timer->interval = interval;
timer->scheduled = SDL_GetTicks() + interval;
timer->canceled = SDL_FALSE;
entry = (SDL_TimerMap *)SDL_malloc(sizeof(*entry));
if (!entry) {
SDL_free(timer);
SDL_OutOfMemory();
return 0;
}
entry->timer = timer;
entry->timerID = timer->timerID;
SDL_LockMutex(data->timermap_lock);
entry->next = data->timermap;
data->timermap = entry;
SDL_UnlockMutex(data->timermap_lock);
/* Add the timer to the pending list for the timer thread */
SDL_AtomicLock(&data->lock);
timer->next = data->pending;
data->pending = timer;
SDL_AtomicUnlock(&data->lock);
/* Wake up the timer thread if necessary */
SDL_SemPost(data->sem);
return entry->timerID;
}
SDL_LockMutex
#define SDL_LockMutex
Definition: SDL_dynapi_overrides.h:266
SDL_TimerMap::timer
SDL_Timer * timer
Definition: SDL_timer.c:45
SDL_Timer::canceled
volatile SDL_bool canceled
Definition: SDL_timer.c:38
SDL_TimerData::timermap
SDL_TimerMap * timermap
Definition: SDL_timer.c:54
SDL_AtomicLock
#define SDL_AtomicLock
Definition: SDL_dynapi_overrides.h:70
SDL_Timer::interval
Uint32 interval
Definition: SDL_timer.c:36
data
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1967
SDL_TimerInit
int SDL_TimerInit(void)
Definition: SDL_timer.c:206
SDL_TimerData::nextID
SDL_atomic_t nextID
Definition: SDL_timer.c:53
SDL_TimerData::active
volatile SDL_bool active
Definition: SDL_timer.c:65
param
GLfloat param
Definition: SDL_opengl_glext.h:370
SDL_SemPost
#define SDL_SemPost
Definition: SDL_dynapi_overrides.h:275
SDL_AtomicUnlock
#define SDL_AtomicUnlock
Definition: SDL_dynapi_overrides.h:71
SDL_RemoveTimer
SDL_bool SDL_RemoveTimer(SDL_TimerID id)
Remove a timer knowing its ID.
Definition: SDL_timer.c:358
SDL_TimerMap
Definition: SDL_timer.c:42
SDL_TimerData::freelist
SDL_Timer *volatile freelist
Definition: SDL_timer.c:64
SDL_Timer::next
struct _SDL_Timer * next
Definition: SDL_timer.c:39
SDL_GetTicks
Uint32 SDL_GetTicks(void)
Get the number of milliseconds since the SDL library initialization.
SDL_Timer::scheduled
Uint32 scheduled
Definition: SDL_timer.c:37
SDL_free
void SDL_free(void *mem)
SDL_Timer::callback
SDL_TimerCallback callback
Definition: SDL_timer.c:34
SDL_Timer::timerID
int timerID
Definition: SDL_timer.c:33
callback
static Uint32 callback(Uint32 interval, void *param)
Definition: testtimer.c:34
SDL_TimerData::sem
SDL_sem * sem
Definition: SDL_timer.c:62
SDL_AtomicIncRef
#define SDL_AtomicIncRef(a)
Increment an atomic variable used as a reference count.
Definition: SDL_atomic.h:225
SDL_TimerMap::next
struct _SDL_TimerMap * next
Definition: SDL_timer.c:46
SDL_Timer::param
void * param
Definition: SDL_timer.c:35
SDL_OutOfMemory
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
SDL_TimerData::timermap_lock
SDL_mutex * timermap_lock
Definition: SDL_timer.c:55
SDL_TimerData::pending
SDL_Timer *volatile pending
Definition: SDL_timer.c:63
SDL_Timer
Definition: SDL_timer.c:31
SDL_timer_data
static SDL_TimerData SDL_timer_data
Definition: SDL_timer.c:71
SDL_FALSE
Definition: SDL_stdinc.h:128
SDL_UnlockMutex
#define SDL_UnlockMutex
Definition: SDL_dynapi_overrides.h:268
SDL_malloc
#define SDL_malloc
Definition: SDL_dynapi_overrides.h:380
SDL_TimerData::lock
SDL_SpinLock lock
Definition: SDL_timer.c:61
SDL_TimerData
Definition: SDL_timer.c:50
SDL_TimerMap::timerID
int timerID
Definition: SDL_timer.c:44

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().

{
SDL_Timer *prev, *curr;
prev = NULL;
for (curr = data->timers; curr; prev = curr, curr = curr->next) {
if ((Sint32)(timer->scheduled-curr->scheduled) < 0) {
break;
}
}
/* Insert the timer here! */
if (prev) {
prev->next = timer;
} else {
data->timers = timer;
}
timer->next = curr;
}
SDL_Timer::next
struct _SDL_Timer * next
Definition: SDL_timer.c:39
SDL_Timer::scheduled
Uint32 scheduled
Definition: SDL_timer.c:37
Sint32
int32_t Sint32
Definition: SDL_stdinc.h:153
NULL
#define NULL
Definition: begin_code.h:143
SDL_Timer
Definition: SDL_timer.c:31
SDL_TimerData::timers
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().

{
SDL_TimerData *data = &SDL_timer_data;
SDL_TimerMap *prev, *entry;
SDL_bool canceled = SDL_FALSE;
/* Find the timer */
SDL_LockMutex(data->timermap_lock);
prev = NULL;
for (entry = data->timermap; entry; prev = entry, entry = entry->next) {
if (entry->timerID == id) {
if (prev) {
prev->next = entry->next;
} else {
data->timermap = entry->next;
}
break;
}
}
SDL_UnlockMutex(data->timermap_lock);
if (entry) {
if (!entry->timer->canceled) {
entry->timer->canceled = SDL_TRUE;
canceled = SDL_TRUE;
}
SDL_free(entry);
}
return canceled;
}
SDL_LockMutex
#define SDL_LockMutex
Definition: SDL_dynapi_overrides.h:266
SDL_TimerMap::timer
SDL_Timer * timer
Definition: SDL_timer.c:45
SDL_Timer::canceled
volatile SDL_bool canceled
Definition: SDL_timer.c:38
SDL_TimerData::timermap
SDL_TimerMap * timermap
Definition: SDL_timer.c:54
data
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1967
SDL_bool
SDL_bool
Definition: SDL_stdinc.h:126
SDL_TimerMap
Definition: SDL_timer.c:42
SDL_free
void SDL_free(void *mem)
SDL_TRUE
Definition: SDL_stdinc.h:129
SDL_TimerMap::next
struct _SDL_TimerMap * next
Definition: SDL_timer.c:46
NULL
#define NULL
Definition: begin_code.h:143
SDL_TimerData::timermap_lock
SDL_mutex * timermap_lock
Definition: SDL_timer.c:55
SDL_timer_data
static SDL_TimerData SDL_timer_data
Definition: SDL_timer.c:71
SDL_FALSE
Definition: SDL_stdinc.h:128
SDL_UnlockMutex
#define SDL_UnlockMutex
Definition: SDL_dynapi_overrides.h:268
SDL_TimerData
Definition: SDL_timer.c:50
SDL_TimerMap::timerID
int timerID
Definition: SDL_timer.c:44

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().

{
SDL_TimerData *data = &SDL_timer_data;
if (!data->active) {
const char *name = "SDLTimer";
data->timermap_lock = SDL_CreateMutex();
if (!data->timermap_lock) {
return -1;
}
data->sem = SDL_CreateSemaphore(0);
if (!data->sem) {
SDL_DestroyMutex(data->timermap_lock);
return -1;
}
data->active = SDL_TRUE;
/* !!! FIXME: this is nasty. */
#if defined(__WIN32__) && !defined(HAVE_LIBC)
#undef SDL_CreateThread
#if SDL_DYNAMIC_API
data->thread = SDL_CreateThread_REAL(SDL_TimerThread, name, data, NULL, NULL);
#else
data->thread = SDL_CreateThread(SDL_TimerThread, name, data, NULL, NULL);
#endif
#else
data->thread = SDL_CreateThread(SDL_TimerThread, name, data);
#endif
if (!data->thread) {
SDL_TimerQuit();
return -1;
}
SDL_AtomicSet(&data->nextID, 1);
}
return 0;
}
SDL_TimerThread
static int SDL_TimerThread(void *_data)
Definition: SDL_timer.c:101
SDL_TimerQuit
void SDL_TimerQuit(void)
Definition: SDL_timer.c:246
SDL_CreateSemaphore
#define SDL_CreateSemaphore
Definition: SDL_dynapi_overrides.h:270
SDL_CreateMutex
#define SDL_CreateMutex
Definition: SDL_dynapi_overrides.h:265
data
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1967
SDL_TimerData::thread
SDL_Thread * thread
Definition: SDL_timer.c:52
name
GLuint const GLchar * name
Definition: SDL_opengl_glext.h:660
SDL_TimerData::nextID
SDL_atomic_t nextID
Definition: SDL_timer.c:53
SDL_TimerData::active
volatile SDL_bool active
Definition: SDL_timer.c:65
SDL_TRUE
Definition: SDL_stdinc.h:129
SDL_TimerData::sem
SDL_sem * sem
Definition: SDL_timer.c:62
SDL_CreateThread
#define SDL_CreateThread
Definition: SDL_dynapi_overrides.h:47
NULL
#define NULL
Definition: begin_code.h:143
SDL_TimerData::timermap_lock
SDL_mutex * timermap_lock
Definition: SDL_timer.c:55
SDL_DestroyMutex
#define SDL_DestroyMutex
Definition: SDL_dynapi_overrides.h:269
SDL_timer_data
static SDL_TimerData SDL_timer_data
Definition: SDL_timer.c:71
SDL_AtomicSet
#define SDL_AtomicSet
Definition: SDL_dynapi_overrides.h:73
SDL_TimerData
Definition: SDL_timer.c:50

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().

{
SDL_TimerData *data = &SDL_timer_data;
SDL_Timer *timer;
SDL_TimerMap *entry;
if (data->active) {
data->active = SDL_FALSE;
/* Shutdown the timer thread */
if (data->thread) {
SDL_SemPost(data->sem);
SDL_WaitThread(data->thread, NULL);
data->thread = NULL;
}
SDL_DestroySemaphore(data->sem);
data->sem = NULL;
/* Clean up the timer entries */
while (data->timers) {
timer = data->timers;
data->timers = timer->next;
SDL_free(timer);
}
while (data->freelist) {
timer = data->freelist;
data->freelist = timer->next;
SDL_free(timer);
}
while (data->timermap) {
entry = data->timermap;
data->timermap = entry->next;
SDL_free(entry);
}
SDL_DestroyMutex(data->timermap_lock);
data->timermap_lock = NULL;
}
}
SDL_TimerData::timermap
SDL_TimerMap * timermap
Definition: SDL_timer.c:54
data
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1967
SDL_TimerData::thread
SDL_Thread * thread
Definition: SDL_timer.c:52
SDL_TimerData::active
volatile SDL_bool active
Definition: SDL_timer.c:65
SDL_SemPost
#define SDL_SemPost
Definition: SDL_dynapi_overrides.h:275
SDL_TimerMap
Definition: SDL_timer.c:42
SDL_TimerData::freelist
SDL_Timer *volatile freelist
Definition: SDL_timer.c:64
SDL_Timer::next
struct _SDL_Timer * next
Definition: SDL_timer.c:39
SDL_free
void SDL_free(void *mem)
SDL_TimerData::sem
SDL_sem * sem
Definition: SDL_timer.c:62
SDL_TimerMap::next
struct _SDL_TimerMap * next
Definition: SDL_timer.c:46
NULL
#define NULL
Definition: begin_code.h:143
SDL_TimerData::timermap_lock
SDL_mutex * timermap_lock
Definition: SDL_timer.c:55
SDL_DestroyMutex
#define SDL_DestroyMutex
Definition: SDL_dynapi_overrides.h:269
SDL_Timer
Definition: SDL_timer.c:31
SDL_DestroySemaphore
#define SDL_DestroySemaphore
Definition: SDL_dynapi_overrides.h:271
SDL_timer_data
static SDL_TimerData SDL_timer_data
Definition: SDL_timer.c:71
SDL_FALSE
Definition: SDL_stdinc.h:128
SDL_TimerData::timers
SDL_Timer * timers
Definition: SDL_timer.c:68
SDL_TimerData
Definition: SDL_timer.c:50
SDL_WaitThread
#define SDL_WaitThread
Definition: SDL_dynapi_overrides.h:482

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().

{
SDL_TimerData *data = (SDL_TimerData *)_data;
SDL_Timer *pending;
SDL_Timer *current;
SDL_Timer *freelist_head = NULL;
SDL_Timer *freelist_tail = NULL;
Uint32 tick, now, interval, delay;
/* Threaded timer loop:
* 1. Queue timers added by other threads
* 2. Handle any timers that should dispatch this cycle
* 3. Wait until next dispatch time or new timer arrives
*/
for ( ; ; ) {
/* Pending and freelist maintenance */
SDL_AtomicLock(&data->lock);
{
/* Get any timers ready to be queued */
pending = data->pending;
data->pending = NULL;
/* Make any unused timer structures available */
if (freelist_head) {
freelist_tail->next = data->freelist;
data->freelist = freelist_head;
}
}
SDL_AtomicUnlock(&data->lock);
/* Sort the pending timers into our list */
while (pending) {
current = pending;
pending = pending->next;
SDL_AddTimerInternal(data, current);
}
freelist_head = NULL;
freelist_tail = NULL;
/* Check to see if we're still running, after maintenance */
if (!data->active) {
break;
}
/* Initial delay if there are no timers */
delay = SDL_MUTEX_MAXWAIT;
tick = SDL_GetTicks();
/* Process all the pending timers for this tick */
while (data->timers) {
current = data->timers;
if ((Sint32)(tick-current->scheduled) < 0) {
/* Scheduled for the future, wait a bit */
delay = (current->scheduled - tick);
break;
}
/* We're going to do something with this timer */
data->timers = current->next;
if (current->canceled) {
interval = 0;
} else {
interval = current->callback(current->interval, current->param);
}
if (interval > 0) {
/* Reschedule this timer */
current->scheduled = tick + interval;
SDL_AddTimerInternal(data, current);
} else {
if (!freelist_head) {
freelist_head = current;
}
if (freelist_tail) {
freelist_tail->next = current;
}
freelist_tail = current;
current->canceled = SDL_TRUE;
}
}
/* Adjust the delay based on processing time */
now = SDL_GetTicks();
interval = (now - tick);
if (interval > delay) {
delay = 0;
} else {
delay -= interval;
}
/* Note that each time a timer is added, this will return
immediately, but we process the timers added all at once.
That's okay, it just means we run through the loop a few
extra times.
*/
SDL_SemWaitTimeout(data->sem, delay);
}
return 0;
}
SDL_Timer::canceled
volatile SDL_bool canceled
Definition: SDL_timer.c:38
Uint32
uint32_t Uint32
An unsigned 32-bit integer type.
Definition: SDL_stdinc.h:157
SDL_AtomicLock
#define SDL_AtomicLock
Definition: SDL_dynapi_overrides.h:70
SDL_Timer::interval
Uint32 interval
Definition: SDL_timer.c:36
data
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1967
SDL_TimerData::active
volatile SDL_bool active
Definition: SDL_timer.c:65
SDL_AtomicUnlock
#define SDL_AtomicUnlock
Definition: SDL_dynapi_overrides.h:71
SDL_TimerData::freelist
SDL_Timer *volatile freelist
Definition: SDL_timer.c:64
SDL_SemWaitTimeout
#define SDL_SemWaitTimeout
Definition: SDL_dynapi_overrides.h:274
SDL_Timer::next
struct _SDL_Timer * next
Definition: SDL_timer.c:39
SDL_MUTEX_MAXWAIT
#define SDL_MUTEX_MAXWAIT
Definition: SDL_mutex.h:49
SDL_GetTicks
Uint32 SDL_GetTicks(void)
Get the number of milliseconds since the SDL library initialization.
SDL_Timer::scheduled
Uint32 scheduled
Definition: SDL_timer.c:37
SDL_Timer::callback
SDL_TimerCallback callback
Definition: SDL_timer.c:34
SDL_TRUE
Definition: SDL_stdinc.h:129
Sint32
int32_t Sint32
Definition: SDL_stdinc.h:153
SDL_TimerData::sem
SDL_sem * sem
Definition: SDL_timer.c:62
NULL
#define NULL
Definition: begin_code.h:143
SDL_Timer::param
void * param
Definition: SDL_timer.c:35
SDL_AddTimerInternal
static void SDL_AddTimerInternal(SDL_TimerData *data, SDL_Timer *timer)
Definition: SDL_timer.c:80
SDL_TimerData::pending
SDL_Timer *volatile pending
Definition: SDL_timer.c:63
SDL_Timer
Definition: SDL_timer.c:31
SDL_TimerData::lock
SDL_SpinLock lock
Definition: SDL_timer.c:61
SDL_TimerData::timers
SDL_Timer * timers
Definition: SDL_timer.c:68
SDL_TimerData
Definition: SDL_timer.c:50

## 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().