diff options
author | Mathias Agopian <mathias@google.com> | 2009-04-20 19:39:12 -0700 |
---|---|---|
committer | Mathias Agopian <mathias@google.com> | 2009-04-24 16:22:36 -0700 |
commit | 6ead5d9f140529edfb744584fa5427b84b4dc13a (patch) | |
tree | 9685b259637326b603a88f1ff9cf8bb125ae9e1d /libs | |
parent | 6cf0db228ca275dfcda57d79c55e5fa306809632 (diff) | |
download | frameworks_base-6ead5d9f140529edfb744584fa5427b84b4dc13a.zip frameworks_base-6ead5d9f140529edfb744584fa5427b84b4dc13a.tar.gz frameworks_base-6ead5d9f140529edfb744584fa5427b84b4dc13a.tar.bz2 |
a brand new MessageQueue for SurfaceFlinger.
Diffstat (limited to 'libs')
-rw-r--r-- | libs/surfaceflinger/Android.mk | 1 | ||||
-rw-r--r-- | libs/surfaceflinger/MessageQueue.cpp | 161 | ||||
-rw-r--r-- | libs/surfaceflinger/MessageQueue.h | 224 | ||||
-rw-r--r-- | libs/surfaceflinger/SurfaceFlinger.cpp | 75 | ||||
-rw-r--r-- | libs/surfaceflinger/SurfaceFlinger.h | 29 | ||||
-rw-r--r-- | libs/ui/SurfaceFlingerSynchro.cpp | 81 |
6 files changed, 441 insertions, 130 deletions
diff --git a/libs/surfaceflinger/Android.mk b/libs/surfaceflinger/Android.mk index b8077c7..2b360d6 100644 --- a/libs/surfaceflinger/Android.mk +++ b/libs/surfaceflinger/Android.mk @@ -16,6 +16,7 @@ LOCAL_SRC_FILES:= \ LayerDim.cpp \ LayerOrientationAnim.cpp \ LayerOrientationAnimRotate.cpp \ + MessageQueue.cpp \ OrientationAnimation.cpp \ SurfaceFlinger.cpp \ Tokenizer.cpp \ diff --git a/libs/surfaceflinger/MessageQueue.cpp b/libs/surfaceflinger/MessageQueue.cpp new file mode 100644 index 0000000..9079383 --- /dev/null +++ b/libs/surfaceflinger/MessageQueue.cpp @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdint.h> +#include <errno.h> +#include <sys/types.h> + +#include <utils/threads.h> +#include <utils/Timers.h> +#include <utils/Log.h> +#include <utils/IPCThreadState.h> + +#include "MessageQueue.h" + +namespace android { + +// --------------------------------------------------------------------------- + +MessageQueue::MessageQueue() +{ + mInvalidateMessage = new MessageBase(INVALIDATE); +} + +MessageQueue::~MessageQueue() +{ +} + +MessageList::NODE_PTR MessageQueue::waitMessage(nsecs_t timeout) +{ + MessageList::NODE_PTR result; + bool again; + do { + const nsecs_t timeoutTime = systemTime() + timeout; + while (true) { + Mutex::Autolock _l(mLock); + nsecs_t now = systemTime(); + nsecs_t nextEventTime = -1; + + // invalidate messages are always handled first + if (mInvalidate) { + mInvalidate = false; + mInvalidateMessage->when = now; + result = mInvalidateMessage; + break; + } + + result = mMessages.head(); + + if (result != 0) { + if (result->when <= now) { + // there is a message to deliver + mMessages.remove(result); + result->detach(); + break; + } + if (timeout>=0 && timeoutTime < now) { + // we timed-out, return a NULL message + result = 0; + break; + } + nextEventTime = result->when; + result = 0; + } + + if (timeout >= 0 && nextEventTime > 0) { + if (nextEventTime > timeoutTime) { + nextEventTime = timeoutTime; + } + } + + if (nextEventTime >= 0) { + //LOGD("nextEventTime = %lld ms", nextEventTime); + if (nextEventTime > 0) { + // we're about to wait, flush the binder command buffer + IPCThreadState::self()->flushCommands(); + mCondition.wait(mLock, nextEventTime); + } + } else { + //LOGD("going to wait"); + // we're about to wait, flush the binder command buffer + IPCThreadState::self()->flushCommands(); + mCondition.wait(mLock); + } + } + // here we're not holding the lock anymore + + if (result == 0) + break; + + again = result->handler(); + if (again) { + // the message has been processed. release our reference to it + // without holding the lock. + result = 0; + } + + } while (again); + return result; +} + +status_t MessageQueue::postMessage( + const MessageList::NODE_PTR& message, nsecs_t relTime, uint32_t flags) +{ + return queueMessage(message, relTime, flags); +} + +status_t MessageQueue::invalidate() { + Mutex::Autolock _l(mLock); + mInvalidate = true; + mCondition.signal(); + return NO_ERROR; +} + +status_t MessageQueue::queueMessage( + const MessageList::NODE_PTR& message, nsecs_t relTime, uint32_t flags) +{ + Mutex::Autolock _l(mLock); + message->when = systemTime() + relTime; + mMessages.insert(message); + + //LOGD("MessageQueue::queueMessage time = %lld ms", message->when); + //dumpLocked(message); + + mCondition.signal(); + return NO_ERROR; +} + +void MessageQueue::dump(const MessageList::NODE_PTR& message) +{ + Mutex::Autolock _l(mLock); + dumpLocked(message); +} + +void MessageQueue::dumpLocked(const MessageList::NODE_PTR& message) +{ + MessageList::NODE_PTR l(mMessages.head()); + int c = 0; + while (l != 0) { + const char tick = (l == message) ? '>' : ' '; + LOGD("%c %d: msg{.what=%08x, when=%lld}", tick, c, l->what, l->when); + l = l->getNext(); + c++; + } +} + +// --------------------------------------------------------------------------- + +}; // namespace android diff --git a/libs/surfaceflinger/MessageQueue.h b/libs/surfaceflinger/MessageQueue.h new file mode 100644 index 0000000..d894fe2 --- /dev/null +++ b/libs/surfaceflinger/MessageQueue.h @@ -0,0 +1,224 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_MESSAGE_QUEUE_H +#define ANDROID_MESSAGE_QUEUE_H + +#include <stdint.h> +#include <errno.h> +#include <sys/types.h> + +#include <utils/threads.h> +#include <utils/Timers.h> + + +namespace android { + +// --------------------------------------------------------------------------- + +template<typename NODE_PTR_TYPE> +class DoublyLinkedList +{ +protected: + typedef NODE_PTR_TYPE NODE_PTR; + + NODE_PTR mFirst; + NODE_PTR mLast; + +public: + class Node { + friend class DoublyLinkedList; + mutable NODE_PTR next; + mutable NODE_PTR prev; + public: + typedef NODE_PTR PTR; + inline NODE_PTR getNext() const { return next; } + inline NODE_PTR getPrev() const { return prev; } + void detach() { + prev = 0; + next = 0; + } + }; + + DoublyLinkedList() : mFirst(0), mLast(0) { } + ~DoublyLinkedList() { } + + bool isEmpty() const { return mFirst == 0; } + const NODE_PTR& head() const { return mFirst; } + const NODE_PTR& tail() const { return mLast; } + const NODE_PTR& head() { return mFirst; } + const NODE_PTR& tail() { return mLast; } + + void insertAfter(const NODE_PTR& node, const NODE_PTR& newNode) { + newNode->prev = node; + newNode->next = node->next; + if (node->next == 0) mLast = newNode; + else node->next->prev = newNode; + node->next = newNode; + } + + void insertBefore(const NODE_PTR& node, const NODE_PTR& newNode) { + newNode->prev = node->prev; + newNode->next = node; + if (node->prev == 0) mFirst = newNode; + else node->prev->next = newNode; + node->prev = newNode; + } + + void insertHead(const NODE_PTR& newNode) { + if (mFirst == 0) { + mFirst = mLast = newNode; + newNode->prev = newNode->next = 0; + } else { + newNode->prev = 0; + newNode->next = mFirst; + mFirst->prev = newNode; + mFirst = newNode; + } + } + + void insertTail(const NODE_PTR& newNode) { + if (mLast == 0) { + insertHead(newNode); + } else { + newNode->prev = mLast; + newNode->next = 0; + mLast->next = newNode; + mLast = newNode; + } + } + + NODE_PTR remove(const NODE_PTR& node) { + if (node->prev == 0) mFirst = node->next; + else node->prev->next = node->next; + if (node->next == 0) mLast = node->prev; + else node->next->prev = node->prev; + return node; + } +}; + +// --------------------------------------------------------------------------- + +template<typename NODE_PTR_TYPE> +class SortedList : protected DoublyLinkedList< NODE_PTR_TYPE > +{ + typedef DoublyLinkedList< NODE_PTR_TYPE > forward; +public: + typedef NODE_PTR_TYPE NODE_PTR; + inline bool isEmpty() const { return forward::isEmpty(); } + inline const NODE_PTR& head() const { return forward::head(); } + inline const NODE_PTR& tail() const { return forward::tail(); } + inline const NODE_PTR& head() { return forward::head(); } + inline const NODE_PTR& tail() { return forward::tail(); } + inline NODE_PTR remove(const NODE_PTR& node) { return forward::remove(node); } + void insert(const NODE_PTR& node) { + NODE_PTR l(head()); + while (l != 0) { + if (*node < *l) { + insertBefore(l, node); + return; + } + l = l->getNext(); + } + insertTail(node); + } +}; + +// ============================================================================ + +class MessageBase : + public LightRefBase<MessageBase>, + public DoublyLinkedList< sp<MessageBase> >::Node +{ +public: + nsecs_t when; + uint32_t what; + int32_t arg0; + + MessageBase(uint32_t what=0, int32_t arg0=0) + : when(0), what(what), arg0(arg0) { } + + // return true if message has a handler + virtual bool handler() { return false; } + +protected: + virtual ~MessageBase() { } + +private: + friend class LightRefBase<MessageBase>; +}; + +inline bool operator < (const MessageBase& lhs, const MessageBase& rhs) { + return lhs.when < rhs.when; +} + +// --------------------------------------------------------------------------- + +/* + * MessageList is a sorted list of sp<MessageBase> + */ + +typedef SortedList< MessageBase::Node::PTR > MessageList; + +// --------------------------------------------------------------------------- + +class MessageQueue +{ +public: + + // this is a work-around the multichar constant warning. A macro would + // work too, but would pollute the namespace. + template <int a, int b, int c, int d> + struct WHAT { + static const uint32_t Value = + (uint32_t(a&0xff)<<24)|(uint32_t(b&0xff)<<16)| + (uint32_t(c&0xff)<<8)|uint32_t(d&0xff); + }; + + MessageQueue(); + ~MessageQueue(); + + // pre-defined messages + enum { + INVALIDATE = WHAT<'_','p','d','t'>::Value + }; + + MessageList::NODE_PTR waitMessage(nsecs_t timeout = -1); + + status_t postMessage(const MessageList::NODE_PTR& message, + nsecs_t reltime=0, uint32_t flags = 0); + + status_t invalidate(); + + void dump(const MessageList::NODE_PTR& message); + +private: + status_t queueMessage(const MessageList::NODE_PTR& message, + nsecs_t reltime, uint32_t flags); + void dumpLocked(const MessageList::NODE_PTR& message); + + Mutex mLock; + Condition mCondition; + MessageList mMessages; + bool mInvalidate; + MessageList::NODE_PTR mInvalidateMessage; +}; + +// --------------------------------------------------------------------------- + +}; // namespace android + +#endif /* ANDROID_MESSAGE_QUEUE_H */ diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp index 6b2a103..1b6d6de 100644 --- a/libs/surfaceflinger/SurfaceFlinger.cpp +++ b/libs/surfaceflinger/SurfaceFlinger.cpp @@ -56,7 +56,6 @@ #include "DisplayHardware/DisplayHardware.h" - #define DISPLAY_COUNT 1 namespace android { @@ -181,8 +180,6 @@ SurfaceFlinger::SurfaceFlinger() mDebugFps(0), mDebugBackground(0), mDebugNoBootAnimation(0), - mSyncObject(), - mDeplayedTransactionPending(0), mConsoleSignals(0), mSecureFrameBuffer(0) { @@ -423,45 +420,53 @@ status_t SurfaceFlinger::readyToRun() void SurfaceFlinger::waitForEvent() { - // wait for something to do - if (UNLIKELY(isFrozen())) { - // wait 5 seconds - const nsecs_t freezeDisplayTimeout = ms2ns(5000); - const nsecs_t now = systemTime(); - if (mFreezeDisplayTime == 0) { - mFreezeDisplayTime = now; + while (true) { + nsecs_t timeout = -1; + if (UNLIKELY(isFrozen())) { + // wait 5 seconds + const nsecs_t freezeDisplayTimeout = ms2ns(5000); + const nsecs_t now = systemTime(); + if (mFreezeDisplayTime == 0) { + mFreezeDisplayTime = now; + } + nsecs_t waitTime = freezeDisplayTimeout - (now - mFreezeDisplayTime); + timeout = waitTime>0 ? waitTime : 0; } - nsecs_t waitTime = freezeDisplayTimeout - (now - mFreezeDisplayTime); - int err = (waitTime > 0) ? mSyncObject.wait(waitTime) : TIMED_OUT; - if (err != NO_ERROR) { + + MessageList::NODE_PTR msg = mEventQueue.waitMessage(timeout); + if (msg != 0) { + mFreezeDisplayTime = 0; + switch (msg->what) { + case MessageQueue::INVALIDATE: + // invalidate message, just return to the main loop + return; + } + } else { + // we timed out if (isFrozen()) { // we timed out and are still frozen LOGW("timeout expired mFreezeDisplay=%d, mFreezeCount=%d", mFreezeDisplay, mFreezeCount); mFreezeCount = 0; mFreezeDisplay = false; + return; } } - } else { - mFreezeDisplayTime = 0; - mSyncObject.wait(); } } void SurfaceFlinger::signalEvent() { - mSyncObject.open(); + mEventQueue.invalidate(); } void SurfaceFlinger::signal() const { - mSyncObject.open(); + // this is the IPC call + const_cast<SurfaceFlinger*>(this)->signalEvent(); } void SurfaceFlinger::signalDelayedEvent(nsecs_t delay) { - if (android_atomic_or(1, &mDeplayedTransactionPending) == 0) { - sp<DelayedTransaction> delayedEvent(new DelayedTransaction(this, delay)); - delayedEvent->run("DelayedeEvent", PRIORITY_URGENT_DISPLAY); - } + mEventQueue.postMessage( new MessageBase(MessageQueue::INVALIDATE), delay); } // ---------------------------------------------------------------------------- @@ -1302,16 +1307,32 @@ status_t SurfaceFlinger::destroySurface(const sp<LayerBaseClient>& layer) */ /* FIXME: - * - this can calls ~Layer(), which is wrong because we're not in the - * GL thread, and ~Layer() currently calls OpenGL. * - ideally we want to release as much GL state as possible after * purgatorizeLayer_l() has been called and the surface is not in any * active list. - * - ideally we'd call ~Layer() without mStateLock held */ - Mutex::Autolock _l(mStateLock); - mLayerPurgatory.remove(layer); + class MessageDestroySurface : public MessageBase { + sp<SurfaceFlinger> flinger; + sp<LayerBaseClient> layer; + public: + MessageDestroySurface(const sp<SurfaceFlinger>& flinger, + const sp<LayerBaseClient>& layer) + : MessageBase(0), flinger(flinger), layer(layer) { + } + ~MessageDestroySurface() { + //LOGD("~MessageDestroySurface, layer=%p", layer.get()); + } + virtual bool handler() { + //LOGD("MessageDestroySurface handler, layer=%p", layer.get()); + Mutex::Autolock _l(flinger->mStateLock); + flinger->mLayerPurgatory.remove(layer); + return true; + } + }; + + mEventQueue.postMessage( new MessageDestroySurface(this, layer) ); + return NO_ERROR; } diff --git a/libs/surfaceflinger/SurfaceFlinger.h b/libs/surfaceflinger/SurfaceFlinger.h index b488ab5..76e40a1 100644 --- a/libs/surfaceflinger/SurfaceFlinger.h +++ b/libs/surfaceflinger/SurfaceFlinger.h @@ -34,13 +34,14 @@ #include <private/ui/SharedState.h> #include <private/ui/LayerState.h> -#include <private/ui/SurfaceFlingerSynchro.h> #include "Barrier.h" #include "BootAnimation.h" #include "Layer.h" #include "Tokenizer.h" +#include "MessageQueue.h" + struct copybit_device_t; struct overlay_device_t; @@ -235,25 +236,6 @@ private: uint8_t freezeDisplay; }; - class DelayedTransaction : public Thread - { - friend class SurfaceFlinger; - sp<SurfaceFlinger> mFlinger; - nsecs_t mDelay; - public: - DelayedTransaction(const sp<SurfaceFlinger>& flinger, nsecs_t delay) - : Thread(false), mFlinger(flinger), mDelay(delay) { - } - virtual bool threadLoop() { - usleep(mDelay / 1000); - if (android_atomic_and(~1, - &mFlinger->mDeplayedTransactionPending) == 1) { - mFlinger->signalEvent(); - } - return false; - } - }; - virtual bool threadLoop(); virtual status_t readyToRun(); virtual void onFirstRef(); @@ -310,6 +292,11 @@ private: void debugShowFPS() const; void drawWormhole() const; + + mutable MessageQueue mEventQueue; + + + // access must be protected by mStateLock mutable Mutex mStateLock; State mCurrentState; @@ -359,8 +346,6 @@ private: // these are thread safe mutable Barrier mReadyToRunBarrier; - mutable SurfaceFlingerSynchro mSyncObject; - volatile int32_t mDeplayedTransactionPending; // atomic variables enum { diff --git a/libs/ui/SurfaceFlingerSynchro.cpp b/libs/ui/SurfaceFlingerSynchro.cpp index 5cd9755..c81db71 100644 --- a/libs/ui/SurfaceFlingerSynchro.cpp +++ b/libs/ui/SurfaceFlingerSynchro.cpp @@ -14,19 +14,7 @@ * limitations under the License. */ -#define LOG_TAG "SurfaceFlingerSynchro" - #include <stdint.h> -#include <string.h> -#include <unistd.h> -#include <fcntl.h> -#include <errno.h> -#include <limits.h> -#include <sys/types.h> -#include <sys/stat.h> - -#include <utils/IPCThreadState.h> -#include <utils/Log.h> #include <private/ui/SurfaceFlingerSynchro.h> @@ -34,61 +22,10 @@ namespace android { // --------------------------------------------------------------------------- -SurfaceFlingerSynchro::Barrier::Barrier() - : state(CLOSED) { -} - -SurfaceFlingerSynchro::Barrier::~Barrier() { -} - -void SurfaceFlingerSynchro::Barrier::open() { - asm volatile ("":::"memory"); - Mutex::Autolock _l(lock); - state = OPENED; - cv.broadcast(); -} - -void SurfaceFlingerSynchro::Barrier::close() { - Mutex::Autolock _l(lock); - state = CLOSED; -} - -void SurfaceFlingerSynchro::Barrier::waitAndClose() -{ - Mutex::Autolock _l(lock); - while (state == CLOSED) { - // we're about to wait, flush the binder command buffer - IPCThreadState::self()->flushCommands(); - cv.wait(lock); - } - state = CLOSED; -} - -status_t SurfaceFlingerSynchro::Barrier::waitAndClose(nsecs_t timeout) -{ - Mutex::Autolock _l(lock); - while (state == CLOSED) { - // we're about to wait, flush the binder command buffer - IPCThreadState::self()->flushCommands(); - int err = cv.waitRelative(lock, timeout); - if (err != 0) - return err; - } - state = CLOSED; - return NO_ERROR; -} - -// --------------------------------------------------------------------------- - SurfaceFlingerSynchro::SurfaceFlingerSynchro(const sp<ISurfaceComposer>& flinger) : mSurfaceComposer(flinger) { } - -SurfaceFlingerSynchro::SurfaceFlingerSynchro() -{ -} - SurfaceFlingerSynchro::~SurfaceFlingerSynchro() { } @@ -99,24 +36,6 @@ status_t SurfaceFlingerSynchro::signal() return NO_ERROR; } -status_t SurfaceFlingerSynchro::wait() -{ - mBarrier.waitAndClose(); - return NO_ERROR; -} - -status_t SurfaceFlingerSynchro::wait(nsecs_t timeout) -{ - if (timeout == 0) - return SurfaceFlingerSynchro::wait(); - return mBarrier.waitAndClose(timeout); -} - -void SurfaceFlingerSynchro::open() -{ - mBarrier.open(); -} - // --------------------------------------------------------------------------- }; // namespace android |