diff options
Diffstat (limited to 'services/surfaceflinger/MessageQueue.cpp')
| -rw-r--r-- | services/surfaceflinger/MessageQueue.cpp | 193 | 
1 files changed, 193 insertions, 0 deletions
| diff --git a/services/surfaceflinger/MessageQueue.cpp b/services/surfaceflinger/MessageQueue.cpp new file mode 100644 index 000000000000..d668e88d471f --- /dev/null +++ b/services/surfaceflinger/MessageQueue.cpp @@ -0,0 +1,193 @@ +/* + * 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 <binder/IPCThreadState.h> + +#include "MessageQueue.h" + +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); +} + +void MessageList::remove(MessageList::LIST::iterator pos)  +{ +    mList.erase(pos); +} + +// --------------------------------------------------------------------------- + +MessageQueue::MessageQueue() +    : mInvalidate(false) +{ +    mInvalidateMessage = new MessageBase(INVALIDATE); +} + +MessageQueue::~MessageQueue() +{ +} + +sp<MessageBase> MessageQueue::waitMessage(nsecs_t timeout) +{ +    sp<MessageBase> 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; +            } + +            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; +                } +                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(); +                    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; + +        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); + +    return result; +} + +status_t MessageQueue::postMessage( +        const sp<MessageBase>& 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 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 | 
