From fe4c774c572e3f55a7417f0ca336ae1479a966ad Mon Sep 17 00:00:00 2001 From: Nikhil Mahale Date: Sat, 24 Jan 2015 17:06:59 -0800 Subject: [PATCH] os: Fix timer race conditions Fixing following kind of race-conditions - WaitForSomething() | ----> // timers -> timer-1 -> timer-2 -> null while (timers && (int) (timers->expires - now) <= 0) // prototype - DoTimer(OsTimerPtr timer, CARD32 now, OsTimerPtr *prev) DoTimer(timers, now, &timers) | | ----> OsBlockSignals(); .... OS Signal comes just before blocking it, .... timer-1 handler gets called. // timer-1 gets served and scheduled again; // timers -> timer-2 -> timer-1 -> null .... *prev = timer->next; timer->next = NULL; // timers -> null // timers list gets corrupted here and timer-2 gets removed from list. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=86288 Signed-off-by: Nikhil Mahale Reviewed-by: Julien Cristau v2: Apply warning fixes from Keith Packard Reviewed-by: Aaron Plattner Signed-off-by: Aaron Plattner Signed-off-by: Keith Packard --- os/WaitFor.c | 41 ++++++++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/os/WaitFor.c b/os/WaitFor.c index 86d96c846..431f1a6b6 100644 --- a/os/WaitFor.c +++ b/os/WaitFor.c @@ -121,9 +121,9 @@ struct _OsTimerRec { void *arg; }; -static void DoTimer(OsTimerPtr timer, CARD32 now, OsTimerPtr *prev); +static void DoTimer(OsTimerPtr timer, CARD32 now, volatile OsTimerPtr *prev); static void CheckAllTimers(void); -static OsTimerPtr timers = NULL; +static volatile OsTimerPtr timers = NULL; /***************** * WaitForSomething: @@ -263,11 +263,14 @@ WaitForSomething(int *pClientsReady) if ((int) (timers->expires - now) <= 0) expired = 1; - while (timers && (int) (timers->expires - now) <= 0) - DoTimer(timers, now, &timers); + if (expired) { + OsBlockSignals(); + while (timers && (int) (timers->expires - now) <= 0) + DoTimer(timers, now, &timers); + OsReleaseSignals(); - if (expired) return 0; + } } } else { @@ -281,11 +284,14 @@ WaitForSomething(int *pClientsReady) if ((int) (timers->expires - now) <= 0) expired = 1; - while (timers && (int) (timers->expires - now) <= 0) - DoTimer(timers, now, &timers); + if (expired) { + OsBlockSignals(); + while (timers && (int) (timers->expires - now) <= 0) + DoTimer(timers, now, &timers); + OsReleaseSignals(); - if (expired) return 0; + } } } if (someReady) @@ -401,24 +407,25 @@ CheckAllTimers(void) } static void -DoTimer(OsTimerPtr timer, CARD32 now, OsTimerPtr *prev) +DoTimer(OsTimerPtr timer, CARD32 now, volatile OsTimerPtr *prev) { CARD32 newTime; OsBlockSignals(); *prev = timer->next; timer->next = NULL; + OsReleaseSignals(); + newTime = (*timer->callback) (timer, now, timer->arg); if (newTime) TimerSet(timer, 0, newTime, timer->callback, timer->arg); - OsReleaseSignals(); } OsTimerPtr TimerSet(OsTimerPtr timer, int flags, CARD32 millis, OsTimerCallback func, void *arg) { - register OsTimerPtr *prev; + volatile OsTimerPtr *prev; CARD32 now = GetTimeInMillis(); if (!timer) { @@ -470,7 +477,7 @@ Bool TimerForce(OsTimerPtr timer) { int rc = FALSE; - OsTimerPtr *prev; + volatile OsTimerPtr *prev; OsBlockSignals(); for (prev = &timers; *prev; prev = &(*prev)->next) { @@ -487,7 +494,7 @@ TimerForce(OsTimerPtr timer) void TimerCancel(OsTimerPtr timer) { - OsTimerPtr *prev; + volatile OsTimerPtr *prev; if (!timer) return; @@ -515,8 +522,12 @@ TimerCheck(void) { CARD32 now = GetTimeInMillis(); - while (timers && (int) (timers->expires - now) <= 0) - DoTimer(timers, now, &timers); + if (timers && (int) (timers->expires - now) <= 0) { + OsBlockSignals(); + while (timers && (int) (timers->expires - now) <= 0) + DoTimer(timers, now, &timers); + OsReleaseSignals(); + } } void