Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f61c57fe authored by Mathias Agopian's avatar Mathias Agopian
Browse files

rewrite SF's message loop on top of Looper

Change-Id: Ib56139f87a5c0b124e34da5c8151207219b2577b
parent 26f68d62
Loading
Loading
Loading
Loading
+49 −137
Original line number Diff line number Diff line
@@ -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)
    : mLooper(new Looper(true)),
      mInvalidatePending(0)
{
    mInvalidateMessage = new MessageBase(INVALIDATE);
}

MessageQueue::~MessageQueue()
{
MessageQueue::~MessageQueue() {
}

sp<MessageBase> MessageQueue::waitMessage(nsecs_t timeout)
{
    sp<MessageBase> result;

    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);
        // handle invalidate events first
        if (android_atomic_and(0, &mInvalidatePending) != 0)
            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)
            break;
        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;

        again = result->handler();
        if (again) {
            // the message has been processed. release our reference to it
            // without holding the lock.
            result->notify();
            result = 0;
        }
            case ALOOPER_POLL_CALLBACK:
                // callback was handled, loop again
                continue;

            case ALOOPER_POLL_TIMEOUT:
                // timeout (should not happen)
                continue;

    } while (again);
            case ALOOPER_POLL_ERROR:
                LOGE("ALOOPER_POLL_ERROR");
                continue;

    return result;
            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);
    }

status_t MessageQueue::invalidate() {
    Mutex::Autolock _l(mLock);
    mInvalidate = true;
    mCondition.signal();
    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();
status_t MessageQueue::invalidate() {
    android_atomic_or(1, &mInvalidatePending);
    mLooper->wake();
    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
+13 −66
Original line number Diff line number Diff line
@@ -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:
    virtual void handleMessage(const Message& message);

    mutable Barrier barrier;
    friend class LightRefBase<MessageBase>;
};

inline bool operator < (const MessageBase& lhs, const MessageBase& rhs) {
    return lhs.when < rhs.when;
}

// ---------------------------------------------------------------------------

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;
};

// ---------------------------------------------------------------------------
+2 −13
Original line number Diff line number Diff line
@@ -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() {