symbian-qemu-0.9.1-12/libsdl-trunk/src/timer/SDL_timer.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 /*
       
     2     SDL - Simple DirectMedia Layer
       
     3     Copyright (C) 1997-2006 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 }