| 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 |
| |