src/timer/SDL_timer.c
author Edgar Simo <bobbens@gmail.com>
Thu, 31 Jul 2008 09:45:27 +0000
branchgsoc2008_force_feedback
changeset 2561 3696b9ce8a37
parent 1895 c121d94672cb
child 2859 99210400e8b9
permissions -rw-r--r--
Correctness patch, it's up to the SDL_haptic.c to clean up effects, not SDL_syshaptic.c.
     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 {
    43     Uint32 interval;
    44     SDL_NewTimerCallback cb;
    45     void *param;
    46     Uint32 last_alarm;
    47     struct _SDL_TimerID *next;
    48 };
    49 
    50 static SDL_TimerID SDL_timers = NULL;
    51 static SDL_mutex *SDL_timer_mutex;
    52 static volatile SDL_bool list_changed = SDL_FALSE;
    53 
    54 /* Set whether or not the timer should use a thread.
    55    This should not be called while the timer subsystem is running.
    56 */
    57 int
    58 SDL_SetTimerThreaded(int value)
    59 {
    60     int retval;
    61 
    62     if (SDL_timer_started) {
    63         SDL_SetError("Timer already initialized");
    64         retval = -1;
    65     } else {
    66         retval = 0;
    67         SDL_timer_threaded = value;
    68     }
    69     return retval;
    70 }
    71 
    72 int
    73 SDL_TimerInit(void)
    74 {
    75     int retval;
    76 
    77     retval = 0;
    78     if (SDL_timer_started) {
    79         SDL_TimerQuit();
    80     }
    81     if (!SDL_timer_threaded) {
    82         retval = SDL_SYS_TimerInit();
    83     }
    84     if (SDL_timer_threaded) {
    85         SDL_timer_mutex = SDL_CreateMutex();
    86     }
    87     if (retval == 0) {
    88         SDL_timer_started = 1;
    89     }
    90     return (retval);
    91 }
    92 
    93 void
    94 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         SDL_timer_mutex = NULL;
   103     }
   104     SDL_timer_started = 0;
   105     SDL_timer_threaded = 0;
   106 }
   107 
   108 void
   109 SDL_ThreadedTimerCheck(void)
   110 {
   111     Uint32 now, ms;
   112     SDL_TimerID t, prev, next;
   113     SDL_bool removed;
   114 
   115     SDL_mutexP(SDL_timer_mutex);
   116     list_changed = SDL_FALSE;
   117     now = SDL_GetTicks();
   118     for (prev = NULL, t = SDL_timers; t; t = next) {
   119         removed = SDL_FALSE;
   120         ms = t->interval - SDL_TIMESLICE;
   121         next = t->next;
   122         if ((int) (now - t->last_alarm) > (int) ms) {
   123             struct _SDL_TimerID timer;
   124 
   125             if ((now - t->last_alarm) < t->interval) {
   126                 t->last_alarm += t->interval;
   127             } else {
   128                 t->last_alarm = now;
   129             }
   130 #ifdef DEBUG_TIMERS
   131             printf("Executing timer %p (thread = %d)\n", t, SDL_ThreadID());
   132 #endif
   133             timer = *t;
   134             SDL_mutexV(SDL_timer_mutex);
   135             ms = timer.cb(timer.interval, timer.param);
   136             SDL_mutexP(SDL_timer_mutex);
   137             if (list_changed) {
   138                 /* Abort, list of timers modified */
   139                 /* FIXME: what if ms was changed? */
   140                 break;
   141             }
   142             if (ms != t->interval) {
   143                 if (ms) {
   144                     t->interval = ROUND_RESOLUTION(ms);
   145                 } else {
   146                     /* Remove timer from the list */
   147 #ifdef DEBUG_TIMERS
   148                     printf("SDL: Removing timer %p\n", t);
   149 #endif
   150                     if (prev) {
   151                         prev->next = next;
   152                     } else {
   153                         SDL_timers = next;
   154                     }
   155                     SDL_free(t);
   156                     --SDL_timer_running;
   157                     removed = SDL_TRUE;
   158                 }
   159             }
   160         }
   161         /* Don't update prev if the timer has disappeared */
   162         if (!removed) {
   163             prev = t;
   164         }
   165     }
   166     SDL_mutexV(SDL_timer_mutex);
   167 }
   168 
   169 static SDL_TimerID
   170 SDL_AddTimerInternal(Uint32 interval, SDL_NewTimerCallback callback,
   171                      void *param)
   172 {
   173     SDL_TimerID t;
   174     t = (SDL_TimerID) SDL_malloc(sizeof(struct _SDL_TimerID));
   175     if (t) {
   176         t->interval = ROUND_RESOLUTION(interval);
   177         t->cb = callback;
   178         t->param = param;
   179         t->last_alarm = SDL_GetTicks();
   180         t->next = SDL_timers;
   181         SDL_timers = t;
   182         ++SDL_timer_running;
   183         list_changed = SDL_TRUE;
   184     }
   185 #ifdef DEBUG_TIMERS
   186     printf("SDL_AddTimer(%d) = %08x num_timers = %d\n", interval, (Uint32) t,
   187            SDL_timer_running);
   188 #endif
   189     return t;
   190 }
   191 
   192 SDL_TimerID
   193 SDL_AddTimer(Uint32 interval, SDL_NewTimerCallback callback, void *param)
   194 {
   195     SDL_TimerID t;
   196     if (!SDL_timer_mutex) {
   197         if (SDL_timer_started) {
   198             SDL_SetError("This platform doesn't support multiple timers");
   199         } else {
   200             SDL_SetError("You must call SDL_Init(SDL_INIT_TIMER) first");
   201         }
   202         return NULL;
   203     }
   204     if (!SDL_timer_threaded) {
   205         SDL_SetError("Multiple timers require threaded events!");
   206         return NULL;
   207     }
   208     SDL_mutexP(SDL_timer_mutex);
   209     t = SDL_AddTimerInternal(interval, callback, param);
   210     SDL_mutexV(SDL_timer_mutex);
   211     return t;
   212 }
   213 
   214 SDL_bool
   215 SDL_RemoveTimer(SDL_TimerID id)
   216 {
   217     SDL_TimerID t, prev = NULL;
   218     SDL_bool removed;
   219 
   220     removed = SDL_FALSE;
   221     SDL_mutexP(SDL_timer_mutex);
   222     /* Look for id in the linked list of timers */
   223     for (t = SDL_timers; t; prev = t, t = t->next) {
   224         if (t == id) {
   225             if (prev) {
   226                 prev->next = t->next;
   227             } else {
   228                 SDL_timers = t->next;
   229             }
   230             SDL_free(t);
   231             --SDL_timer_running;
   232             removed = SDL_TRUE;
   233             list_changed = SDL_TRUE;
   234             break;
   235         }
   236     }
   237 #ifdef DEBUG_TIMERS
   238     printf("SDL_RemoveTimer(%08x) = %d num_timers = %d thread = %d\n",
   239            (Uint32) id, removed, SDL_timer_running, SDL_ThreadID());
   240 #endif
   241     SDL_mutexV(SDL_timer_mutex);
   242     return removed;
   243 }
   244 
   245 /* Old style callback functions are wrapped through this */
   246 static Uint32 SDLCALL
   247 callback_wrapper(Uint32 ms, void *param)
   248 {
   249     SDL_TimerCallback func = (SDL_TimerCallback) param;
   250     return (*func) (ms);
   251 }
   252 
   253 int
   254 SDL_SetTimer(Uint32 ms, SDL_TimerCallback callback)
   255 {
   256     int retval;
   257 
   258 #ifdef DEBUG_TIMERS
   259     printf("SDL_SetTimer(%d)\n", ms);
   260 #endif
   261     retval = 0;
   262 
   263     if (SDL_timer_threaded) {
   264         SDL_mutexP(SDL_timer_mutex);
   265     }
   266     if (SDL_timer_running) {    /* Stop any currently running timer */
   267         if (SDL_timer_threaded) {
   268             while (SDL_timers) {
   269                 SDL_TimerID freeme = SDL_timers;
   270                 SDL_timers = SDL_timers->next;
   271                 SDL_free(freeme);
   272             }
   273             SDL_timer_running = 0;
   274             list_changed = SDL_TRUE;
   275         } else {
   276             SDL_SYS_StopTimer();
   277             SDL_timer_running = 0;
   278         }
   279     }
   280     if (ms) {
   281         if (SDL_timer_threaded) {
   282             if (SDL_AddTimerInternal
   283                 (ms, callback_wrapper, (void *) callback) == NULL) {
   284                 retval = -1;
   285             }
   286         } else {
   287             SDL_timer_running = 1;
   288             SDL_alarm_interval = ms;
   289             SDL_alarm_callback = callback;
   290             retval = SDL_SYS_StartTimer();
   291         }
   292     }
   293     if (SDL_timer_threaded) {
   294         SDL_mutexV(SDL_timer_mutex);
   295     }
   296 
   297     return retval;
   298 }
   299 
   300 /* vi: set ts=4 sw=4 expandtab: */