Fix a race condition in TimedEventQueue, an event may be cancelled while we're waiting for its scheduled time to come in which case we'd be removing it from the queue twice.

Change-Id: I4e42e318fd5373d1f352f54027d4bf823126266d
related-to-bug: 2585276
This commit is contained in:
Andreas Huber
2010-04-12 13:10:20 -07:00
parent 36acfbc2b8
commit ea1d6712fe
2 changed files with 38 additions and 11 deletions

View File

@@ -19,6 +19,7 @@
#define __STDC_LIMIT_MACROS
#include <stdint.h>
//#define LOG_NDEBUG 0
#define LOG_TAG "TimedEventQueue"
#include <utils/Log.h>
@@ -169,6 +170,8 @@ void TimedEventQueue::cancelEvents(
mQueueHeadChangedCondition.signal();
}
LOGV("cancelling event %d", (*it).event->eventID());
(*it).event->setEventID(0);
it = mQueue.erase(it);
@@ -229,14 +232,16 @@ void TimedEventQueue::threadEntry() {
mQueueNotEmptyCondition.wait(mLock);
}
List<QueueItem>::iterator it;
event_id eventID = 0;
for (;;) {
if (mQueue.empty()) {
// The only event in the queue could have been cancelled
// while we were waiting for its scheduled time.
break;
}
it = mQueue.begin();
List<QueueItem>::iterator it = mQueue.begin();
eventID = (*it).event->eventID();
now_us = getRealTimeUs();
int64_t when_us = (*it).realtime_us;
@@ -276,19 +281,39 @@ void TimedEventQueue::threadEntry() {
}
}
if (mQueue.empty()) {
continue;
}
event = (*it).event;
event->setEventID(0);
mQueue.erase(it);
// The event w/ this id may have been cancelled while we're
// waiting for its trigger-time, in that case
// removeEventFromQueue_l will return NULL.
// Otherwise, the QueueItem will be removed
// from the queue and the referenced event returned.
event = removeEventFromQueue_l(eventID);
}
// Fire event with the lock NOT held.
event->fire(this, now_us);
if (event != NULL) {
// Fire event with the lock NOT held.
event->fire(this, now_us);
}
}
}
sp<TimedEventQueue::Event> TimedEventQueue::removeEventFromQueue_l(
event_id id) {
for (List<QueueItem>::iterator it = mQueue.begin();
it != mQueue.end(); ++it) {
if ((*it).event->eventID() == id) {
sp<Event> event = (*it).event;
event->setEventID(0);
mQueue.erase(it);
return event;
}
}
LOGW("Event %d was not found in the queue, already cancelled?", id);
return NULL;
}
} // namespace android

View File

@@ -121,6 +121,8 @@ private:
static void *ThreadWrapper(void *me);
void threadEntry();
sp<Event> removeEventFromQueue_l(event_id id);
TimedEventQueue(const TimedEventQueue &);
TimedEventQueue &operator=(const TimedEventQueue &);
};