Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

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