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:
@@ -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
|
||||
|
||||
|
||||
@@ -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 &);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user