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

Commit 6ead5d9f authored by Mathias Agopian's avatar Mathias Agopian
Browse files

a brand new MessageQueue for SurfaceFlinger.

parent 6cf0db22
Loading
Loading
Loading
Loading
+0 −28
Original line number Original line Diff line number Diff line
@@ -21,7 +21,6 @@
#include <stdint.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/types.h>
#include <utils/Errors.h>
#include <utils/Errors.h>
#include <utils/threads.h>
#include <ui/ISurfaceComposer.h>
#include <ui/ISurfaceComposer.h>


namespace android {
namespace android {
@@ -31,7 +30,6 @@ class SurfaceFlinger;
class SurfaceFlingerSynchro
class SurfaceFlingerSynchro
{
{
public:
public:

                // client constructor
                // client constructor
                SurfaceFlingerSynchro(const sp<ISurfaceComposer>& flinger);
                SurfaceFlingerSynchro(const sp<ISurfaceComposer>& flinger);
                ~SurfaceFlingerSynchro();
                ~SurfaceFlingerSynchro();
@@ -40,34 +38,8 @@ public:
    status_t    signal();
    status_t    signal();
    
    
private:
private:
    class Barrier {
    public:
        Barrier();
        ~Barrier();
        void open();
        void close();
        void waitAndClose();
        status_t waitAndClose(nsecs_t timeout);
    private:
        enum { OPENED, CLOSED };
        mutable     Mutex       lock;
        mutable     Condition   cv;
        volatile    int         state;
    };

    friend class SurfaceFlinger;
    friend class SurfaceFlinger;

                // server constructor
                SurfaceFlingerSynchro();
                
    void        open();
    
                // wait until there is some work to do
    status_t    wait();
    status_t    wait(nsecs_t timeout);
    
    sp<ISurfaceComposer> mSurfaceComposer;
    sp<ISurfaceComposer> mSurfaceComposer;
    Barrier              mBarrier;
};
};


}; // namespace android
}; // namespace android
+12 −3
Original line number Original line Diff line number Diff line
@@ -117,13 +117,22 @@ public:
            mFirst = mLast = newNode;
            mFirst = mLast = newNode;
            newNode->prev = newNode->next = 0;
            newNode->prev = newNode->next = 0;
        } else {
        } else {
            insertBefore(mFirst, newNode);
            newNode->prev = 0;
            newNode->next = mFirst;
            mFirst->prev = newNode;
            mFirst = newNode;
        }
        }
    }
    }
    
    
    void insertTail(NODE* newNode) {
    void insertTail(NODE* newNode) {
        if (mLast == 0) insertBeginning(newNode);
        if (mLast == 0) {
        else            insertAfter(mLast, newNode);
            insertHead(newNode);
        } else {
            newNode->prev = mLast;
            newNode->next = 0;
            mLast->next = newNode;
            mLast = newNode;
        }
    }
    }


    NODE* remove(NODE* node) {
    NODE* remove(NODE* node) {
+1 −0
Original line number Original line Diff line number Diff line
@@ -16,6 +16,7 @@ LOCAL_SRC_FILES:= \
    LayerDim.cpp \
    LayerDim.cpp \
    LayerOrientationAnim.cpp \
    LayerOrientationAnim.cpp \
    LayerOrientationAnimRotate.cpp \
    LayerOrientationAnimRotate.cpp \
    MessageQueue.cpp \
    OrientationAnimation.cpp \
    OrientationAnimation.cpp \
    SurfaceFlinger.cpp \
    SurfaceFlinger.cpp \
    Tokenizer.cpp \
    Tokenizer.cpp \
+161 −0
Original line number Original line Diff line number Diff line
/*
 * 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
+224 −0
Original line number Original line Diff line number Diff line
/*
 * 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 */
Loading