/* * 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() { } MessageList::value_type MessageQueue::waitMessage(nsecs_t timeout) { MessageList::value_type 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 = 0; } } while (again); return result; } status_t MessageQueue::postMessage( const MessageList::value_type& 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::value_type& 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::value_type& message) { Mutex::Autolock _l(mLock); dumpLocked(message); } void MessageQueue::dumpLocked(const MessageList::value_type& 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