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

Commit ed739327 authored by Jeff Brown's avatar Jeff Brown
Browse files

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
parent cce0cd13
Loading
Loading
Loading
Loading
+54 −69
Original line number Diff line number Diff line
@@ -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,38 +106,56 @@ 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) {
                    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 (pendingIdleHandlerCount == 0) {
                    // No idle handlers to run.  Loop and wait some more.
                    continue;
                }

                if (tryIdle && mIdleHandlers.size() > 0) {
                    idlers = mIdleHandlers.toArray();
                if (mPendingIdleHandlers == null) {
                    mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
                }
                mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
            }

            // 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) {
            // 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 {
                        didIdle = true;
                        keep = ((IdleHandler)idler).queueIdle();
                    keep = idler.queueIdle();
                } catch (Throwable t) {
                    Log.wtf("MessageQueue", "IdleHandler threw exception", t);
                }
@@ -147,50 +166,16 @@ public class MessageQueue {
                    }
                }
            }
            }
            
            // 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;
            }

            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;
                    }
                } else {
                    Binder.flushPendingCommands();
                    timeToNextEventMillis = -1;
                }
            }
            // loop to the while(true) and do the appropriate nativeWait(when)
        }
    }
            // Reset the idle handler count to 0 so we do not run them again.
            pendingIdleHandlerCount = 0;

    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;
            // 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;
        }
    }

        return null;
    }

    final boolean enqueueMessage(Message msg, long when) {
        if (msg.when != 0) {
            throw new AndroidRuntimeException(msg