diff options
author | Jeff Brown <jeffbrown@google.com> | 2010-09-21 15:14:14 -0700 |
---|---|---|
committer | Jeff Brown <jeffbrown@google.com> | 2010-09-21 15:41:33 -0700 |
commit | ed7393274af2f268fcdede5f1a3d72c9af842b8e (patch) | |
tree | 37d4ec6892e9543e8e083326df8335a4c2661de2 | |
parent | cce0cd138dd0dc338db59083052aca01a51bd52d (diff) | |
download | frameworks_base-ed7393274af2f268fcdede5f1a3d72c9af842b8e.zip frameworks_base-ed7393274af2f268fcdede5f1a3d72c9af842b8e.tar.gz frameworks_base-ed7393274af2f268fcdede5f1a3d72c9af842b8e.tar.bz2 |
Simplify and optimize MessageQueue loop.
Avoids allocating new idle handler arrays on each iteration since
we only need one to copy into.
Coalesced the synchronized blocks.
Hoisted the call to Binder.flushPendingCommands() outside of the
synchronized block.
Change-Id: Iabb6b633627954564bdd5d09e696663223407f47
-rw-r--r-- | core/java/android/os/MessageQueue.java | 123 |
1 files changed, 54 insertions, 69 deletions
diff --git a/core/java/android/os/MessageQueue.java b/core/java/android/os/MessageQueue.java index 2813863..6237c0e 100644 --- a/core/java/android/os/MessageQueue.java +++ b/core/java/android/os/MessageQueue.java @@ -33,6 +33,7 @@ import java.util.ArrayList; public class MessageQueue { Message mMessages; private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>(); + private IdleHandler[] mPendingIdleHandlers; private boolean mQuiting = false; boolean mQuitAllowed = true; @@ -105,90 +106,74 @@ public class MessageQueue { } final Message next() { - boolean tryIdle = true; - // when we start out, we'll just touch the input pipes and then go from there - int timeToNextEventMillis = 0; + int pendingIdleHandlerCount = -1; // -1 only during first iteration + int nextPollTimeoutMillis = 0; - while (true) { - long now; - Object[] idlers = null; - - boolean dispatched = nativePollOnce(timeToNextEventMillis); + for (;;) { + if (nextPollTimeoutMillis != 0) { + Binder.flushPendingCommands(); + } + nativePollOnce(nextPollTimeoutMillis); - // Try to retrieve the next message, returning if found. synchronized (this) { - now = SystemClock.uptimeMillis(); - Message msg = pullNextLocked(now); + // Try to retrieve the next message. Return if found. + final long now = SystemClock.uptimeMillis(); + final Message msg = mMessages; if (msg != null) { - return msg; + final long when = msg.when; + if (now >= when) { + mMessages = msg.next; + if (Config.LOGV) Log.v("MessageQueue", "Returning message: " + msg); + return msg; + } else { + nextPollTimeoutMillis = (int) Math.min(when - now, Integer.MAX_VALUE); + } + } else { + nextPollTimeoutMillis = -1; + } + + // If first time, then get the number of idlers to run. + if (pendingIdleHandlerCount < 0) { + pendingIdleHandlerCount = mIdleHandlers.size(); } - - if (tryIdle && mIdleHandlers.size() > 0) { - idlers = mIdleHandlers.toArray(); + if (pendingIdleHandlerCount == 0) { + // No idle handlers to run. Loop and wait some more. + continue; } - } - - // There was no message so we are going to wait... but first, - // if there are any idle handlers let them know. - boolean didIdle = false; - if (idlers != null) { - for (Object idler : idlers) { - boolean keep = false; - try { - didIdle = true; - keep = ((IdleHandler)idler).queueIdle(); - } catch (Throwable t) { - Log.wtf("MessageQueue", "IdleHandler threw exception", t); - } - if (!keep) { - synchronized (this) { - mIdleHandlers.remove(idler); - } - } + if (mPendingIdleHandlers == null) { + mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)]; } - } - - // While calling an idle handler, a new message could have been - // delivered... so go back and look again for a pending message. - if (didIdle) { - tryIdle = false; - continue; + mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers); } - synchronized (this) { - // No messages, nobody to tell about it... time to wait! - if (mMessages != null) { - long longTimeToNextEventMillis = mMessages.when - now; - - if (longTimeToNextEventMillis > 0) { - Binder.flushPendingCommands(); - timeToNextEventMillis = (int) Math.min(longTimeToNextEventMillis, - Integer.MAX_VALUE); - } else { - timeToNextEventMillis = 0; + // Run the idle handlers. + // We only ever reach this code block during the first iteration. + for (int i = 0; i < pendingIdleHandlerCount; i++) { + final IdleHandler idler = mPendingIdleHandlers[i]; + mPendingIdleHandlers[i] = null; // release the reference to the handler + + boolean keep = false; + try { + keep = idler.queueIdle(); + } catch (Throwable t) { + Log.wtf("MessageQueue", "IdleHandler threw exception", t); + } + + if (!keep) { + synchronized (this) { + mIdleHandlers.remove(idler); } - } else { - Binder.flushPendingCommands(); - timeToNextEventMillis = -1; } } - // loop to the while(true) and do the appropriate nativeWait(when) - } - } - final Message pullNextLocked(long now) { - Message msg = mMessages; - if (msg != null) { - if (now >= msg.when) { - mMessages = msg.next; - if (Config.LOGV) Log.v( - "MessageQueue", "Returning message: " + msg); - return msg; - } - } + // Reset the idle handler count to 0 so we do not run them again. + pendingIdleHandlerCount = 0; - return null; + // While calling an idle handler, a new message could have been delivered + // so go back and look again for a pending message without waiting. + nextPollTimeoutMillis = 0; + } } final boolean enqueueMessage(Message msg, long when) { |