Mercurial > sdl-ios-xcode
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/timer/SDL_timer.c Thu Apr 26 16:50:19 2001 +0000 @@ -0,0 +1,286 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997, 1998 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Sam Lantinga + 5635-34 Springhouse Dr. + Pleasanton, CA 94588 (USA) + slouken@devolution.com +*/ + +#ifdef SAVE_RCSID +static char rcsid = + "@(#) $Id$"; +#endif + +#include <stdlib.h> +#include <stdio.h> /* For the definition of NULL */ + +#include "SDL_error.h" +#include "SDL_timer.h" +#include "SDL_timer_c.h" +#include "SDL_mutex.h" +#include "SDL_systimer.h" + +/* #define DEBUG_TIMERS */ + +int SDL_timer_started = 0; +int SDL_timer_running = 0; + +/* Data to handle a single periodic alarm */ +Uint32 SDL_alarm_interval = 0; +SDL_TimerCallback SDL_alarm_callback; + +static SDL_bool list_changed = SDL_FALSE; + +/* Data used for a thread-based timer */ +static int SDL_timer_threaded = 0; + +struct _SDL_TimerID { + Uint32 interval; + SDL_NewTimerCallback cb; + void *param; + Uint32 last_alarm; + struct _SDL_TimerID *next; +}; + +static SDL_TimerID SDL_timers = NULL; +static Uint32 num_timers = 0; +static SDL_mutex *SDL_timer_mutex; + +/* Set whether or not the timer should use a thread. + This should not be called while the timer subsystem is running. +*/ +int SDL_SetTimerThreaded(int value) +{ + int retval; + + if ( SDL_timer_started ) { + SDL_SetError("Timer already initialized"); + retval = -1; + } else { + retval = 0; + SDL_timer_threaded = value; + } + return retval; +} + +int SDL_TimerInit(void) +{ + int retval; + + SDL_timer_running = 0; + SDL_SetTimer(0, NULL); + retval = 0; + if ( ! SDL_timer_threaded ) { + retval = SDL_SYS_TimerInit(); + } + if ( SDL_timer_threaded ) { + SDL_timer_mutex = SDL_CreateMutex(); + } + SDL_timer_started = 1; + return(retval); +} + +void SDL_TimerQuit(void) +{ + SDL_SetTimer(0, NULL); + if ( SDL_timer_threaded < 2 ) { + SDL_SYS_TimerQuit(); + } + if ( SDL_timer_threaded ) { + SDL_DestroyMutex(SDL_timer_mutex); + } + SDL_timer_started = 0; + SDL_timer_threaded = 0; +} + +void SDL_ThreadedTimerCheck(void) +{ + Uint32 now, ms; + SDL_TimerID t, prev, next; + int removed; + + now = SDL_GetTicks(); + + SDL_mutexP(SDL_timer_mutex); + for ( prev = NULL, t = SDL_timers; t; t = next ) { + removed = 0; + ms = t->interval - SDL_TIMESLICE; + next = t->next; + if ( (t->last_alarm < now) && ((now - t->last_alarm) > ms) ) { + if ( (now - t->last_alarm) < t->interval ) { + t->last_alarm += t->interval; + } else { + t->last_alarm = now; + } + list_changed = SDL_FALSE; +#ifdef DEBUG_TIMERS + printf("Executing timer %p (thread = %d)\n", + t, SDL_ThreadID()); +#endif + SDL_mutexV(SDL_timer_mutex); + ms = t->cb(t->interval, t->param); + SDL_mutexP(SDL_timer_mutex); + if ( list_changed ) { + /* Abort, list of timers has been modified */ + break; + } + if ( ms != t->interval ) { + if ( ms ) { + t->interval = ROUND_RESOLUTION(ms); + } else { /* Remove the timer from the linked list */ +#ifdef DEBUG_TIMERS + printf("SDL: Removing timer %p\n", t); +#endif + if ( prev ) { + prev->next = next; + } else { + SDL_timers = next; + } + free(t); + -- num_timers; + removed = 1; + } + } + } + /* Don't update prev if the timer has disappeared */ + if ( ! removed ) { + prev = t; + } + } + SDL_mutexV(SDL_timer_mutex); +} + +SDL_TimerID SDL_AddTimer(Uint32 interval, SDL_NewTimerCallback callback, void *param) +{ + SDL_TimerID t; + if ( ! SDL_timer_mutex ) { + if ( SDL_timer_started ) { + SDL_SetError("This platform doesn't support multiple timers"); + } else { + SDL_SetError("You must call SDL_Init(SDL_INIT_TIMER) first"); + } + return NULL; + } + if ( ! SDL_timer_threaded ) { + SDL_SetError("Multiple timers require threaded events!"); + return NULL; + } + SDL_mutexP(SDL_timer_mutex); + t = (SDL_TimerID) malloc(sizeof(struct _SDL_TimerID)); + if ( t ) { + t->interval = ROUND_RESOLUTION(interval); + t->cb = callback; + t->param = param; + t->last_alarm = SDL_GetTicks(); + t->next = SDL_timers; + SDL_timers = t; + ++ num_timers; + list_changed = SDL_TRUE; + SDL_timer_running = 1; + } +#ifdef DEBUG_TIMERS + printf("SDL_AddTimer(%d) = %08x num_timers = %d\n", interval, (Uint32)t, num_timers); +#endif + SDL_mutexV(SDL_timer_mutex); + return t; +} + +SDL_bool SDL_RemoveTimer(SDL_TimerID id) +{ + SDL_TimerID t, prev = NULL; + SDL_bool removed; + + removed = SDL_FALSE; + SDL_mutexP(SDL_timer_mutex); + /* Look for id in the linked list of timers */ + for (t = SDL_timers; t; prev=t, t = t->next ) { + if ( t == id ) { + if(prev) { + prev->next = t->next; + } else { + SDL_timers = t->next; + } + free(t); + -- num_timers; + removed = SDL_TRUE; + list_changed = SDL_TRUE; + break; + } + } +#ifdef DEBUG_TIMERS + printf("SDL_RemoveTimer(%08x) = %d num_timers = %d thread = %d\n", (Uint32)id, removed, num_timers, SDL_ThreadID()); +#endif + SDL_mutexV(SDL_timer_mutex); + return removed; +} + +static void SDL_RemoveAllTimers(SDL_TimerID t) +{ + SDL_TimerID freeme; + + /* Changed to non-recursive implementation. + The recursive implementation is elegant, but subject to + stack overflow if there are lots and lots of timers. + */ + while ( t ) { + freeme = t; + t = t->next; + free(freeme); + } +} + +/* Old style callback functions are wrapped through this */ +static Uint32 callback_wrapper(Uint32 ms, void *param) +{ + SDL_TimerCallback func = (SDL_TimerCallback) param; + return (*func)(ms); +} + +int SDL_SetTimer(Uint32 ms, SDL_TimerCallback callback) +{ + int retval; + +#ifdef DEBUG_TIMERS + printf("SDL_SetTimer(%d)\n", ms); +#endif + retval = 0; + if ( SDL_timer_running ) { /* Stop any currently running timer */ + SDL_timer_running = 0; + if ( SDL_timer_threaded ) { + SDL_mutexP(SDL_timer_mutex); + SDL_RemoveAllTimers(SDL_timers); + SDL_timers = NULL; + SDL_mutexV(SDL_timer_mutex); + } else { + SDL_SYS_StopTimer(); + } + } + if ( ms ) { + if ( SDL_timer_threaded ) { + retval = (SDL_AddTimer(ms, callback_wrapper, + (void *)callback) != NULL); + } else { + SDL_timer_running = 1; + SDL_alarm_interval = ms; + SDL_alarm_callback = callback; + retval = SDL_SYS_StartTimer(); + } + } + return retval; +}