SDL_timer.c
上传用户:sun1608
上传日期:2007-02-02
资源大小:6116k
文件大小:7k
源码类别:

流媒体/Mpeg4/MP4

开发平台:

Visual C++

  1. /*
  2.     SDL - Simple DirectMedia Layer
  3.     Copyright (C) 1997, 1998  Sam Lantinga
  4.     This library is free software; you can redistribute it and/or
  5.     modify it under the terms of the GNU Library General Public
  6.     License as published by the Free Software Foundation; either
  7.     version 2 of the License, or (at your option) any later version.
  8.     This library is distributed in the hope that it will be useful,
  9.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  11.     Library General Public License for more details.
  12.     You should have received a copy of the GNU Library General Public
  13.     License along with this library; if not, write to the Free
  14.     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  15.     Sam Lantinga
  16.     5635-34 Springhouse Dr.
  17.     Pleasanton, CA 94588 (USA)
  18.     slouken@libsdl.org
  19. */
  20. #ifdef SAVE_RCSID
  21. static char rcsid =
  22.  "@(#) $Id: SDL_timer.c,v 1.4 2002/04/22 21:38:03 wmay Exp $";
  23. #endif
  24. #include <stdlib.h>
  25. #include <stdio.h> /* For the definition of NULL */
  26. #include "SDL_error.h"
  27. #include "SDL_timer.h"
  28. #include "SDL_timer_c.h"
  29. #include "SDL_mutex.h"
  30. #include "SDL_systimer.h"
  31. /* #define DEBUG_TIMERS */
  32. int SDL_timer_started = 0;
  33. int SDL_timer_running = 0;
  34. /* Data to handle a single periodic alarm */
  35. Uint32 SDL_alarm_interval = 0;
  36. SDL_TimerCallback SDL_alarm_callback;
  37. static SDL_bool list_changed = SDL_FALSE;
  38. /* Data used for a thread-based timer */
  39. static int SDL_timer_threaded = 0;
  40. struct _SDL_TimerID {
  41. Uint32 interval;
  42. SDL_NewTimerCallback cb;
  43. void *param;
  44. Uint32 last_alarm;
  45. struct _SDL_TimerID *next;
  46. };
  47. static SDL_TimerID SDL_timers = NULL;
  48. static Uint32 num_timers = 0;
  49. static SDL_mutex *SDL_timer_mutex;
  50. /* Set whether or not the timer should use a thread.
  51.    This should not be called while the timer subsystem is running.
  52. */
  53. int SDL_SetTimerThreaded(int value)
  54. {
  55. int retval;
  56. if ( SDL_timer_started ) {
  57. SDL_SetError("Timer already initialized");
  58. retval = -1;
  59. } else {
  60. retval = 0;
  61. SDL_timer_threaded = value;
  62. }
  63. return retval;
  64. }
  65. int SDL_TimerInit(void)
  66. {
  67. int retval;
  68. SDL_timer_running = 0;
  69. SDL_SetTimer(0, NULL);
  70. retval = 0;
  71. if ( ! SDL_timer_threaded ) {
  72. retval = SDL_SYS_TimerInit();
  73. }
  74. if ( SDL_timer_threaded ) {
  75. SDL_timer_mutex = SDL_CreateMutex();
  76. }
  77. SDL_timer_started = 1;
  78. return(retval);
  79. }
  80. void SDL_TimerQuit(void)
  81. {
  82. SDL_SetTimer(0, NULL);
  83. if ( SDL_timer_threaded < 2 ) {
  84. SDL_SYS_TimerQuit();
  85. }
  86. if ( SDL_timer_threaded ) {
  87. SDL_DestroyMutex(SDL_timer_mutex);
  88. }
  89. SDL_timer_started = 0;
  90. SDL_timer_threaded = 0;
  91. }
  92. void SDL_ThreadedTimerCheck(void)
  93. {
  94. Uint32 now, ms;
  95. SDL_TimerID t, prev, next;
  96. int removed;
  97. now = SDL_GetTicks();
  98. SDL_mutexP(SDL_timer_mutex);
  99. for ( prev = NULL, t = SDL_timers; t; t = next ) {
  100. removed = 0;
  101. ms = t->interval - SDL_TIMESLICE;
  102. next = t->next;
  103. if ( (t->last_alarm < now) && ((now - t->last_alarm) > ms) ) {
  104. if ( (now - t->last_alarm) < t->interval ) {
  105. t->last_alarm += t->interval;
  106. } else {
  107. t->last_alarm = now;
  108. }
  109. list_changed = SDL_FALSE;
  110. #ifdef DEBUG_TIMERS
  111. printf("Executing timer %p (thread = %d)n",
  112. t, SDL_ThreadID());
  113. #endif
  114. SDL_mutexV(SDL_timer_mutex);
  115. ms = t->cb(t->interval, t->param);
  116. SDL_mutexP(SDL_timer_mutex);
  117. if ( list_changed ) {
  118. /* Abort, list of timers has been modified */
  119. break;
  120. }
  121. if ( ms != t->interval ) {
  122. if ( ms ) {
  123. t->interval = ROUND_RESOLUTION(ms);
  124. } else { /* Remove the timer from the linked list */
  125. #ifdef DEBUG_TIMERS
  126. printf("SDL: Removing timer %pn", t);
  127. #endif
  128. if ( prev ) {
  129. prev->next = next;
  130. } else {
  131. SDL_timers = next;
  132. }
  133. free(t);
  134. -- num_timers;
  135. removed = 1;
  136. }
  137. }
  138. }
  139. /* Don't update prev if the timer has disappeared */
  140. if ( ! removed ) {
  141. prev = t;
  142. }
  143. }
  144. SDL_mutexV(SDL_timer_mutex);
  145. }
  146. SDL_TimerID SDL_AddTimer(Uint32 interval, SDL_NewTimerCallback callback, void *param)
  147. {
  148. SDL_TimerID t;
  149. if ( ! SDL_timer_mutex ) {
  150. if ( SDL_timer_started ) {
  151. SDL_SetError("This platform doesn't support multiple timers");
  152. } else {
  153. SDL_SetError("You must call SDL_Init(SDL_INIT_TIMER) first");
  154. }
  155. return NULL;
  156. }
  157. if ( ! SDL_timer_threaded ) {
  158. SDL_SetError("Multiple timers require threaded events!");
  159. return NULL;
  160. }
  161. SDL_mutexP(SDL_timer_mutex);
  162. t = (SDL_TimerID) malloc(sizeof(struct _SDL_TimerID));
  163. if ( t ) {
  164. t->interval = ROUND_RESOLUTION(interval);
  165. t->cb = callback;
  166. t->param = param;
  167. t->last_alarm = SDL_GetTicks();
  168. t->next = SDL_timers;
  169. SDL_timers = t;
  170. ++ num_timers;
  171. list_changed = SDL_TRUE;
  172. SDL_timer_running = 1;
  173. }
  174. #ifdef DEBUG_TIMERS
  175. printf("SDL_AddTimer(%d) = %08x num_timers = %dn", interval, (Uint32)t, num_timers);
  176. #endif
  177. SDL_mutexV(SDL_timer_mutex);
  178. return t;
  179. }
  180. SDL_bool SDL_RemoveTimer(SDL_TimerID id)
  181. {
  182. SDL_TimerID t, prev = NULL;
  183. SDL_bool removed;
  184. removed = SDL_FALSE;
  185. SDL_mutexP(SDL_timer_mutex);
  186. /* Look for id in the linked list of timers */
  187. for (t = SDL_timers; t; prev=t, t = t->next ) {
  188. if ( t == id ) {
  189. if(prev) {
  190. prev->next = t->next;
  191. } else {
  192. SDL_timers = t->next;
  193. }
  194. free(t);
  195. -- num_timers;
  196. removed = SDL_TRUE;
  197. list_changed = SDL_TRUE;
  198. break;
  199. }
  200. }
  201. #ifdef DEBUG_TIMERS
  202. printf("SDL_RemoveTimer(%08x) = %d num_timers = %d thread = %dn", (Uint32)id, removed, num_timers, SDL_ThreadID());
  203. #endif
  204. SDL_mutexV(SDL_timer_mutex);
  205. return removed;
  206. }
  207. static void SDL_RemoveAllTimers(SDL_TimerID t)
  208. {
  209. SDL_TimerID freeme;
  210. /* Changed to non-recursive implementation.
  211.    The recursive implementation is elegant, but subject to 
  212.    stack overflow if there are lots and lots of timers.
  213.  */
  214. while ( t ) {
  215. freeme = t;
  216. t = t->next;
  217. free(freeme);
  218. }
  219. }
  220. /* Old style callback functions are wrapped through this */
  221. static Uint32 callback_wrapper(Uint32 ms, void *param)
  222. {
  223. SDL_TimerCallback func = (SDL_TimerCallback) param;
  224. return (*func)(ms);
  225. }
  226. int SDL_SetTimer(Uint32 ms, SDL_TimerCallback callback)
  227. {
  228. int retval;
  229. #ifdef DEBUG_TIMERS
  230. printf("SDL_SetTimer(%d)n", ms);
  231. #endif
  232. retval = 0;
  233. if ( SDL_timer_running ) { /* Stop any currently running timer */
  234. SDL_timer_running = 0;
  235. if ( SDL_timer_threaded ) {
  236. SDL_mutexP(SDL_timer_mutex);
  237. SDL_RemoveAllTimers(SDL_timers);
  238. SDL_timers = NULL;
  239. SDL_mutexV(SDL_timer_mutex);
  240. } else {
  241. SDL_SYS_StopTimer();
  242. }
  243. }
  244. if ( ms ) {
  245. if ( SDL_timer_threaded ) {
  246. retval = (SDL_AddTimer(ms, callback_wrapper,
  247.        (void *)callback) != NULL);
  248. } else {
  249. SDL_timer_running = 1;
  250. SDL_alarm_interval = ms;
  251. SDL_alarm_callback = callback;
  252. retval = SDL_SYS_StartTimer();
  253. }
  254. }
  255. return retval;
  256. }