blob: 9f04b259cc4993d087379d8002a45df9245da28e [file] [log] [blame]
From: Daniel Kurtz <djkurtz@chromium.org>
Date: Sat, 22 Sep 2012 19:58:22 +0800
Subject: [PATCH] os: block signals when accessing global timer list
X Input drivers, such as xf86-input-synaptics, tend to do all of their
processing in a SIGIO signal handler. This processing often involves
creating, modifying or canceling a timer. Any of these operations may
modify the global "timers" array. Therefore, all accesses of this global
must be done in critical sections during which signals are blocked.
Otherwise, for example, a signal may clear the last timer between, which
sets timers global to NULL, between the NULL check and checking "expires",
which causes a SEGV.
A previous patch protected write accesses. However, this is not
sufficient. ead accesses must also be made atomic such that a signal
cannot occur between the timers pointer NULL check and a subsequent
dereference.
This change actually makes the Signal blocking in DoTimer() and
CheckAllTimers() redundant, since they are always called with signals
already blocked.
Also, make the global volatile to ensure that the compiler does not
cache its value.
Signed-off-by: Daniel Kurtz <djkurtz@chromium.org>
---
os/WaitFor.c | 27 +++++++++++++++++++--------
1 files changed, 19 insertions(+), 8 deletions(-)
diff --git a/os/WaitFor.c b/os/WaitFor.c
index 852362e..f105acc 100644
--- a/os/WaitFor.c
+++ b/os/WaitFor.c
@@ -122,7 +122,7 @@ struct _OsTimerRec {
static void DoTimer(OsTimerPtr timer, CARD32 now, OsTimerPtr *prev);
static void CheckAllTimers(void);
-static OsTimerPtr timers = NULL;
+volatile static OsTimerPtr timers = NULL;
/*****************
* WaitForSomething:
@@ -186,6 +186,7 @@ WaitForSomething(int *pClientsReady)
}
else {
wt = NULL;
+ OsBlockSignals();
if (timers) {
now = GetTimeInMillis();
timeout = timers->expires - now;
@@ -204,6 +205,7 @@ WaitForSomething(int *pClientsReady)
wt = &waittime;
}
}
+ OsReleaseSignals();
XFD_COPYSET(&AllSockets, &LastSelectMask);
}
@@ -251,6 +253,7 @@ WaitForSomething(int *pClientsReady)
if (*checkForInput[0] != *checkForInput[1])
return 0;
+ OsBlockSignals();
if (timers) {
int expired = 0;
@@ -261,14 +264,18 @@ WaitForSomething(int *pClientsReady)
while (timers && (int) (timers->expires - now) <= 0)
DoTimer(timers, now, &timers);
- if (expired)
+ if (expired) {
+ OsReleaseSignals();
return 0;
+ }
}
+ OsReleaseSignals();
}
else {
fd_set tmp_set;
if (*checkForInput[0] == *checkForInput[1]) {
+ OsBlockSignals();
if (timers) {
int expired = 0;
@@ -279,9 +286,12 @@ WaitForSomething(int *pClientsReady)
while (timers && (int) (timers->expires - now) <= 0)
DoTimer(timers, now, &timers);
- if (expired)
+ if (expired) {
+ OsReleaseSignals();
return 0;
+ }
}
+ OsReleaseSignals();
}
if (someReady)
XFD_ORSET(&LastSelectMask, &ClientsWithInput, &LastSelectMask);
@@ -382,7 +392,6 @@ CheckAllTimers(void)
OsTimerPtr timer;
CARD32 now;
- OsBlockSignals();
start:
now = GetTimeInMillis();
@@ -392,7 +401,6 @@ CheckAllTimers(void)
goto start;
}
}
- OsReleaseSignals();
}
static void
@@ -400,13 +408,11 @@ DoTimer(OsTimerPtr timer, CARD32 now, OsTimerPtr *prev)
{
CARD32 newTime;
- OsBlockSignals();
*prev = timer->next;
timer->next = NULL;
newTime = (*timer->callback) (timer, now, timer->arg);
if (newTime)
TimerSet(timer, 0, newTime, timer->callback, timer->arg);
- OsReleaseSignals();
}
OsTimerPtr
@@ -508,10 +514,13 @@ TimerFree(OsTimerPtr timer)
void
TimerCheck(void)
{
- CARD32 now = GetTimeInMillis();
+ CARD32 now;
+ OsBlockSignals();
+ now = GetTimeInMillis();
while (timers && (int) (timers->expires - now) <= 0)
DoTimer(timers, now, &timers);
+ OsReleaseSignals();
}
void
@@ -519,10 +528,12 @@ TimerInit(void)
{
OsTimerPtr timer;
+ OsBlockSignals();
while ((timer = timers)) {
timers = timer->next;
free(timer);
}
+ OsReleaseSignals();
}
#ifdef DPMSExtension
--
1.7.7.3