summaryrefslogtreecommitdiffstats
path: root/libs
diff options
context:
space:
mode:
authorMathias Agopian <mathias@google.com>2013-07-23 21:50:20 -0700
committerMathias Agopian <mathias@google.com>2013-07-23 21:55:32 -0700
commit6bac363cbdca7f5c4135d66c0e379475ecbd7319 (patch)
tree4d03542e3fb573b092b3ba2585ba9d0ea06da573 /libs
parent7ffaa7c60d51cc0eb731158de2ac3df9c50cc0b4 (diff)
downloadframeworks_native-6bac363cbdca7f5c4135d66c0e379475ecbd7319.zip
frameworks_native-6bac363cbdca7f5c4135d66c0e379475ecbd7319.tar.gz
frameworks_native-6bac363cbdca7f5c4135d66c0e379475ecbd7319.tar.bz2
Fix a race in BufferQueue
BufferQueue::dequeueBuffer() could incorrectly return WOULD_BLOCK while in "cannot block" mode if it happened while a consumer acquired the last allowed buffer before releasing the old one (which is a valid thing to do). Change-Id: I318e5408871ba85e068ea9ef4dc9b578f1bb1043
Diffstat (limited to 'libs')
-rw-r--r--libs/gui/BufferQueue.cpp44
1 files changed, 27 insertions, 17 deletions
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index 73bd488..320f4cf 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -268,7 +268,6 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>* outFence, bool async
usage |= mConsumerUsageBits;
int found = -1;
- int dequeuedCount = 0;
bool tryAgain = true;
while (tryAgain) {
if (mAbandoned) {
@@ -299,23 +298,28 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>* outFence, bool async
// look for a free buffer to give to the client
found = INVALID_BUFFER_SLOT;
- dequeuedCount = 0;
+ int dequeuedCount = 0;
+ int acquiredCount = 0;
for (int i = 0; i < maxBufferCount; i++) {
const int state = mSlots[i].mBufferState;
- if (state == BufferSlot::DEQUEUED) {
- dequeuedCount++;
- }
-
- if (state == BufferSlot::FREE) {
- /* We return the oldest of the free buffers to avoid
- * stalling the producer if possible. This is because
- * the consumer may still have pending reads of the
- * buffers in flight.
- */
- if ((found < 0) ||
- mSlots[i].mFrameNumber < mSlots[found].mFrameNumber) {
- found = i;
- }
+ switch (state) {
+ case BufferSlot::DEQUEUED:
+ dequeuedCount++;
+ break;
+ case BufferSlot::ACQUIRED:
+ acquiredCount++;
+ break;
+ case BufferSlot::FREE:
+ /* We return the oldest of the free buffers to avoid
+ * stalling the producer if possible. This is because
+ * the consumer may still have pending reads of the
+ * buffers in flight.
+ */
+ if ((found < 0) ||
+ mSlots[i].mFrameNumber < mSlots[found].mFrameNumber) {
+ found = i;
+ }
+ break;
}
}
@@ -348,7 +352,13 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>* outFence, bool async
// the max buffer count to change.
tryAgain = found == INVALID_BUFFER_SLOT;
if (tryAgain) {
- if (mDequeueBufferCannotBlock) {
+ // return an error if we're in "cannot block" mode (producer and consumer
+ // are controlled by the application) -- however, the consumer is allowed
+ // to acquire briefly an extra buffer (which could cause us to have to wait here)
+ // and that's okay because we know the wait will be brief (it happens
+ // if we dequeue a buffer while the consumer has acquired one but not released
+ // the old one yet -- for e.g.: see GLConsumer::updateTexImage()).
+ if (mDequeueBufferCannotBlock && (acquiredCount <= mMaxAcquiredBufferCount)) {
ST_LOGE("dequeueBuffer: would block! returning an error instead.");
return WOULD_BLOCK;
}