summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Brown <jeffbrown@google.com>2010-09-21 15:14:14 -0700
committerJeff Brown <jeffbrown@google.com>2010-09-21 15:41:33 -0700
commited7393274af2f268fcdede5f1a3d72c9af842b8e (patch)
tree37d4ec6892e9543e8e083326df8335a4c2661de2
parentcce0cd138dd0dc338db59083052aca01a51bd52d (diff)
downloadframeworks_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.java123
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) {