From: Mathias Agopian Date: Mon, 5 Dec 2011 22:33:34 +0000 (-0800) Subject: fix a deadlock when removing a DisplayEventConnection X-Git-Tag: android-x86-4.4-r1~1471^2~340^2 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=23748668d33ac850e64d87e25ac4cc78679c9384;p=android-x86%2Fframeworks-native.git 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 --- diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp index edb06ba21a..42477a9170 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& 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 > 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 conn(mDisplayEventConnections.itemAt(i).promote()); + sp 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; } diff --git a/services/surfaceflinger/EventThread.h b/services/surfaceflinger/EventThread.h index 0482ab7528..4872c2b823 100644 --- a/services/surfaceflinger/EventThread.h +++ b/services/surfaceflinger/EventThread.h @@ -58,6 +58,9 @@ private: virtual status_t readyToRun(); virtual void onFirstRef(); + status_t removeDisplayEventConnection( + const wp& connection); + // constants sp mFlinger; const DisplayHardware& mHw;