Improved timer implementation
authorSam Lantinga <slouken@libsdl.org>
Thu, 27 Jan 2011 14:45:06 -0800
changeset 5111481dabb098ef
parent 5110 0846f18eb625
child 5112 39772ccf7ddd
Improved timer implementation

The new timer model is formalized as using a separate thread to handle timer callbacks. This was the case on almost every platform before, but it's now a requirement, and simplifies the implementation and makes it perform consistently across platforms.

Goals:
* Minimize timer thread blocking
* Dispatch timers as accurately as possible
* SDL_AddTimer() and SDL_RemoveTimer() are completely threadsafe
* SDL_RemoveTimer() doesn't crash with a timer that's expired or removed
include/SDL_compat.h
include/SDL_timer.h
src/SDL_compat.c
src/events/SDL_events.c
src/timer/SDL_systimer.h
src/timer/SDL_timer.c
src/timer/SDL_timer_c.h
src/timer/beos/SDL_systimer.c
src/timer/dummy/SDL_systimer.c
src/timer/nds/SDL_systimer.c
src/timer/unix/SDL_systimer.c
src/timer/wince/SDL_systimer.c
src/timer/windows/SDL_systimer.c
     1.1 --- a/include/SDL_compat.h	Thu Jan 27 10:40:17 2011 -0800
     1.2 +++ b/include/SDL_compat.h	Thu Jan 27 14:45:06 2011 -0800
     1.3 @@ -344,6 +344,13 @@
     1.4  #define SDL_RenderFill(X)  (X) ? SDL_RenderFillRect(X) : SDL_RenderClear()
     1.5  #define SDL_KillThread(X)
     1.6  
     1.7 +/* The timeslice and timer resolution are no longer relevant */
     1.8 +#define SDL_TIMESLICE		10
     1.9 +#define TIMER_RESOLUTION	10
    1.10 +
    1.11 +typedef Uint32 (SDLCALL * SDL_OldTimerCallback) (Uint32 interval);
    1.12 +extern DECLSPEC int SDLCALL SDL_SetTimer(Uint32 interval, SDL_OldTimerCallback callback);
    1.13 +
    1.14  extern DECLSPEC int SDLCALL SDL_putenv(const char *variable);
    1.15  
    1.16  /*@}*//*Compatibility*/
     2.1 --- a/include/SDL_timer.h	Thu Jan 27 10:40:17 2011 -0800
     2.2 +++ b/include/SDL_timer.h	Thu Jan 27 14:45:06 2011 -0800
     2.3 @@ -41,104 +41,50 @@
     2.4  #endif
     2.5  
     2.6  /**
     2.7 - *  This is the OS scheduler timeslice, in milliseconds.
     2.8 - */
     2.9 -#define SDL_TIMESLICE		10
    2.10 -
    2.11 -/**
    2.12 - *  This is the maximum resolution of the SDL timer on all platforms.
    2.13 - */
    2.14 -#define TIMER_RESOLUTION	10      /**< Experimentally determined */
    2.15 -
    2.16 -/**
    2.17 - *  Get the number of milliseconds since the SDL library initialization.
    2.18 + * \brief Get the number of milliseconds since the SDL library initialization.
    2.19   *  
    2.20 - *  Note that this value wraps if the program runs for more than ~49 days.
    2.21 + * \note This value wraps if the program runs for more than ~49 days.
    2.22   */
    2.23  extern DECLSPEC Uint32 SDLCALL SDL_GetTicks(void);
    2.24  
    2.25  /**
    2.26 - *  Wait a specified number of milliseconds before returning.
    2.27 + * \brief Wait a specified number of milliseconds before returning.
    2.28   */
    2.29  extern DECLSPEC void SDLCALL SDL_Delay(Uint32 ms);
    2.30  
    2.31  /**
    2.32   *  Function prototype for the timer callback function.
    2.33 - */
    2.34 -typedef Uint32(SDLCALL * SDL_TimerCallback) (Uint32 interval);
    2.35 -
    2.36 -/**
    2.37 - *  Set a callback to run after the specified number of milliseconds has
    2.38 - *  elapsed. The callback function is passed the current timer interval
    2.39 - *  and returns the next timer interval.  If the returned value is the 
    2.40 - *  same as the one passed in, the periodic alarm continues, otherwise a
    2.41 - *  new alarm is scheduled.  If the callback returns 0, the periodic alarm
    2.42 - *  is cancelled.
    2.43 - *  
    2.44 - *  To cancel a currently running timer, call 
    2.45 - *  \code SDL_SetTimer(0, NULL); \endcode
    2.46 - *  
    2.47 - *  The timer callback function may run in a different thread than your
    2.48 - *  main code, and so shouldn't call any functions from within itself.
    2.49 - *  
    2.50 - *  The maximum resolution of this timer is 10 ms, which means that if
    2.51 - *  you request a 16 ms timer, your callback will run approximately 20 ms
    2.52 - *  later on an unloaded system.  If you wanted to set a flag signaling
    2.53 - *  a frame update at 30 frames per second (every 33 ms), you might set a 
    2.54 - *  timer for 30 ms:
    2.55 - *  \code
    2.56 - *    SDL_SetTimer((33/10)*10, flag_update);
    2.57 - *  \endcode
    2.58 - *  
    2.59 - *  If you use this function, you need to pass ::SDL_INIT_TIMER to SDL_Init().
    2.60 - *  
    2.61 - *  Under UNIX, you should not use raise or use SIGALRM and this function
    2.62 - *  in the same program, as it is implemented using setitimer().  You also
    2.63 - *  should not use this function in multi-threaded applications as signals
    2.64 - *  to multi-threaded apps have undefined behavior in some implementations.
    2.65 - *  
    2.66 - *  \return 0 if successful, or -1 if there was an error.
    2.67 - */
    2.68 -extern DECLSPEC int SDLCALL SDL_SetTimer(Uint32 interval,
    2.69 -                                         SDL_TimerCallback callback);
    2.70 -
    2.71 -/**
    2.72 - *  \name Peter timers
    2.73 - *  New timer API, supports multiple timers
    2.74 - *  Written by Stephane Peter <megastep@lokigames.com>
    2.75 - */
    2.76 -/*@{*/
    2.77 -
    2.78 -/**
    2.79 - *  Function prototype for the new timer callback function.
    2.80   *  
    2.81   *  The callback function is passed the current timer interval and returns
    2.82   *  the next timer interval.  If the returned value is the same as the one
    2.83   *  passed in, the periodic alarm continues, otherwise a new alarm is
    2.84   *  scheduled.  If the callback returns 0, the periodic alarm is cancelled.
    2.85   */
    2.86 -typedef Uint32(SDLCALL * SDL_NewTimerCallback) (Uint32 interval, void *param);
    2.87 +typedef Uint32 (SDLCALL * SDL_TimerCallback) (Uint32 interval, void *param);
    2.88  
    2.89  /**
    2.90 - *  Definition of the timer ID type.
    2.91 + * Definition of the timer ID type.
    2.92   */
    2.93 -typedef struct _SDL_TimerID *SDL_TimerID;
    2.94 +typedef int SDL_TimerID;
    2.95  
    2.96  /**
    2.97 - *  Add a new timer to the pool of timers already running.
    2.98 - *  \return A timer ID, or NULL when an error occurs.
    2.99 + * \brief Add a new timer to the pool of timers already running.
   2.100 + *
   2.101 + * \return A timer ID, or NULL when an error occurs.
   2.102   */
   2.103  extern DECLSPEC SDL_TimerID SDLCALL SDL_AddTimer(Uint32 interval,
   2.104 -                                                 SDL_NewTimerCallback
   2.105 -                                                 callback, void *param);
   2.106 +                                                 SDL_TimerCallback callback,
   2.107 +                                                 void *param);
   2.108  
   2.109  /**
   2.110 - *  Remove one of the multiple timers knowing its ID.
   2.111 - *  \return A boolean value indicating success or failure.
   2.112 + * \brief Remove a timer knowing its ID.
   2.113 + *
   2.114 + * \return A boolean value indicating success or failure.
   2.115 + *
   2.116 + * \warning It is not safe to remove a timer multiple times.
   2.117   */
   2.118  extern DECLSPEC SDL_bool SDLCALL SDL_RemoveTimer(SDL_TimerID t);
   2.119  
   2.120 -/*@}*//*Peter timers*/
   2.121  
   2.122  /* Ends C function definitions when using C++ */
   2.123  #ifdef __cplusplus
     3.1 --- a/src/SDL_compat.c	Thu Jan 27 10:40:17 2011 -0800
     3.2 +++ b/src/SDL_compat.c	Thu Jan 27 14:45:06 2011 -0800
     3.3 @@ -1760,6 +1760,31 @@
     3.4      return previous;
     3.5  }
     3.6  
     3.7 +static Uint32
     3.8 +SDL_SetTimerCallback(Uint32 interval, void* param)
     3.9 +{
    3.10 +    return ((SDL_OldTimerCallback)param)(interval);
    3.11 +}
    3.12 +
    3.13 +int
    3.14 +SDL_SetTimer(Uint32 interval, SDL_OldTimerCallback callback)
    3.15 +{
    3.16 +    static SDL_TimerID compat_timer;
    3.17 +
    3.18 +    if (compat_timer) {
    3.19 +        SDL_RemoveTimer(compat_timer);
    3.20 +        compat_timer = 0;
    3.21 +    }
    3.22 +
    3.23 +    if (interval && callback) {
    3.24 +        compat_timer = SDL_AddTimer(interval, SDL_SetTimerCallback, callback);
    3.25 +        if (!compat_timer) {
    3.26 +            return -1;
    3.27 +        }
    3.28 +    }
    3.29 +    return 0;
    3.30 +}
    3.31 +
    3.32  int
    3.33  SDL_putenv(const char *_var)
    3.34  {
     4.1 --- a/src/events/SDL_events.c	Thu Jan 27 10:40:17 2011 -0800
     4.2 +++ b/src/events/SDL_events.c	Thu Jan 27 14:45:06 2011 -0800
     4.3 @@ -123,9 +123,6 @@
     4.4  
     4.5          /* Give up the CPU for the rest of our timeslice */
     4.6          SDL_EventLock.safe = 1;
     4.7 -        if (SDL_timer_running) {
     4.8 -            SDL_ThreadedTimerCheck();
     4.9 -        }
    4.10          SDL_Delay(1);
    4.11  
    4.12          /* Check for event locking.
    4.13 @@ -140,7 +137,6 @@
    4.14          SDL_EventLock.safe = 0;
    4.15          SDL_mutexV(SDL_EventLock.lock);
    4.16      }
    4.17 -    SDL_SetTimerThreaded(0);
    4.18      event_thread = 0;
    4.19      return (0);
    4.20  }
    4.21 @@ -168,8 +164,6 @@
    4.22          }
    4.23          SDL_EventLock.safe = 0;
    4.24  
    4.25 -        /* The event thread will handle timers too */
    4.26 -        SDL_SetTimerThreaded(2);
    4.27  #if (defined(__WIN32__) && !defined(_WIN32_WCE)) && !defined(HAVE_LIBC)
    4.28  #undef SDL_CreateThread
    4.29          SDL_EventThread =
     5.1 --- a/src/timer/SDL_systimer.h	Thu Jan 27 10:40:17 2011 -0800
     5.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.3 @@ -1,42 +0,0 @@
     5.4 -/*
     5.5 -    SDL - Simple DirectMedia Layer
     5.6 -    Copyright (C) 1997-2010 Sam Lantinga
     5.7 -
     5.8 -    This library is free software; you can redistribute it and/or
     5.9 -    modify it under the terms of the GNU Lesser General Public
    5.10 -    License as published by the Free Software Foundation; either
    5.11 -    version 2.1 of the License, or (at your option) any later version.
    5.12 -
    5.13 -    This library is distributed in the hope that it will be useful,
    5.14 -    but WITHOUT ANY WARRANTY; without even the implied warranty of
    5.15 -    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    5.16 -    Lesser General Public License for more details.
    5.17 -
    5.18 -    You should have received a copy of the GNU Lesser General Public
    5.19 -    License along with this library; if not, write to the Free Software
    5.20 -    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    5.21 -
    5.22 -    Sam Lantinga
    5.23 -    slouken@libsdl.org
    5.24 -*/
    5.25 -#include "SDL_config.h"
    5.26 -
    5.27 -/* The system dependent timer handling functions */
    5.28 -
    5.29 -#include "SDL_timer.h"
    5.30 -#include "SDL_timer_c.h"
    5.31 -
    5.32 -
    5.33 -/* Initialize the system dependent timer subsystem */
    5.34 -extern int SDL_SYS_TimerInit(void);
    5.35 -
    5.36 -/* Quit the system dependent timer subsystem */
    5.37 -extern void SDL_SYS_TimerQuit(void);
    5.38 -
    5.39 -/* Start a timer set up by SDL_SetTimer() */
    5.40 -extern int SDL_SYS_StartTimer(void);
    5.41 -
    5.42 -/* Stop a previously started timer */
    5.43 -extern void SDL_SYS_StopTimer(void);
    5.44 -
    5.45 -/* vi: set ts=4 sw=4 expandtab: */
     6.1 --- a/src/timer/SDL_timer.c	Thu Jan 27 10:40:17 2011 -0800
     6.2 +++ b/src/timer/SDL_timer.c	Thu Jan 27 14:45:06 2011 -0800
     6.3 @@ -23,289 +23,360 @@
     6.4  
     6.5  #include "SDL_timer.h"
     6.6  #include "SDL_timer_c.h"
     6.7 -#include "SDL_mutex.h"
     6.8 -#include "SDL_systimer.h"
     6.9 +#include "SDL_atomic.h"
    6.10 +#include "SDL_thread.h"
    6.11  
    6.12  /* #define DEBUG_TIMERS */
    6.13  
    6.14 -int SDL_timer_started = 0;
    6.15 -int SDL_timer_running = 0;
    6.16 +typedef struct _SDL_Timer
    6.17 +{
    6.18 +    int timerID;
    6.19 +    SDL_TimerCallback callback;
    6.20 +    void *param;
    6.21 +    Uint32 interval;
    6.22 +    Uint32 scheduled;
    6.23 +    volatile SDL_bool canceled;
    6.24 +    struct _SDL_Timer *next;
    6.25 +} SDL_Timer;
    6.26  
    6.27 -/* Data to handle a single periodic alarm */
    6.28 -Uint32 SDL_alarm_interval = 0;
    6.29 -SDL_TimerCallback SDL_alarm_callback;
    6.30 +typedef struct _SDL_TimerMap
    6.31 +{
    6.32 +    int timerID;
    6.33 +    SDL_Timer *timer;
    6.34 +    struct _SDL_TimerMap *next;
    6.35 +} SDL_TimerMap;
    6.36  
    6.37 -/* Data used for a thread-based timer */
    6.38 -static int SDL_timer_threaded = 0;
    6.39 +/* A reasonable guess */
    6.40 +#define CACHELINE_SIZE  128
    6.41  
    6.42 -struct _SDL_TimerID
    6.43 +/* The timers are kept in a sorted list */
    6.44 +typedef struct {
    6.45 +    /* Data used by the main thread */
    6.46 +    SDL_Thread *thread;
    6.47 +    SDL_atomic_t nextID;
    6.48 +    SDL_TimerMap *timermap;
    6.49 +    SDL_mutex *timermap_lock;
    6.50 +
    6.51 +    /* Padding to separate cache lines between threads */
    6.52 +    char pad[CACHELINE_SIZE];
    6.53 +
    6.54 +    /* Data used to communicate with the timer thread */
    6.55 +    SDL_SpinLock lock;
    6.56 +    SDL_sem *sem;
    6.57 +    SDL_Timer * volatile pending;
    6.58 +    SDL_Timer * volatile freelist;
    6.59 +    volatile SDL_bool active;
    6.60 +
    6.61 +    /* List of timers - this is only touched by the timer thread */
    6.62 +    SDL_Timer *timers;
    6.63 +} SDL_TimerData;
    6.64 +
    6.65 +static SDL_TimerData SDL_timer_data;
    6.66 +
    6.67 +
    6.68 +/* The idea here is that any thread might add a timer, but a single
    6.69 + * thread manages the active timer queue, sorted by scheduling time.
    6.70 + *
    6.71 + * Timers are removed by simply setting a canceled flag
    6.72 + */
    6.73 +
    6.74 +static void
    6.75 +SDL_AddTimerInternal(SDL_TimerData *data, SDL_Timer *timer)
    6.76  {
    6.77 -    Uint32 interval;
    6.78 -    SDL_NewTimerCallback cb;
    6.79 -    void *param;
    6.80 -    Uint32 last_alarm;
    6.81 -    struct _SDL_TimerID *next;
    6.82 -};
    6.83 +    SDL_Timer *prev, *curr;
    6.84  
    6.85 -static SDL_TimerID SDL_timers = NULL;
    6.86 -static SDL_mutex *SDL_timer_mutex;
    6.87 -static volatile SDL_bool list_changed = SDL_FALSE;
    6.88 +    prev = NULL;
    6.89 +    for (curr = data->timers; curr; prev = curr, curr = curr->next) {
    6.90 +        if ((Sint32)(timer->scheduled-curr->scheduled) < 0) {
    6.91 +            break;
    6.92 +        }
    6.93 +    }
    6.94  
    6.95 -/* Set whether or not the timer should use a thread.
    6.96 -   This should not be called while the timer subsystem is running.
    6.97 -*/
    6.98 -int
    6.99 -SDL_SetTimerThreaded(int value)
   6.100 +    /* Insert the timer here! */
   6.101 +    if (prev) {
   6.102 +        prev->next = timer;
   6.103 +    } else {
   6.104 +        data->timers = timer;
   6.105 +    }
   6.106 +    timer->next = curr;
   6.107 +}
   6.108 +
   6.109 +static int
   6.110 +SDL_TimerThread(void *_data)
   6.111  {
   6.112 -    int retval;
   6.113 +    SDL_TimerData *data = (SDL_TimerData *)_data;
   6.114 +    SDL_Timer *pending;
   6.115 +    SDL_Timer *current;
   6.116 +    SDL_Timer *freelist_head = NULL;
   6.117 +    SDL_Timer *freelist_tail = NULL;
   6.118 +    Uint32 tick, now, interval, delay;
   6.119  
   6.120 -    if (SDL_timer_started) {
   6.121 -        SDL_SetError("Timer already initialized");
   6.122 -        retval = -1;
   6.123 -    } else {
   6.124 -        retval = 0;
   6.125 -        SDL_timer_threaded = value;
   6.126 +    /* Threaded timer loop:
   6.127 +     *  1. Queue timers added by other threads
   6.128 +     *  2. Handle any timers that should dispatch this cycle
   6.129 +     *  3. Wait until next dispatch time or new timer arrives
   6.130 +     */
   6.131 +    for ( ; ; ) {
   6.132 +        /* Pending and freelist maintenance */
   6.133 +        SDL_AtomicLock(&data->lock);
   6.134 +        {
   6.135 +            /* Get any timers ready to be queued */
   6.136 +            pending = data->pending;
   6.137 +            data->pending = NULL;
   6.138 +
   6.139 +            /* Make any unused timer structures available */
   6.140 +            if (freelist_head) {
   6.141 +                freelist_tail->next = data->freelist;
   6.142 +                data->freelist = freelist_head;
   6.143 +            }
   6.144 +        }
   6.145 +        SDL_AtomicUnlock(&data->lock);
   6.146 +
   6.147 +        /* Sort the pending timers into our list */
   6.148 +        while (pending) {
   6.149 +            current = pending;
   6.150 +            pending = pending->next;
   6.151 +            SDL_AddTimerInternal(data, current);
   6.152 +        }
   6.153 +        freelist_head = NULL;
   6.154 +        freelist_tail = NULL;
   6.155 +
   6.156 +        /* Check to see if we're still running, after maintenance */
   6.157 +        if (!data->active) {
   6.158 +            break;
   6.159 +        }
   6.160 +
   6.161 +        /* Initial delay if there are no timers */
   6.162 +        delay = SDL_MUTEX_MAXWAIT;
   6.163 +
   6.164 +        tick = SDL_GetTicks();
   6.165 +
   6.166 +        /* Process all the pending timers for this tick */
   6.167 +        while (data->timers) {
   6.168 +            current = data->timers;
   6.169 +
   6.170 +            if ((Sint32)(tick-current->scheduled) < 0) {
   6.171 +                /* Scheduled for the future, wait a bit */
   6.172 +                delay = (current->scheduled - tick);
   6.173 +                break;
   6.174 +            }
   6.175 +
   6.176 +            /* We're going to do something with this timer */
   6.177 +            data->timers = current->next;
   6.178 +
   6.179 +            if (current->canceled) {
   6.180 +                interval = 0;
   6.181 +            } else {
   6.182 +                interval = current->callback(current->interval, current->param);
   6.183 +            }
   6.184 +
   6.185 +            if (interval > 0) {
   6.186 +                /* Reschedule this timer */
   6.187 +                current->scheduled = tick + interval;
   6.188 +                SDL_AddTimerInternal(data, current);
   6.189 +            } else {
   6.190 +                if (!freelist_head) {
   6.191 +                    freelist_head = current;
   6.192 +                }
   6.193 +                if (freelist_tail) {
   6.194 +                    freelist_tail->next = current;
   6.195 +                }
   6.196 +                freelist_tail = current;
   6.197 +
   6.198 +                current->canceled = SDL_TRUE;
   6.199 +            }
   6.200 +        }
   6.201 +
   6.202 +        /* Adjust the delay based on processing time */
   6.203 +        now = SDL_GetTicks();
   6.204 +        interval = (now - tick);
   6.205 +        if (interval > delay) {
   6.206 +            delay = 0;
   6.207 +        } else {
   6.208 +            delay -= interval;
   6.209 +        }
   6.210 +
   6.211 +        /* Note that each time a timer is added, this will return
   6.212 +           immediately, but we process the timers added all at once.
   6.213 +           That's okay, it just means we run through the loop a few
   6.214 +           extra times.
   6.215 +         */
   6.216 +        SDL_SemWaitTimeout(data->sem, delay);
   6.217      }
   6.218 -    return retval;
   6.219 +    return 0;
   6.220  }
   6.221  
   6.222  int
   6.223  SDL_TimerInit(void)
   6.224  {
   6.225 -    int retval;
   6.226 +    SDL_TimerData *data = &SDL_timer_data;
   6.227  
   6.228 -    retval = 0;
   6.229 -    if (SDL_timer_started) {
   6.230 -        SDL_TimerQuit();
   6.231 +    if (!data->active) {
   6.232 +        data->timermap_lock = SDL_CreateMutex();
   6.233 +        if (!data->timermap_lock) {
   6.234 +            return -1;
   6.235 +        }
   6.236 +
   6.237 +        data->sem = SDL_CreateSemaphore(0);
   6.238 +        if (!data->sem) {
   6.239 +            SDL_DestroyMutex(data->timermap_lock);
   6.240 +            return -1;
   6.241 +        }
   6.242 +
   6.243 +        data->active = SDL_TRUE;
   6.244 +        data->thread = SDL_CreateThread(SDL_TimerThread, data);
   6.245 +        if (!data->thread) {
   6.246 +            SDL_TimerQuit();
   6.247 +            return -1;
   6.248 +        }
   6.249 +
   6.250 +        SDL_AtomicSet(&data->nextID, 1);
   6.251      }
   6.252 -    if (!SDL_timer_threaded) {
   6.253 -        retval = SDL_SYS_TimerInit();
   6.254 -    }
   6.255 -    if (SDL_timer_threaded) {
   6.256 -        SDL_timer_mutex = SDL_CreateMutex();
   6.257 -    }
   6.258 -    if (retval == 0) {
   6.259 -        SDL_timer_started = 1;
   6.260 -    }
   6.261 -    return (retval);
   6.262 +    return 0;
   6.263  }
   6.264  
   6.265  void
   6.266  SDL_TimerQuit(void)
   6.267  {
   6.268 -    SDL_SetTimer(0, NULL);
   6.269 -    if (SDL_timer_threaded < 2) {
   6.270 -        SDL_SYS_TimerQuit();
   6.271 +    SDL_TimerData *data = &SDL_timer_data;
   6.272 +    SDL_Timer *timer;
   6.273 +    SDL_TimerMap *entry;
   6.274 +
   6.275 +    if (data->active) {
   6.276 +        data->active = SDL_FALSE;
   6.277 +
   6.278 +        /* Shutdown the timer thread */
   6.279 +        if (data->thread) {
   6.280 +            SDL_SemPost(data->sem);
   6.281 +            SDL_WaitThread(data->thread, NULL);
   6.282 +            data->thread = NULL;
   6.283 +        }
   6.284 +
   6.285 +        SDL_DestroySemaphore(data->sem);
   6.286 +        data->sem = NULL;
   6.287 +
   6.288 +        /* Clean up the timer entries */
   6.289 +        while (data->timers) {
   6.290 +            timer = data->timers;
   6.291 +            data->timers = timer->next;
   6.292 +            SDL_free(timer);
   6.293 +        }
   6.294 +        while (data->freelist) {
   6.295 +            timer = data->freelist;
   6.296 +            data->freelist = timer->next;
   6.297 +            SDL_free(timer);
   6.298 +        }
   6.299 +        while (data->timermap) {
   6.300 +            entry = data->timermap;
   6.301 +            data->timermap = entry->next;
   6.302 +            SDL_free(entry);
   6.303 +        }
   6.304 +
   6.305 +        SDL_DestroyMutex(data->timermap_lock);
   6.306 +        data->timermap_lock = NULL;
   6.307      }
   6.308 -    if (SDL_timer_threaded) {
   6.309 -        SDL_DestroyMutex(SDL_timer_mutex);
   6.310 -        SDL_timer_mutex = NULL;
   6.311 -    }
   6.312 -    SDL_timer_started = 0;
   6.313 -    SDL_timer_threaded = 0;
   6.314 -}
   6.315 -
   6.316 -void
   6.317 -SDL_ThreadedTimerCheck(void)
   6.318 -{
   6.319 -    Uint32 now, ms;
   6.320 -    SDL_TimerID t, prev, next;
   6.321 -    SDL_bool removed;
   6.322 -
   6.323 -    SDL_mutexP(SDL_timer_mutex);
   6.324 -
   6.325 -    now = SDL_GetTicks();
   6.326 -    do {
   6.327 -        list_changed = SDL_FALSE;
   6.328 -        for (prev = NULL, t = SDL_timers; t; t = next) {
   6.329 -            removed = SDL_FALSE;
   6.330 -            ms = t->interval - SDL_TIMESLICE;
   6.331 -            next = t->next;
   6.332 -            if ((int) (now - t->last_alarm) > (int) ms) {
   6.333 -                struct _SDL_TimerID timer;
   6.334 -
   6.335 -                if ((now - t->last_alarm) < t->interval) {
   6.336 -                    t->last_alarm += t->interval;
   6.337 -                } else {
   6.338 -                    t->last_alarm = now;
   6.339 -                }
   6.340 -#ifdef DEBUG_TIMERS
   6.341 -                printf("Executing timer %p (thread = %lu)\n",
   6.342 -                       t, SDL_ThreadID());
   6.343 -#endif
   6.344 -                timer = *t;
   6.345 -                SDL_mutexV(SDL_timer_mutex);
   6.346 -                ms = timer.cb(timer.interval, timer.param);
   6.347 -                SDL_mutexP(SDL_timer_mutex);
   6.348 -                if (list_changed) {
   6.349 -                    next = t->next;
   6.350 -                    for (prev = SDL_timers; prev; prev = prev->next) {
   6.351 -                        if (prev->next == t)
   6.352 -                            break;
   6.353 -                    }
   6.354 -                }
   6.355 -                if (ms != t->interval) {
   6.356 -                    if (ms) {
   6.357 -                        t->interval = ROUND_RESOLUTION(ms);
   6.358 -                    } else {
   6.359 -                        /* Remove timer from the list */
   6.360 -#ifdef DEBUG_TIMERS
   6.361 -                        printf("SDL: Removing timer %p\n", t);
   6.362 -#endif
   6.363 -                        if (prev) {
   6.364 -                            prev->next = next;
   6.365 -                        } else {
   6.366 -                            SDL_timers = next;
   6.367 -                        }
   6.368 -                        SDL_free(t);
   6.369 -                        --SDL_timer_running;
   6.370 -                        removed = SDL_TRUE;
   6.371 -                    }
   6.372 -                }
   6.373 -                if (list_changed) {
   6.374 -                    /* Abort, list of timers modified */
   6.375 -                    break;
   6.376 -                }
   6.377 -            }
   6.378 -            /* Don't update prev if the timer has disappeared */
   6.379 -            if (!removed) {
   6.380 -                prev = t;
   6.381 -            }
   6.382 -        }
   6.383 -    } while (list_changed);
   6.384 -
   6.385 -    SDL_mutexV(SDL_timer_mutex);
   6.386 -}
   6.387 -
   6.388 -static SDL_TimerID
   6.389 -SDL_AddTimerInternal(Uint32 interval, SDL_NewTimerCallback callback,
   6.390 -                     void *param)
   6.391 -{
   6.392 -    SDL_TimerID t;
   6.393 -    t = (SDL_TimerID) SDL_malloc(sizeof(struct _SDL_TimerID));
   6.394 -    if (t) {
   6.395 -        t->interval = ROUND_RESOLUTION(interval);
   6.396 -        t->cb = callback;
   6.397 -        t->param = param;
   6.398 -        t->last_alarm = SDL_GetTicks();
   6.399 -        t->next = SDL_timers;
   6.400 -        SDL_timers = t;
   6.401 -        ++SDL_timer_running;
   6.402 -        list_changed = SDL_TRUE;
   6.403 -    }
   6.404 -#ifdef DEBUG_TIMERS
   6.405 -    printf("SDL_AddTimer(%d) = %08x num_timers = %d\n", interval, (Uint32) t,
   6.406 -           SDL_timer_running);
   6.407 -#endif
   6.408 -    return t;
   6.409  }
   6.410  
   6.411  SDL_TimerID
   6.412 -SDL_AddTimer(Uint32 interval, SDL_NewTimerCallback callback, void *param)
   6.413 +SDL_AddTimer(Uint32 interval, SDL_TimerCallback callback, void *param)
   6.414  {
   6.415 -    SDL_TimerID t;
   6.416 -    if (!SDL_timer_mutex) {
   6.417 -        if (SDL_timer_started) {
   6.418 -            SDL_SetError("This platform doesn't support multiple timers");
   6.419 -        } else {
   6.420 -            SDL_SetError("You must call SDL_Init(SDL_INIT_TIMER) first");
   6.421 +    SDL_TimerData *data = &SDL_timer_data;
   6.422 +    SDL_Timer *timer;
   6.423 +    SDL_TimerMap *entry;
   6.424 +
   6.425 +    if (!data->active) {
   6.426 +        int status = 0;
   6.427 +
   6.428 +        SDL_AtomicLock(&data->lock);
   6.429 +        if (!data->active) {
   6.430 +            status = SDL_TimerInit();
   6.431          }
   6.432 -        return NULL;
   6.433 +        SDL_AtomicUnlock(&data->lock);
   6.434 +
   6.435 +        if (status < 0) {
   6.436 +            return 0;
   6.437 +        }
   6.438      }
   6.439 -    if (!SDL_timer_threaded) {
   6.440 -        SDL_SetError("Multiple timers require threaded events!");
   6.441 -        return NULL;
   6.442 +
   6.443 +    SDL_AtomicLock(&data->lock);
   6.444 +    timer = data->freelist;
   6.445 +    if (timer) {
   6.446 +        data->freelist = timer->next;
   6.447      }
   6.448 -    SDL_mutexP(SDL_timer_mutex);
   6.449 -    t = SDL_AddTimerInternal(interval, callback, param);
   6.450 -    SDL_mutexV(SDL_timer_mutex);
   6.451 -    return t;
   6.452 +    SDL_AtomicUnlock(&data->lock);
   6.453 +
   6.454 +    if (timer) {
   6.455 +        SDL_RemoveTimer(timer->timerID);
   6.456 +    } else {
   6.457 +        timer = (SDL_Timer *)SDL_malloc(sizeof(*timer));
   6.458 +        if (!timer) {
   6.459 +            SDL_OutOfMemory();
   6.460 +            return 0;
   6.461 +        }
   6.462 +    }
   6.463 +    timer->timerID = SDL_AtomicIncRef(&data->nextID);
   6.464 +    timer->callback = callback;
   6.465 +    timer->param = param;
   6.466 +    timer->interval = interval;
   6.467 +    timer->scheduled = SDL_GetTicks() + interval;
   6.468 +    timer->canceled = SDL_FALSE;
   6.469 + 
   6.470 +    entry = (SDL_TimerMap *)SDL_malloc(sizeof(*entry));
   6.471 +    if (!entry) {
   6.472 +        SDL_free(timer);
   6.473 +        SDL_OutOfMemory();
   6.474 +        return 0;
   6.475 +    }
   6.476 +    entry->timer = timer;
   6.477 +    entry->timerID = timer->timerID;
   6.478 +
   6.479 +    SDL_mutexP(data->timermap_lock);
   6.480 +    entry->next = data->timermap;
   6.481 +    data->timermap = entry;
   6.482 +    SDL_mutexV(data->timermap_lock);
   6.483 +
   6.484 +    /* Add the timer to the pending list for the timer thread */
   6.485 +    SDL_AtomicLock(&data->lock);
   6.486 +    timer->next = data->pending;
   6.487 +    data->pending = timer;
   6.488 +    SDL_AtomicUnlock(&data->lock);
   6.489 +
   6.490 +    /* Wake up the timer thread if necessary */
   6.491 +    SDL_SemPost(data->sem);
   6.492 +
   6.493 +    return entry->timerID;
   6.494  }
   6.495  
   6.496  SDL_bool
   6.497  SDL_RemoveTimer(SDL_TimerID id)
   6.498  {
   6.499 -    SDL_TimerID t, prev = NULL;
   6.500 -    SDL_bool removed;
   6.501 +    SDL_TimerData *data = &SDL_timer_data;
   6.502 +    SDL_TimerMap *prev, *entry;
   6.503 +    SDL_bool canceled = SDL_FALSE;
   6.504  
   6.505 -    removed = SDL_FALSE;
   6.506 -    SDL_mutexP(SDL_timer_mutex);
   6.507 -    /* Look for id in the linked list of timers */
   6.508 -    for (t = SDL_timers; t; prev = t, t = t->next) {
   6.509 -        if (t == id) {
   6.510 +    /* Find the timer */
   6.511 +    SDL_mutexP(data->timermap_lock);
   6.512 +    prev = NULL;
   6.513 +    for (entry = data->timermap; entry; prev = entry, entry = entry->next) {
   6.514 +        if (entry->timerID == id) {
   6.515              if (prev) {
   6.516 -                prev->next = t->next;
   6.517 +                prev->next = entry->next;
   6.518              } else {
   6.519 -                SDL_timers = t->next;
   6.520 +                data->timermap = entry->next;
   6.521              }
   6.522 -            SDL_free(t);
   6.523 -            --SDL_timer_running;
   6.524 -            removed = SDL_TRUE;
   6.525 -            list_changed = SDL_TRUE;
   6.526              break;
   6.527          }
   6.528      }
   6.529 -#ifdef DEBUG_TIMERS
   6.530 -    printf("SDL_RemoveTimer(%08x) = %d num_timers = %d thread = %lu\n",
   6.531 -           (Uint32) id, removed, SDL_timer_running, SDL_ThreadID());
   6.532 -#endif
   6.533 -    SDL_mutexV(SDL_timer_mutex);
   6.534 -    return removed;
   6.535 -}
   6.536 +    SDL_mutexV(data->timermap_lock);
   6.537  
   6.538 -/* Old style callback functions are wrapped through this */
   6.539 -static Uint32 SDLCALL
   6.540 -callback_wrapper(Uint32 ms, void *param)
   6.541 -{
   6.542 -    SDL_TimerCallback func = (SDL_TimerCallback) param;
   6.543 -    return (*func) (ms);
   6.544 -}
   6.545 -
   6.546 -int
   6.547 -SDL_SetTimer(Uint32 ms, SDL_TimerCallback callback)
   6.548 -{
   6.549 -    int retval;
   6.550 -
   6.551 -#ifdef DEBUG_TIMERS
   6.552 -    printf("SDL_SetTimer(%d)\n", ms);
   6.553 -#endif
   6.554 -    retval = 0;
   6.555 -
   6.556 -    if (SDL_timer_threaded) {
   6.557 -        SDL_mutexP(SDL_timer_mutex);
   6.558 +    if (entry) {
   6.559 +        if (!entry->timer->canceled) {
   6.560 +            entry->timer->canceled = SDL_TRUE;
   6.561 +            canceled = SDL_TRUE;
   6.562 +        }
   6.563 +        SDL_free(entry);
   6.564      }
   6.565 -    if (SDL_timer_running) {    /* Stop any currently running timer */
   6.566 -        if (SDL_timer_threaded) {
   6.567 -            while (SDL_timers) {
   6.568 -                SDL_TimerID freeme = SDL_timers;
   6.569 -                SDL_timers = SDL_timers->next;
   6.570 -                SDL_free(freeme);
   6.571 -            }
   6.572 -            SDL_timer_running = 0;
   6.573 -            list_changed = SDL_TRUE;
   6.574 -        } else {
   6.575 -            SDL_SYS_StopTimer();
   6.576 -            SDL_timer_running = 0;
   6.577 -        }
   6.578 -    }
   6.579 -    if (ms) {
   6.580 -        if (SDL_timer_threaded) {
   6.581 -            if (SDL_AddTimerInternal
   6.582 -                (ms, callback_wrapper, (void *) callback) == NULL) {
   6.583 -                retval = -1;
   6.584 -            }
   6.585 -        } else {
   6.586 -            SDL_timer_running = 1;
   6.587 -            SDL_alarm_interval = ms;
   6.588 -            SDL_alarm_callback = callback;
   6.589 -            retval = SDL_SYS_StartTimer();
   6.590 -        }
   6.591 -    }
   6.592 -    if (SDL_timer_threaded) {
   6.593 -        SDL_mutexV(SDL_timer_mutex);
   6.594 -    }
   6.595 -
   6.596 -    return retval;
   6.597 +    return canceled;
   6.598  }
   6.599  
   6.600  /* vi: set ts=4 sw=4 expandtab: */
     7.1 --- a/src/timer/SDL_timer_c.h	Thu Jan 27 10:40:17 2011 -0800
     7.2 +++ b/src/timer/SDL_timer_c.h	Thu Jan 27 14:45:06 2011 -0800
     7.3 @@ -27,21 +27,7 @@
     7.4  #define ROUND_RESOLUTION(X)	\
     7.5  	(((X+TIMER_RESOLUTION-1)/TIMER_RESOLUTION)*TIMER_RESOLUTION)
     7.6  
     7.7 -extern int SDL_timer_started;
     7.8 -extern int SDL_timer_running;
     7.9 -
    7.10 -/* Data to handle a single periodic alarm */
    7.11 -extern Uint32 SDL_alarm_interval;
    7.12 -extern SDL_TimerCallback SDL_alarm_callback;
    7.13 -
    7.14 -/* Set whether or not the timer should use a thread.
    7.15 -   This should be called while the timer subsystem is running.
    7.16 -*/
    7.17 -extern int SDL_SetTimerThreaded(int value);
    7.18 -
    7.19  extern int SDL_TimerInit(void);
    7.20  extern void SDL_TimerQuit(void);
    7.21  
    7.22 -/* This function is called from the SDL event thread if it is available */
    7.23 -extern void SDL_ThreadedTimerCheck(void);
    7.24  /* vi: set ts=4 sw=4 expandtab: */
     8.1 --- a/src/timer/beos/SDL_systimer.c	Thu Jan 27 10:40:17 2011 -0800
     8.2 +++ b/src/timer/beos/SDL_systimer.c	Thu Jan 27 14:45:06 2011 -0800
     8.3 @@ -25,9 +25,7 @@
     8.4  
     8.5  #include <be/kernel/OS.h>
     8.6  
     8.7 -#include "SDL_thread.h"
     8.8  #include "SDL_timer.h"
     8.9 -#include "../SDL_timer_c.h"
    8.10  
    8.11  static bigtime_t start;
    8.12  
    8.13 @@ -50,55 +48,6 @@
    8.14      snooze(ms * 1000);
    8.15  }
    8.16  
    8.17 -/* Data to handle a single periodic alarm */
    8.18 -static int timer_alive = 0;
    8.19 -static SDL_Thread *timer = NULL;
    8.20 +#endif /* SDL_TIMER_BEOS */
    8.21  
    8.22 -static int
    8.23 -RunTimer(void *unused)
    8.24 -{
    8.25 -    while (timer_alive) {
    8.26 -        if (SDL_timer_running) {
    8.27 -            SDL_ThreadedTimerCheck();
    8.28 -        }
    8.29 -        SDL_Delay(10);
    8.30 -    }
    8.31 -    return (0);
    8.32 -}
    8.33 -
    8.34 -/* This is only called if the event thread is not running */
    8.35 -int
    8.36 -SDL_SYS_TimerInit(void)
    8.37 -{
    8.38 -    timer_alive = 1;
    8.39 -    timer = SDL_CreateThread(RunTimer, NULL);
    8.40 -    if (timer == NULL)
    8.41 -        return (-1);
    8.42 -    return (SDL_SetTimerThreaded(1));
    8.43 -}
    8.44 -
    8.45 -void
    8.46 -SDL_SYS_TimerQuit(void)
    8.47 -{
    8.48 -    timer_alive = 0;
    8.49 -    if (timer) {
    8.50 -        SDL_WaitThread(timer, NULL);
    8.51 -        timer = NULL;
    8.52 -    }
    8.53 -}
    8.54 -
    8.55 -int
    8.56 -SDL_SYS_StartTimer(void)
    8.57 -{
    8.58 -    SDL_SetError("Internal logic error: BeOS uses threaded timer");
    8.59 -    return (-1);
    8.60 -}
    8.61 -
    8.62 -void
    8.63 -SDL_SYS_StopTimer(void)
    8.64 -{
    8.65 -    return;
    8.66 -}
    8.67 -
    8.68 -#endif /* SDL_TIMER_BEOS */
    8.69  /* vi: set ts=4 sw=4 expandtab: */
     9.1 --- a/src/timer/dummy/SDL_systimer.c	Thu Jan 27 10:40:17 2011 -0800
     9.2 +++ b/src/timer/dummy/SDL_systimer.c	Thu Jan 27 14:45:06 2011 -0800
     9.3 @@ -24,7 +24,6 @@
     9.4  #if defined(SDL_TIMER_DUMMY) || defined(SDL_TIMERS_DISABLED)
     9.5  
     9.6  #include "SDL_timer.h"
     9.7 -#include "../SDL_timer_c.h"
     9.8  
     9.9  void
    9.10  SDL_StartTicks(void)
    9.11 @@ -44,57 +43,6 @@
    9.12      SDL_Unsupported();
    9.13  }
    9.14  
    9.15 -#include "SDL_thread.h"
    9.16 +#endif /* SDL_TIMER_DUMMY || SDL_TIMERS_DISABLED */
    9.17  
    9.18 -/* Data to handle a single periodic alarm */
    9.19 -static int timer_alive = 0;
    9.20 -static SDL_Thread *timer = NULL;
    9.21 -
    9.22 -static int
    9.23 -RunTimer(void *unused)
    9.24 -{
    9.25 -    while (timer_alive) {
    9.26 -        if (SDL_timer_running) {
    9.27 -            SDL_ThreadedTimerCheck();
    9.28 -        }
    9.29 -        SDL_Delay(1);
    9.30 -    }
    9.31 -    return (0);
    9.32 -}
    9.33 -
    9.34 -/* This is only called if the event thread is not running */
    9.35 -int
    9.36 -SDL_SYS_TimerInit(void)
    9.37 -{
    9.38 -    timer_alive = 1;
    9.39 -    timer = SDL_CreateThread(RunTimer, NULL);
    9.40 -    if (timer == NULL)
    9.41 -        return (-1);
    9.42 -    return (SDL_SetTimerThreaded(1));
    9.43 -}
    9.44 -
    9.45 -void
    9.46 -SDL_SYS_TimerQuit(void)
    9.47 -{
    9.48 -    timer_alive = 0;
    9.49 -    if (timer) {
    9.50 -        SDL_WaitThread(timer, NULL);
    9.51 -        timer = NULL;
    9.52 -    }
    9.53 -}
    9.54 -
    9.55 -int
    9.56 -SDL_SYS_StartTimer(void)
    9.57 -{
    9.58 -    SDL_SetError("Internal logic error: threaded timer in use");
    9.59 -    return (-1);
    9.60 -}
    9.61 -
    9.62 -void
    9.63 -SDL_SYS_StopTimer(void)
    9.64 -{
    9.65 -    return;
    9.66 -}
    9.67 -
    9.68 -#endif /* SDL_TIMER_DUMMY || SDL_TIMERS_DISABLED */
    9.69  /* vi: set ts=4 sw=4 expandtab: */
    10.1 --- a/src/timer/nds/SDL_systimer.c	Thu Jan 27 10:40:17 2011 -0800
    10.2 +++ b/src/timer/nds/SDL_systimer.c	Thu Jan 27 14:45:06 2011 -0800
    10.3 @@ -27,22 +27,25 @@
    10.4  #include <nds/timers.h>
    10.5  
    10.6  #include "SDL_timer.h"
    10.7 -#include "../SDL_timer_c.h"
    10.8 -#include "../SDL_systimer.h"
    10.9  
   10.10 -/* Data to handle a single periodic alarm */
   10.11 -static int timer_alive = 0;
   10.12 -static Uint32 timer_ticks;
   10.13 +
   10.14 +static volatile Uint32 timer_ticks;
   10.15 +
   10.16 +static void
   10.17 +NDS_TimerInterrupt(void)
   10.18 +{
   10.19 +    timer_ticks++;
   10.20 +}
   10.21  
   10.22  void
   10.23  SDL_StartTicks(void)
   10.24  {
   10.25 -    if (!timer_alive) {
   10.26 -        SDL_SYS_TimerInit();
   10.27 -        SDL_SYS_StartTimer();
   10.28 -    }
   10.29 +    timer_ticks = 0;
   10.30  
   10.31 -    timer_ticks = 0;
   10.32 +    TIMER_CR(3) = TIMER_DIV_1024 | TIMER_IRQ_REQ;
   10.33 +    TIMER_DATA(3) = TIMER_FREQ_1024(1000);
   10.34 +    irqSet(IRQ_TIMER3, NDS_TimerInterrupt);
   10.35 +    irqEnable(IRQ_TIMER3);
   10.36  }
   10.37  
   10.38  Uint32
   10.39 @@ -61,60 +64,6 @@
   10.40      }
   10.41  }
   10.42  
   10.43 -static int
   10.44 -RunTimer(void *unused)
   10.45 -{
   10.46 -    while (timer_alive) {
   10.47 -        if (SDL_timer_running) {
   10.48 -        }
   10.49 -        SDL_Delay(1);
   10.50 -    }
   10.51 -    return (0);
   10.52 -}
   10.53 +#endif /* SDL_TIMER_NDS */
   10.54  
   10.55 -void
   10.56 -NDS_TimerInterrupt(void)
   10.57 -{
   10.58 -    timer_ticks++;
   10.59 -}
   10.60 -
   10.61 -/* This is only called if the event thread is not running */
   10.62 -int
   10.63 -SDL_SYS_TimerInit(void)
   10.64 -{
   10.65 -    timer_alive = 1;
   10.66 -    timer_ticks = 0;
   10.67 -    TIMER_CR(3) = TIMER_DIV_1024 | TIMER_IRQ_REQ;
   10.68 -    TIMER_DATA(3) = TIMER_FREQ_1024(1000);
   10.69 -    irqSet(IRQ_TIMER3, NDS_TimerInterrupt);
   10.70 -    irqEnable(IRQ_TIMER3);
   10.71 -    return 0;
   10.72 -}
   10.73 -
   10.74 -void
   10.75 -SDL_SYS_TimerQuit(void)
   10.76 -{
   10.77 -    if (timer_alive) {
   10.78 -        TIMER_CR(3) = 0;
   10.79 -    }
   10.80 -    timer_alive = 0;
   10.81 -    irqDisable(IRQ_TIMER3);
   10.82 -}
   10.83 -
   10.84 -int
   10.85 -SDL_SYS_StartTimer(void)
   10.86 -{
   10.87 -    TIMER_CR(3) |= TIMER_ENABLE;
   10.88 -    return 0;
   10.89 -}
   10.90 -
   10.91 -void
   10.92 -SDL_SYS_StopTimer(void)
   10.93 -{
   10.94 -    TIMER_CR(3) &= ~TIMER_ENABLE;
   10.95 -    return;
   10.96 -}
   10.97 -
   10.98 -
   10.99 -#endif /* SDL_TIMER_NDS */
  10.100  /* vi: set ts=4 sw=4 expandtab: */
    11.1 --- a/src/timer/unix/SDL_systimer.c	Thu Jan 27 10:40:17 2011 -0800
    11.2 +++ b/src/timer/unix/SDL_systimer.c	Thu Jan 27 14:45:06 2011 -0800
    11.3 @@ -25,14 +25,10 @@
    11.4  
    11.5  #include <stdio.h>
    11.6  #include <sys/time.h>
    11.7 -#include <signal.h>
    11.8  #include <unistd.h>
    11.9 -#include <string.h>
   11.10  #include <errno.h>
   11.11  
   11.12  #include "SDL_timer.h"
   11.13 -#include "../SDL_systimer.h"
   11.14 -#include "../SDL_timer_c.h"
   11.15  
   11.16  /* The clock_gettime provides monotonous time, so we should use it if
   11.17     it's available. The clock_gettime function is behind ifdef
   11.18 @@ -43,10 +39,6 @@
   11.19  #include <time.h>
   11.20  #endif
   11.21  
   11.22 -#if SDL_THREADS_DISABLED
   11.23 -#define USE_ITIMER
   11.24 -#endif
   11.25 -
   11.26  /* The first ticks value of the application */
   11.27  #ifdef HAVE_CLOCK_GETTIME
   11.28  static struct timespec start;
   11.29 @@ -131,118 +123,6 @@
   11.30      } while (was_error && (errno == EINTR));
   11.31  }
   11.32  
   11.33 -#ifdef USE_ITIMER
   11.34 +#endif /* SDL_TIMER_UNIX */
   11.35  
   11.36 -static void
   11.37 -HandleAlarm(int sig)
   11.38 -{
   11.39 -    Uint32 ms;
   11.40 -
   11.41 -    if (SDL_alarm_callback) {
   11.42 -        ms = (*SDL_alarm_callback) (SDL_alarm_interval);
   11.43 -        if (ms != SDL_alarm_interval) {
   11.44 -            SDL_SetTimer(ms, SDL_alarm_callback);
   11.45 -        }
   11.46 -    }
   11.47 -}
   11.48 -
   11.49 -int
   11.50 -SDL_SYS_TimerInit(void)
   11.51 -{
   11.52 -    struct sigaction action;
   11.53 -
   11.54 -    /* Set the alarm handler (Linux specific) */
   11.55 -    SDL_memset(&action, 0, sizeof(action));
   11.56 -    action.sa_handler = HandleAlarm;
   11.57 -    action.sa_flags = SA_RESTART;
   11.58 -    sigemptyset(&action.sa_mask);
   11.59 -    sigaction(SIGALRM, &action, NULL);
   11.60 -    return (0);
   11.61 -}
   11.62 -
   11.63 -void
   11.64 -SDL_SYS_TimerQuit(void)
   11.65 -{
   11.66 -    SDL_SetTimer(0, NULL);
   11.67 -}
   11.68 -
   11.69 -int
   11.70 -SDL_SYS_StartTimer(void)
   11.71 -{
   11.72 -    struct itimerval timer;
   11.73 -
   11.74 -    timer.it_value.tv_sec = (SDL_alarm_interval / 1000);
   11.75 -    timer.it_value.tv_usec = (SDL_alarm_interval % 1000) * 1000;
   11.76 -    timer.it_interval.tv_sec = (SDL_alarm_interval / 1000);
   11.77 -    timer.it_interval.tv_usec = (SDL_alarm_interval % 1000) * 1000;
   11.78 -    setitimer(ITIMER_REAL, &timer, NULL);
   11.79 -    return (0);
   11.80 -}
   11.81 -
   11.82 -void
   11.83 -SDL_SYS_StopTimer(void)
   11.84 -{
   11.85 -    struct itimerval timer;
   11.86 -
   11.87 -    SDL_memset(&timer, 0, (sizeof timer));
   11.88 -    setitimer(ITIMER_REAL, &timer, NULL);
   11.89 -}
   11.90 -
   11.91 -#else /* USE_ITIMER */
   11.92 -
   11.93 -#include "SDL_thread.h"
   11.94 -
   11.95 -/* Data to handle a single periodic alarm */
   11.96 -static int timer_alive = 0;
   11.97 -static SDL_Thread *timer = NULL;
   11.98 -
   11.99 -static int
  11.100 -RunTimer(void *unused)
  11.101 -{
  11.102 -    while (timer_alive) {
  11.103 -        if (SDL_timer_running) {
  11.104 -            SDL_ThreadedTimerCheck();
  11.105 -        }
  11.106 -        SDL_Delay(1);
  11.107 -    }
  11.108 -    return (0);
  11.109 -}
  11.110 -
  11.111 -/* This is only called if the event thread is not running */
  11.112 -int
  11.113 -SDL_SYS_TimerInit(void)
  11.114 -{
  11.115 -    timer_alive = 1;
  11.116 -    timer = SDL_CreateThread(RunTimer, NULL);
  11.117 -    if (timer == NULL)
  11.118 -        return (-1);
  11.119 -    return (SDL_SetTimerThreaded(1));
  11.120 -}
  11.121 -
  11.122 -void
  11.123 -SDL_SYS_TimerQuit(void)
  11.124 -{
  11.125 -    timer_alive = 0;
  11.126 -    if (timer) {
  11.127 -        SDL_WaitThread(timer, NULL);
  11.128 -        timer = NULL;
  11.129 -    }
  11.130 -}
  11.131 -
  11.132 -int
  11.133 -SDL_SYS_StartTimer(void)
  11.134 -{
  11.135 -    SDL_SetError("Internal logic error: Linux uses threaded timer");
  11.136 -    return (-1);
  11.137 -}
  11.138 -
  11.139 -void
  11.140 -SDL_SYS_StopTimer(void)
  11.141 -{
  11.142 -    return;
  11.143 -}
  11.144 -
  11.145 -#endif /* USE_ITIMER */
  11.146 -
  11.147 -#endif /* SDL_TIMER_UNIX */
  11.148  /* vi: set ts=4 sw=4 expandtab: */
    12.1 --- a/src/timer/wince/SDL_systimer.c	Thu Jan 27 10:40:17 2011 -0800
    12.2 +++ b/src/timer/wince/SDL_systimer.c	Thu Jan 27 14:45:06 2011 -0800
    12.3 @@ -24,11 +24,8 @@
    12.4  #ifdef SDL_TIMER_WINCE
    12.5  
    12.6  #include "../../core/windows/SDL_windows.h"
    12.7 -#include <mmsystem.h>
    12.8  
    12.9 -#include "SDL_thread.h"
   12.10  #include "SDL_timer.h"
   12.11 -#include "../SDL_timer_c.h"
   12.12  
   12.13  static Uint64 start_date;
   12.14  static Uint64 start_ticks;
   12.15 @@ -69,6 +66,14 @@
   12.16      return ((Sint32) (wce_date() - start_date));
   12.17  }
   12.18  
   12.19 +/* Recard start-time of application for reference */
   12.20 +void
   12.21 +SDL_StartTicks(void)
   12.22 +{
   12.23 +    start_date = wce_date();
   12.24 +    start_ticks = wce_ticks();
   12.25 +}
   12.26 +
   12.27  /* Return time in ms relative to when SDL was started */
   12.28  Uint32
   12.29  SDL_GetTicks()
   12.30 @@ -89,122 +94,6 @@
   12.31      Sleep(ms);
   12.32  }
   12.33  
   12.34 -/* Recard start-time of application for reference */
   12.35 -void
   12.36 -SDL_StartTicks(void)
   12.37 -{
   12.38 -    start_date = wce_date();
   12.39 -    start_ticks = wce_ticks();
   12.40 -}
   12.41 +#endif /* SDL_TIMER_WINCE */
   12.42  
   12.43 -static UINT WIN_timer;
   12.44 -
   12.45 -#if ( _WIN32_WCE <= 420 )
   12.46 -
   12.47 -static HANDLE timersThread = 0;
   12.48 -static HANDLE timersQuitEvent = 0;
   12.49 -
   12.50 -DWORD
   12.51 -TimersThreadProc(void *data)
   12.52 -{
   12.53 -    while (WaitForSingleObject(timersQuitEvent, 10) == WAIT_TIMEOUT) {
   12.54 -        SDL_ThreadedTimerCheck();
   12.55 -    }
   12.56 -    return 0;
   12.57 -}
   12.58 -
   12.59 -int
   12.60 -SDL_SYS_TimerInit(void)
   12.61 -{
   12.62 -    // create a thread to process a threaded timers
   12.63 -    // SetTimer does not suit the needs because 
   12.64 -    // TimerCallbackProc will be called only when WM_TIMER occured
   12.65 -
   12.66 -    timersQuitEvent = CreateEvent(0, TRUE, FALSE, 0);
   12.67 -    if (!timersQuitEvent) {
   12.68 -        SDL_SetError("Cannot create event for timers thread");
   12.69 -        return -1;
   12.70 -    }
   12.71 -    timersThread = CreateThread(NULL, 0, TimersThreadProc, 0, 0, 0);
   12.72 -    if (!timersThread) {
   12.73 -        SDL_SetError
   12.74 -            ("Cannot create timers thread, check amount of RAM available");
   12.75 -        return -1;
   12.76 -    }
   12.77 -    SetThreadPriority(timersThread, THREAD_PRIORITY_HIGHEST);
   12.78 -
   12.79 -    return (SDL_SetTimerThreaded(1));
   12.80 -}
   12.81 -
   12.82 -void
   12.83 -SDL_SYS_TimerQuit(void)
   12.84 -{
   12.85 -    SetEvent(timersQuitEvent);
   12.86 -    if (WaitForSingleObject(timersThread, 2000) == WAIT_TIMEOUT)
   12.87 -        TerminateThread(timersThread, 0);
   12.88 -    CloseHandle(timersThread);
   12.89 -    CloseHandle(timersQuitEvent);
   12.90 -    return;
   12.91 -}
   12.92 -
   12.93 -#else
   12.94 -
   12.95 -#pragma comment(lib, "mmtimer.lib")
   12.96 -
   12.97 -/* Data to handle a single periodic alarm */
   12.98 -static UINT timerID = 0;
   12.99 -
  12.100 -static void CALLBACK
  12.101 -HandleAlarm(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
  12.102 -{
  12.103 -    SDL_ThreadedTimerCheck();
  12.104 -}
  12.105 -
  12.106 -
  12.107 -int
  12.108 -SDL_SYS_TimerInit(void)
  12.109 -{
  12.110 -    MMRESULT result;
  12.111 -
  12.112 -    /* Set timer resolution */
  12.113 -    result = timeBeginPeriod(TIMER_RESOLUTION);
  12.114 -    if (result != TIMERR_NOERROR) {
  12.115 -        SDL_SetError("Warning: Can't set %d ms timer resolution",
  12.116 -                     TIMER_RESOLUTION);
  12.117 -    }
  12.118 -    /* Allow 10 ms of drift so we don't chew on CPU */
  12.119 -    timerID =
  12.120 -        timeSetEvent(TIMER_RESOLUTION, 1, HandleAlarm, 0, TIME_PERIODIC);
  12.121 -    if (!timerID) {
  12.122 -        SDL_SetError("timeSetEvent() failed");
  12.123 -        return (-1);
  12.124 -    }
  12.125 -    return (SDL_SetTimerThreaded(1));
  12.126 -}
  12.127 -
  12.128 -void
  12.129 -SDL_SYS_TimerQuit(void)
  12.130 -{
  12.131 -    if (timerID) {
  12.132 -        timeKillEvent(timerID);
  12.133 -    }
  12.134 -    timeEndPeriod(TIMER_RESOLUTION);
  12.135 -}
  12.136 -
  12.137 -#endif
  12.138 -
  12.139 -int
  12.140 -SDL_SYS_StartTimer(void)
  12.141 -{
  12.142 -    SDL_SetError("Internal logic error: WinCE uses threaded timer");
  12.143 -    return (-1);
  12.144 -}
  12.145 -
  12.146 -void
  12.147 -SDL_SYS_StopTimer(void)
  12.148 -{
  12.149 -    return;
  12.150 -}
  12.151 -
  12.152 -#endif /* SDL_TIMER_WINCE */
  12.153  /* vi: set ts=4 sw=4 expandtab: */
    13.1 --- a/src/timer/windows/SDL_systimer.c	Thu Jan 27 10:40:17 2011 -0800
    13.2 +++ b/src/timer/windows/SDL_systimer.c	Thu Jan 27 14:45:06 2011 -0800
    13.3 @@ -24,10 +24,8 @@
    13.4  #ifdef SDL_TIMER_WINDOWS
    13.5  
    13.6  #include "../../core/windows/SDL_windows.h"
    13.7 -#include <mmsystem.h>
    13.8  
    13.9  #include "SDL_timer.h"
   13.10 -#include "../SDL_timer_c.h"
   13.11  
   13.12  #ifdef _WIN32_WCE
   13.13  #error This is WinCE. Please use src/timer/wince/SDL_systimer.c instead.
   13.14 @@ -106,60 +104,6 @@
   13.15      Sleep(ms);
   13.16  }
   13.17  
   13.18 -/* Data to handle a single periodic alarm */
   13.19 -static UINT timerID = 0;
   13.20 -
   13.21 -static void CALLBACK
   13.22 -HandleAlarm(UINT uID, UINT uMsg, DWORD_PTR dwUser,
   13.23 -            DWORD_PTR dw1, DWORD_PTR dw2)
   13.24 -{
   13.25 -    SDL_ThreadedTimerCheck();
   13.26 -}
   13.27 -
   13.28 -
   13.29 -int
   13.30 -SDL_SYS_TimerInit(void)
   13.31 -{
   13.32 -    MMRESULT result;
   13.33 -
   13.34 -    /* Set timer resolution */
   13.35 -    result = timeBeginPeriod(TIMER_RESOLUTION);
   13.36 -    if (result != TIMERR_NOERROR) {
   13.37 -        SDL_SetError("Warning: Can't set %d ms timer resolution",
   13.38 -                     TIMER_RESOLUTION);
   13.39 -    }
   13.40 -    /* Allow 10 ms of drift so we don't chew on CPU */
   13.41 -    timerID =
   13.42 -        timeSetEvent(TIMER_RESOLUTION, 1, HandleAlarm, 0, TIME_PERIODIC);
   13.43 -    if (!timerID) {
   13.44 -        SDL_SetError("timeSetEvent() failed");
   13.45 -        return (-1);
   13.46 -    }
   13.47 -    return (SDL_SetTimerThreaded(1));
   13.48 -}
   13.49 -
   13.50 -void
   13.51 -SDL_SYS_TimerQuit(void)
   13.52 -{
   13.53 -    if (timerID) {
   13.54 -        timeKillEvent(timerID);
   13.55 -    }
   13.56 -    timeEndPeriod(TIMER_RESOLUTION);
   13.57 -}
   13.58 -
   13.59 -int
   13.60 -SDL_SYS_StartTimer(void)
   13.61 -{
   13.62 -    SDL_SetError("Internal logic error: Win32 uses threaded timer");
   13.63 -    return (-1);
   13.64 -}
   13.65 -
   13.66 -void
   13.67 -SDL_SYS_StopTimer(void)
   13.68 -{
   13.69 -    return;
   13.70 -}
   13.71 -
   13.72  #endif /* SDL_TIMER_WINDOWS */
   13.73  
   13.74  /* vi: set ts=4 sw=4 expandtab: */