rewrite SF's message loop on top of Looper

Change-Id: Ib56139f87a5c0b124e34da5c8151207219b2577b
This commit is contained in:
Mathias Agopian 2011-11-23 16:49:10 -08:00
parent 26f68d62eb
commit f61c57fe2e
3 changed files with 66 additions and 218 deletions

View File

@ -29,169 +29,81 @@ namespace android {
// ---------------------------------------------------------------------------
void MessageList::insert(const sp<MessageBase>& node)
{
LIST::iterator cur(mList.begin());
LIST::iterator end(mList.end());
while (cur != end) {
if (*node < **cur) {
mList.insert(cur, node);
return;
}
++cur;
}
mList.insert(++end, node);
MessageBase::MessageBase()
: MessageHandler() {
}
void MessageList::remove(MessageList::LIST::iterator pos)
{
mList.erase(pos);
MessageBase::~MessageBase() {
}
void MessageBase::handleMessage(const Message&) {
this->handler();
barrier.open();
};
// ---------------------------------------------------------------------------
MessageQueue::MessageQueue()
: mInvalidate(false)
{
mInvalidateMessage = new MessageBase(INVALIDATE);
}
MessageQueue::~MessageQueue()
: mLooper(new Looper(true)),
mInvalidatePending(0)
{
}
sp<MessageBase> MessageQueue::waitMessage(nsecs_t timeout)
{
sp<MessageBase> result;
MessageQueue::~MessageQueue() {
}
bool again;
void MessageQueue::waitMessage() {
do {
const nsecs_t timeoutTime = systemTime() + timeout;
while (true) {
Mutex::Autolock _l(mLock);
nsecs_t now = systemTime();
nsecs_t nextEventTime = -1;
LIST::iterator cur(mMessages.begin());
if (cur != mMessages.end()) {
result = *cur;
}
if (result != 0) {
if (result->when <= now) {
// there is a message to deliver
mMessages.remove(cur);
break;
}
nextEventTime = result->when;
result = 0;
}
// see if we have an invalidate message
if (mInvalidate) {
mInvalidate = false;
mInvalidateMessage->when = now;
result = mInvalidateMessage;
break;
}
if (timeout >= 0) {
if (timeoutTime < now) {
// we timed-out, return a NULL message
result = 0;
break;
}
if (nextEventTime > 0) {
if (nextEventTime > timeoutTime) {
nextEventTime = timeoutTime;
}
} else {
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();
const nsecs_t reltime = nextEventTime - systemTime();
if (reltime > 0) {
mCondition.waitRelative(mLock, reltime);
}
}
} 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)
// handle invalidate events first
if (android_atomic_and(0, &mInvalidatePending) != 0)
break;
again = result->handler();
if (again) {
// the message has been processed. release our reference to it
// without holding the lock.
result->notify();
result = 0;
}
} while (again);
IPCThreadState::self()->flushCommands();
return result;
int32_t ret = mLooper->pollOnce(-1);
switch (ret) {
case ALOOPER_POLL_WAKE:
// we got woken-up there is work to do in the main loop
continue;
case ALOOPER_POLL_CALLBACK:
// callback was handled, loop again
continue;
case ALOOPER_POLL_TIMEOUT:
// timeout (should not happen)
continue;
case ALOOPER_POLL_ERROR:
LOGE("ALOOPER_POLL_ERROR");
continue;
default:
// should not happen
LOGE("Looper::pollOnce() returned unknown status %d", ret);
continue;
}
} while (true);
}
status_t MessageQueue::postMessage(
const sp<MessageBase>& message, nsecs_t relTime, uint32_t flags)
const sp<MessageBase>& messageHandler, nsecs_t relTime)
{
return queueMessage(message, relTime, flags);
const Message dummyMessage;
if (relTime > 0) {
mLooper->sendMessageDelayed(relTime, messageHandler, dummyMessage);
} else {
mLooper->sendMessage(messageHandler, dummyMessage);
}
return NO_ERROR;
}
status_t MessageQueue::invalidate() {
Mutex::Autolock _l(mLock);
mInvalidate = true;
mCondition.signal();
android_atomic_or(1, &mInvalidatePending);
mLooper->wake();
return NO_ERROR;
}
status_t MessageQueue::queueMessage(
const sp<MessageBase>& 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 sp<MessageBase>& message)
{
Mutex::Autolock _l(mLock);
dumpLocked(message);
}
void MessageQueue::dumpLocked(const sp<MessageBase>& message)
{
LIST::const_iterator cur(mMessages.begin());
LIST::const_iterator end(mMessages.end());
int c = 0;
while (cur != end) {
const char tick = (*cur == message) ? '>' : ' ';
LOGD("%c %d: msg{.what=%08x, when=%lld}",
tick, c, (*cur)->what, (*cur)->when);
++cur;
c++;
}
}
// ---------------------------------------------------------------------------
}; // namespace android

View File

@ -23,7 +23,7 @@
#include <utils/threads.h>
#include <utils/Timers.h>
#include <utils/List.h>
#include <utils/Looper.h>
#include "Barrier.h"
@ -31,92 +31,39 @@ namespace android {
// ---------------------------------------------------------------------------
class MessageBase;
class MessageList
{
List< sp<MessageBase> > mList;
typedef List< sp<MessageBase> > LIST;
public:
inline LIST::iterator begin() { return mList.begin(); }
inline LIST::const_iterator begin() const { return mList.begin(); }
inline LIST::iterator end() { return mList.end(); }
inline LIST::const_iterator end() const { return mList.end(); }
inline bool isEmpty() const { return mList.empty(); }
void insert(const sp<MessageBase>& node);
void remove(LIST::iterator pos);
};
// ============================================================================
class MessageBase :
public LightRefBase<MessageBase>
class MessageBase : public MessageHandler
{
public:
nsecs_t when;
uint32_t what;
int32_t arg0;
MessageBase() : when(0), what(0), arg0(0) { }
MessageBase(uint32_t what, int32_t arg0=0)
: when(0), what(what), arg0(arg0) { }
MessageBase();
// return true if message has a handler
virtual bool handler() { return false; }
virtual bool handler() = 0;
// waits for the handler to be processed
void wait() const { barrier.wait(); }
// releases all waiters. this is done automatically if
// handler returns true
void notify() const { barrier.open(); }
protected:
virtual ~MessageBase() { }
virtual ~MessageBase();
private:
mutable Barrier barrier;
friend class LightRefBase<MessageBase>;
};
virtual void handleMessage(const Message& message);
inline bool operator < (const MessageBase& lhs, const MessageBase& rhs) {
return lhs.when < rhs.when;
}
mutable Barrier barrier;
};
// ---------------------------------------------------------------------------
class MessageQueue
{
typedef List< sp<MessageBase> > LIST;
public:
class MessageQueue {
sp<Looper> mLooper;
volatile int32_t mInvalidatePending;
public:
MessageQueue();
~MessageQueue();
// pre-defined messages
enum {
INVALIDATE = '_upd'
};
sp<MessageBase> waitMessage(nsecs_t timeout = -1);
status_t postMessage(const sp<MessageBase>& message,
nsecs_t reltime=0, uint32_t flags = 0);
void waitMessage();
status_t postMessage(const sp<MessageBase>& message, nsecs_t reltime=0);
status_t invalidate();
void dump(const sp<MessageBase>& message);
private:
status_t queueMessage(const sp<MessageBase>& message,
nsecs_t reltime, uint32_t flags);
void dumpLocked(const sp<MessageBase>& message);
Mutex mLock;
Condition mCondition;
MessageList mMessages;
bool mInvalidate;
sp<MessageBase> mInvalidateMessage;
};
// ---------------------------------------------------------------------------

View File

@ -311,19 +311,8 @@ status_t SurfaceFlinger::readyToRun()
#pragma mark Events Handler
#endif
void SurfaceFlinger::waitForEvent()
{
while (true) {
nsecs_t timeout = -1;
sp<MessageBase> msg = mEventQueue.waitMessage(timeout);
if (msg != 0) {
switch (msg->what) {
case MessageQueue::INVALIDATE:
// invalidate message, just return to the main loop
return;
}
}
}
void SurfaceFlinger::waitForEvent() {
mEventQueue.waitMessage();
}
void SurfaceFlinger::signalEvent() {