changeset 5074:906d7293bb47

Fixed bug in timer when the list of timers changed. Fix contributed by Michael Bicha
author Sam Lantinga <slouken@libsdl.org>
date Sat, 22 Jan 2011 00:33:37 -0800
parents 1e94e68525d5
children 8bf5781fc582
files src/timer/SDL_timer.c
diffstat 1 files changed, 51 insertions(+), 40 deletions(-) [+]
line wrap: on
line diff
--- a/src/timer/SDL_timer.c	Fri Jan 21 23:46:51 2011 -0800
+++ b/src/timer/SDL_timer.c	Sat Jan 22 00:33:37 2011 -0800
@@ -113,56 +113,67 @@
     SDL_bool removed;
 
     SDL_mutexP(SDL_timer_mutex);
-    list_changed = SDL_FALSE;
+
     now = SDL_GetTicks();
-    for (prev = NULL, t = SDL_timers; t; t = next) {
-        removed = SDL_FALSE;
-        ms = t->interval - SDL_TIMESLICE;
-        next = t->next;
-        if ((int) (now - t->last_alarm) > (int) ms) {
-            struct _SDL_TimerID timer;
+    do {
+        list_changed = SDL_FALSE;
+        for (prev = NULL, t = SDL_timers; t; t = next) {
+            removed = SDL_FALSE;
+            ms = t->interval - SDL_TIMESLICE;
+            next = t->next;
+            if ((int) (now - t->last_alarm) > (int) ms) {
+                struct _SDL_TimerID timer;
 
-            if ((now - t->last_alarm) < t->interval) {
-                t->last_alarm += t->interval;
-            } else {
-                t->last_alarm = now;
-            }
+                if ((now - t->last_alarm) < t->interval) {
+                    t->last_alarm += t->interval;
+                } else {
+                    t->last_alarm = now;
+                }
 #ifdef DEBUG_TIMERS
-            printf("Executing timer %p (thread = %lu)\n", t, SDL_ThreadID());
+                printf("Executing timer %p (thread = %lu)\n",
+                       t, SDL_ThreadID());
 #endif
-            timer = *t;
-            SDL_mutexV(SDL_timer_mutex);
-            ms = timer.cb(timer.interval, timer.param);
-            SDL_mutexP(SDL_timer_mutex);
-            if (list_changed) {
-                /* Abort, list of timers modified */
-                /* FIXME: what if ms was changed? */
-                break;
-            }
-            if (ms != t->interval) {
-                if (ms) {
-                    t->interval = ROUND_RESOLUTION(ms);
-                } else {
-                    /* Remove timer from the list */
+                timer = *t;
+                SDL_mutexV(SDL_timer_mutex);
+                ms = timer.cb(timer.interval, timer.param);
+                SDL_mutexP(SDL_timer_mutex);
+                if (list_changed) {
+                    next = t->next;
+                    for (prev = SDL_timers; prev; prev = prev->next) {
+                        if (prev->next == t)
+                            break;
+                    }
+                }
+                if (ms != t->interval) {
+                    if (ms) {
+                        t->interval = ROUND_RESOLUTION(ms);
+                    } else {
+                        /* Remove timer from the list */
 #ifdef DEBUG_TIMERS
-                    printf("SDL: Removing timer %p\n", t);
+                        printf("SDL: Removing timer %p\n", t);
 #endif
-                    if (prev) {
-                        prev->next = next;
-                    } else {
-                        SDL_timers = next;
+                        if (prev) {
+                            prev->next = next;
+                        } else {
+                            SDL_timers = next;
+                        }
+                        SDL_free(t);
+                        --SDL_timer_running;
+                        removed = SDL_TRUE;
                     }
-                    SDL_free(t);
-                    --SDL_timer_running;
-                    removed = SDL_TRUE;
+                }
+                if (list_changed) {
+                    /* Abort, list of timers modified */
+                    break;
                 }
             }
+            /* Don't update prev if the timer has disappeared */
+            if (!removed) {
+                prev = t;
+            }
         }
-        /* Don't update prev if the timer has disappeared */
-        if (!removed) {
-            prev = t;
-        }
-    }
+    } while (list_changed);
+
     SDL_mutexV(SDL_timer_mutex);
 }