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

流媒体/Mpeg4/MP4

开发平台:

Visual C++

  1. /*
  2.     SDL - Simple DirectMedia Layer
  3.     Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002  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.     slouken@libsdl.org
  17.     RDTSC stuff by lompik (lompik@voila.fr) 20/03/2002 
  18. */
  19. #ifdef SAVE_RCSID
  20. static char rcsid =
  21.  "@(#) $Id: SDL_systimer.c,v 1.4 2002/04/22 21:38:03 wmay Exp $";
  22. #endif
  23. #include <stdio.h>
  24. #include <sys/time.h>
  25. #include <signal.h>
  26. #include <unistd.h>
  27. #include <string.h>
  28. #include <errno.h>
  29. #include "SDL_error.h"
  30. #include "SDL_timer.h"
  31. #include "SDL_timer_c.h"
  32. #if _POSIX_THREAD_SYSCALL_SOFT
  33. #include <pthread.h>
  34. #endif
  35. #if defined(DISABLE_THREADS) || defined(FORK_HACK)
  36. #define USE_ITIMER
  37. #endif
  38. /* The following defines should really be determined at configure time */
  39. #if defined(linux)
  40. /* Linux select() changes its timeout parameter upon return to contain
  41.    the remaining time. Most other unixen leave it unchanged or undefined. */
  42. #define SELECT_SETS_REMAINING
  43. #elif defined(__bsdi__) || defined(__FreeBSD__) || defined(__sun)
  44. #define USE_NANOSLEEP
  45. #endif
  46. #if defined(i386) || defined(__i386__)
  47. /* This only works on pentium or newer x86 processors */
  48. /* Actually, this isn't reliable on multi-cpu systems, so is disabled */
  49. /*#define USE_RDTSC*/
  50. #endif
  51. #ifdef USE_RDTSC 
  52. /* The first ticks value of the application */
  53. static unsigned long long start;
  54. static float cpu_mhz1000 = 0.0f;
  55. #if 1
  56. /* This is for old binutils version that don't recognize rdtsc mnemonics.
  57.    But all binutils version supports this.
  58. */
  59. #define rdtsc(t) asm(".byte 0x0f, 0x31; " : "=A" (t));   
  60. #else
  61. #define rdtsc(t) asm("rdtsc" : "=A" (t));
  62. #endif
  63. static float calc_cpu_mhz(void)
  64. {
  65. float cpu_mhz;
  66. unsigned long long tsc_start;
  67. unsigned long long tsc_end;
  68. struct timeval tv_start, tv_end;
  69. long usec_delay;
  70. rdtsc(tsc_start);
  71. gettimeofday(&tv_start, NULL);
  72. sleep(1);
  73. rdtsc(tsc_end);
  74. gettimeofday(&tv_end, NULL);
  75. usec_delay = 1000000L * (tv_end.tv_sec - tv_start.tv_sec) +
  76.                         (tv_end.tv_usec - tv_start.tv_usec);
  77. cpu_mhz = (float)(tsc_end-tsc_start) / usec_delay;
  78. #if 0
  79. printf("cpu MHztt: %.3fn", cpu_mhz);
  80. #endif
  81. return cpu_mhz;
  82. }
  83. #else
  84. /* The first ticks value of the application */
  85. static struct timeval start;
  86. #endif  /* USE_RDTSC */
  87. void SDL_StartTicks(void)
  88. {
  89. /* Set first ticks value */
  90. #ifdef USE_RDTSC
  91. if ( ! cpu_mhz1000 ) {
  92. cpu_mhz1000 = calc_cpu_mhz() * 1000.0f;
  93. }
  94. rdtsc(start);
  95. #else
  96. gettimeofday(&start, NULL);
  97. #endif /* USE_RDTSC */
  98. }
  99. Uint32 SDL_GetTicks (void)
  100. {
  101. #ifdef USE_RDTSC 
  102. unsigned long long now;
  103. if ( ! cpu_mhz1000 ) {
  104. return 0; /* Shouldn't happen. BUG!! */
  105. }
  106. rdtsc(now);
  107. return (Uint32)((now-start)/cpu_mhz1000);
  108. #else
  109. struct timeval now;
  110. Uint32 ticks;
  111. gettimeofday(&now, NULL);
  112. ticks=(now.tv_sec-start.tv_sec)*1000+(now.tv_usec-start.tv_usec)/1000;
  113. return(ticks);
  114. #endif /* USE_RDTSC */
  115. }
  116. void SDL_Delay (Uint32 ms)
  117. {
  118. int was_error;
  119. #ifdef USE_NANOSLEEP
  120. struct timespec elapsed, tv;
  121. #else
  122. struct timeval tv;
  123. #ifndef SELECT_SETS_REMAINING
  124. Uint32 then, now, elapsed;
  125. #endif
  126. #endif
  127. /* Set the timeout interval - Linux only needs to do this once */
  128. #ifdef SELECT_SETS_REMAINING
  129. tv.tv_sec = ms/1000;
  130. tv.tv_usec = (ms%1000)*1000;
  131. #elif defined(USE_NANOSLEEP)
  132. elapsed.tv_sec = ms/1000;
  133. elapsed.tv_nsec = (ms%1000)*1000000;
  134. #else
  135. then = SDL_GetTicks();
  136. #endif
  137. do {
  138. errno = 0;
  139. #if _POSIX_THREAD_SYSCALL_SOFT
  140. pthread_yield_np();
  141. #endif
  142. #ifdef USE_NANOSLEEP
  143. tv.tv_sec = elapsed.tv_sec;
  144. tv.tv_nsec = elapsed.tv_nsec;
  145. was_error = nanosleep(&tv, &elapsed);
  146. #else
  147. #ifndef SELECT_SETS_REMAINING
  148. /* Calculate the time interval left (in case of interrupt) */
  149. now = SDL_GetTicks();
  150. elapsed = (now-then);
  151. then = now;
  152. if ( elapsed >= ms ) {
  153. break;
  154. }
  155. ms -= elapsed;
  156. tv.tv_sec = ms/1000;
  157. tv.tv_usec = (ms%1000)*1000;
  158. #endif
  159. was_error = select(0, NULL, NULL, NULL, &tv);
  160. #endif /* USE_NANOSLEEP */
  161. } while ( was_error && (errno == EINTR) );
  162. }
  163. #ifdef USE_ITIMER
  164. static void HandleAlarm(int sig)
  165. {
  166. Uint32 ms;
  167. if ( SDL_alarm_callback ) {
  168. ms = (*SDL_alarm_callback)(SDL_alarm_interval);
  169. if ( ms != SDL_alarm_interval ) {
  170. SDL_SetTimer(ms, SDL_alarm_callback);
  171. }
  172. }
  173. }
  174. int SDL_SYS_TimerInit(void)
  175. {
  176. struct sigaction action;
  177. /* Set the alarm handler (Linux specific) */
  178. memset(&action, 0, sizeof(action));
  179. action.sa_handler = HandleAlarm;
  180. action.sa_flags = SA_RESTART;
  181. sigemptyset(&action.sa_mask);
  182. sigaction(SIGALRM, &action, NULL);
  183. return(0);
  184. }
  185. void SDL_SYS_TimerQuit(void)
  186. {
  187. SDL_SetTimer(0, NULL);
  188. }
  189. int SDL_SYS_StartTimer(void)
  190. {
  191. struct itimerval timer;
  192. timer.it_value.tv_sec = (SDL_alarm_interval/1000);
  193. timer.it_value.tv_usec = (SDL_alarm_interval%1000)*1000;
  194. timer.it_interval.tv_sec = (SDL_alarm_interval/1000);
  195. timer.it_interval.tv_usec = (SDL_alarm_interval%1000)*1000;
  196. setitimer(ITIMER_REAL, &timer, NULL);
  197. return(0);
  198. }
  199. void SDL_SYS_StopTimer(void)
  200. {
  201. struct itimerval timer;
  202. memset(&timer, 0, (sizeof timer));
  203. setitimer(ITIMER_REAL, &timer, NULL);
  204. }
  205. #else /* USE_ITIMER */
  206. #include "SDL_thread.h"
  207. /* Data to handle a single periodic alarm */
  208. static int timer_alive = 0;
  209. static SDL_Thread *timer = NULL;
  210. static int RunTimer(void *unused)
  211. {
  212. while ( timer_alive ) {
  213. if ( SDL_timer_running ) {
  214. SDL_ThreadedTimerCheck();
  215. }
  216. SDL_Delay(1);
  217. }
  218. return(0);
  219. }
  220. /* This is only called if the event thread is not running */
  221. int SDL_SYS_TimerInit(void)
  222. {
  223. timer_alive = 1;
  224. timer = SDL_CreateThread(RunTimer, NULL);
  225. if ( timer == NULL )
  226. return(-1);
  227. return(SDL_SetTimerThreaded(1));
  228. }
  229. void SDL_SYS_TimerQuit(void)
  230. {
  231. timer_alive = 0;
  232. if ( timer ) {
  233. SDL_WaitThread(timer, NULL);
  234. timer = NULL;
  235. }
  236. }
  237. int SDL_SYS_StartTimer(void)
  238. {
  239. SDL_SetError("Internal logic error: Linux uses threaded timer");
  240. return(-1);
  241. }
  242. void SDL_SYS_StopTimer(void)
  243. {
  244. return;
  245. }
  246. #endif /* USE_ITIMER */