summaryrefslogtreecommitdiffstats
path: root/services/surfaceflinger/EventThread.cpp
diff options
context:
space:
mode:
authorMathias Agopian <mathias@google.com>2011-12-05 14:33:34 -0800
committerMathias Agopian <mathias@google.com>2011-12-05 19:58:47 -0800
commit23748668d33ac850e64d87e25ac4cc78679c9384 (patch)
treea4f7155e7d0e10895947a985fd9e447a72f9a5a0 /services/surfaceflinger/EventThread.cpp
parent2892cb045d88a75b6cd8b0d6b0d71b4b68c00f52 (diff)
downloadframeworks_native-23748668d33ac850e64d87e25ac4cc78679c9384.zip
frameworks_native-23748668d33ac850e64d87e25ac4cc78679c9384.tar.gz
frameworks_native-23748668d33ac850e64d87e25ac4cc78679c9384.tar.bz2
fix a deadlock when removing a DisplayEventConnection
the deadlock would happen when the pipe became invalid and SF trying to remove the connection from its list. we know make sure to process events without holding a lock. Change-Id: I39927ed8824fc7811e16db3c7608a2ebc72d9642
Diffstat (limited to 'services/surfaceflinger/EventThread.cpp')
-rw-r--r--services/surfaceflinger/EventThread.cpp64
1 files changed, 43 insertions, 21 deletions
diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp
index edb06ba..42477a9 100644
--- a/services/surfaceflinger/EventThread.cpp
+++ b/services/surfaceflinger/EventThread.cpp
@@ -60,36 +60,51 @@ status_t EventThread::unregisterDisplayEventConnection(
return NO_ERROR;
}
+status_t EventThread::removeDisplayEventConnection(
+ const wp<DisplayEventConnection>& connection) {
+ Mutex::Autolock _l(mLock);
+ mDisplayEventConnections.remove(connection);
+ return NO_ERROR;
+}
+
bool EventThread::threadLoop() {
nsecs_t timestamp;
- Mutex::Autolock _l(mLock);
- do {
- // wait for listeners
- while (!mDisplayEventConnections.size()) {
- mCondition.wait(mLock);
- }
+ DisplayEventReceiver::Event vsync;
+ SortedVector<wp<DisplayEventConnection> > displayEventConnections;
+
+ { // scope for the lock
+ Mutex::Autolock _l(mLock);
+ do {
+ // wait for listeners
+ while (!mDisplayEventConnections.size()) {
+ mCondition.wait(mLock);
+ }
- // wait for vsync
- mLock.unlock();
- timestamp = mHw.waitForVSync();
- mLock.lock();
+ // wait for vsync
+ mLock.unlock();
+ timestamp = mHw.waitForVSync();
+ mLock.lock();
- // make sure we still have some listeners
- } while (!mDisplayEventConnections.size());
+ // make sure we still have some listeners
+ } while (!mDisplayEventConnections.size());
- // dispatch vsync events to listeners...
- mDeliveredEvents++;
- const size_t count = mDisplayEventConnections.size();
+ // dispatch vsync events to listeners...
+ mDeliveredEvents++;
- DisplayEventReceiver::Event vsync;
- vsync.header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
- vsync.header.timestamp = timestamp;
- vsync.vsync.count = mDeliveredEvents;
+ vsync.header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
+ vsync.header.timestamp = timestamp;
+ vsync.vsync.count = mDeliveredEvents;
+ // make a copy of our connection list, so we can
+ // dispatch events without holding mLock
+ displayEventConnections = mDisplayEventConnections;
+ }
+
+ const size_t count = displayEventConnections.size();
for (size_t i=0 ; i<count ; i++) {
- sp<DisplayEventConnection> conn(mDisplayEventConnections.itemAt(i).promote());
+ sp<DisplayEventConnection> conn(displayEventConnections.itemAt(i).promote());
// make sure the connection didn't die
if (conn != NULL) {
status_t err = conn->postEvent(vsync);
@@ -103,11 +118,18 @@ bool EventThread::threadLoop() {
// handle any other error on the pipe as fatal. the only
// reasonable thing to do is to clean-up this connection.
// The most common error we'll get here is -EPIPE.
- mDisplayEventConnections.remove(conn);
+ removeDisplayEventConnection(displayEventConnections.itemAt(i));
}
+ } else {
+ // somehow the connection is dead, but we still have it in our list
+ // just clean the list.
+ removeDisplayEventConnection(displayEventConnections.itemAt(i));
}
}
+ // clear all our references without holding mLock
+ displayEventConnections.clear();
+
return true;
}