Switch to a fancy new queue

Test: unit tests & benchmarks pass/faster

Change-Id: I9521432172d6dd6039c5280b1265479a36a86247
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 51e9374..f3bb120 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -49,101 +49,6 @@
 // Slight delay to give the UI time to push us a new frame before we replay
 static const nsecs_t DISPATCH_FRAME_CALLBACKS_DELAY = milliseconds_to_nanoseconds(4);
 
-TaskQueue::TaskQueue() : mHead(nullptr), mTail(nullptr) {}
-
-RenderTask* TaskQueue::next() {
-    RenderTask* ret = mHead;
-    if (ret) {
-        mHead = ret->mNext;
-        if (!mHead) {
-            mTail = nullptr;
-        }
-        ret->mNext = nullptr;
-    }
-    return ret;
-}
-
-RenderTask* TaskQueue::peek() {
-    return mHead;
-}
-
-void TaskQueue::queue(RenderTask* task) {
-    // Since the RenderTask itself forms the linked list it is not allowed
-    // to have the same task queued twice
-    LOG_ALWAYS_FATAL_IF(task->mNext || mTail == task, "Task is already in the queue!");
-    if (mTail) {
-        // Fast path if we can just append
-        if (mTail->mRunAt <= task->mRunAt) {
-            mTail->mNext = task;
-            mTail = task;
-        } else {
-            // Need to find the proper insertion point
-            RenderTask* previous = nullptr;
-            RenderTask* next = mHead;
-            while (next && next->mRunAt <= task->mRunAt) {
-                previous = next;
-                next = next->mNext;
-            }
-            if (!previous) {
-                task->mNext = mHead;
-                mHead = task;
-            } else {
-                previous->mNext = task;
-                if (next) {
-                    task->mNext = next;
-                } else {
-                    mTail = task;
-                }
-            }
-        }
-    } else {
-        mTail = mHead = task;
-    }
-}
-
-void TaskQueue::queueAtFront(RenderTask* task) {
-    LOG_ALWAYS_FATAL_IF(task->mNext || mHead == task, "Task is already in the queue!");
-    if (mTail) {
-        task->mNext = mHead;
-        mHead = task;
-    } else {
-        mTail = mHead = task;
-    }
-}
-
-void TaskQueue::remove(RenderTask* task) {
-    // TaskQueue is strict here to enforce that users are keeping track of
-    // their RenderTasks due to how their memory is managed
-    LOG_ALWAYS_FATAL_IF(!task->mNext && mTail != task,
-            "Cannot remove a task that isn't in the queue!");
-
-    // If task is the head we can just call next() to pop it off
-    // Otherwise we need to scan through to find the task before it
-    if (peek() == task) {
-        next();
-    } else {
-        RenderTask* previous = mHead;
-        while (previous->mNext != task) {
-            previous = previous->mNext;
-        }
-        previous->mNext = task->mNext;
-        if (mTail == task) {
-            mTail = previous;
-        }
-    }
-}
-
-class DispatchFrameCallbacks : public RenderTask {
-private:
-    RenderThread* mRenderThread;
-public:
-    explicit DispatchFrameCallbacks(RenderThread* rt) : mRenderThread(rt) {}
-
-    virtual void run() override {
-        mRenderThread->dispatchFrameCallbacks();
-    }
-};
-
 static bool gHasRenderThreadInstance = false;
 
 bool RenderThread::hasInstance() {
@@ -159,19 +64,15 @@
     return *sInstance;
 }
 
-RenderThread::RenderThread() : Thread(true)
-        , mNextWakeup(LLONG_MAX)
+RenderThread::RenderThread() : ThreadBase()
         , mDisplayEventReceiver(nullptr)
         , mVsyncRequested(false)
         , mFrameCallbackTaskPending(false)
-        , mFrameCallbackTask(nullptr)
         , mRenderState(nullptr)
         , mEglManager(nullptr)
         , mVkManager(nullptr) {
     Properties::load();
-    mFrameCallbackTask = new DispatchFrameCallbacks(this);
-    mLooper = new Looper(false);
-    run("RenderThread");
+    start("RenderThread");
 }
 
 RenderThread::~RenderThread() {
@@ -321,7 +222,9 @@
             ATRACE_NAME("queue mFrameCallbackTask");
             mFrameCallbackTaskPending = true;
             nsecs_t runAt = (vsyncEvent + DISPATCH_FRAME_CALLBACKS_DELAY);
-            queueAt(mFrameCallbackTask, runAt);
+            queue().postAt(runAt, [this]() {
+                dispatchFrameCallbacks();
+            });
         }
     }
 }
@@ -356,35 +259,9 @@
     setpriority(PRIO_PROCESS, 0, PRIORITY_DISPLAY);
     initThreadLocals();
 
-    int timeoutMillis = -1;
-    for (;;) {
-        int result = mLooper->pollOnce(timeoutMillis);
-        LOG_ALWAYS_FATAL_IF(result == Looper::POLL_ERROR,
-                "RenderThread Looper POLL_ERROR!");
-
-        nsecs_t nextWakeup;
-        {
-            FatVector<RenderTask*, 10> workQueue;
-            // Process our queue, if we have anything. By first acquiring
-            // all the pending events then processing them we avoid vsync
-            // starvation if more tasks are queued while we are processing tasks.
-            while (RenderTask* task = nextTask(&nextWakeup)) {
-                workQueue.push_back(task);
-            }
-            for (auto task : workQueue) {
-                task->run();
-                // task may have deleted itself, do not reference it again
-            }
-        }
-        if (nextWakeup == LLONG_MAX) {
-            timeoutMillis = -1;
-        } else {
-            nsecs_t timeoutNanos = nextWakeup - systemTime(SYSTEM_TIME_MONOTONIC);
-            timeoutMillis = nanoseconds_to_milliseconds(timeoutNanos);
-            if (timeoutMillis < 0) {
-                timeoutMillis = 0;
-            }
-        }
+    while (true) {
+        waitForWork();
+        processQueue();
 
         if (mPendingRegistrationFrameCallbacks.size() && !mFrameCallbackTaskPending) {
             drainDisplayEventQueue();
@@ -406,46 +283,6 @@
     return false;
 }
 
-void RenderThread::queue(RenderTask* task) {
-    AutoMutex _lock(mLock);
-    mQueue.queue(task);
-    if (mNextWakeup && task->mRunAt < mNextWakeup) {
-        mNextWakeup = 0;
-        mLooper->wake();
-    }
-}
-
-void RenderThread::queueAndWait(RenderTask* task) {
-    // These need to be local to the thread to avoid the Condition
-    // signaling the wrong thread. The easiest way to achieve that is to just
-    // make this on the stack, although that has a slight cost to it
-    Mutex mutex;
-    Condition condition;
-    SignalingRenderTask syncTask(task, &mutex, &condition);
-
-    AutoMutex _lock(mutex);
-    queue(&syncTask);
-    while (!syncTask.hasRun()) {
-        condition.wait(mutex);
-    }
-}
-
-void RenderThread::queueAtFront(RenderTask* task) {
-    AutoMutex _lock(mLock);
-    mQueue.queueAtFront(task);
-    mLooper->wake();
-}
-
-void RenderThread::queueAt(RenderTask* task, nsecs_t runAtNs) {
-    task->mRunAt = runAtNs;
-    queue(task);
-}
-
-void RenderThread::remove(RenderTask* task) {
-    AutoMutex _lock(mLock);
-    mQueue.remove(task);
-}
-
 void RenderThread::postFrameCallback(IFrameCallback* callback) {
     mPendingRegistrationFrameCallbacks.insert(callback);
 }
@@ -463,26 +300,6 @@
     }
 }
 
-RenderTask* RenderThread::nextTask(nsecs_t* nextWakeup) {
-    AutoMutex _lock(mLock);
-    RenderTask* next = mQueue.peek();
-    if (!next) {
-        mNextWakeup = LLONG_MAX;
-    } else {
-        mNextWakeup = next->mRunAt;
-        // Most tasks won't be delayed, so avoid unnecessary systemTime() calls
-        if (next->mRunAt <= 0 || next->mRunAt <= systemTime(SYSTEM_TIME_MONOTONIC)) {
-            next = mQueue.next();
-        } else {
-            next = nullptr;
-        }
-    }
-    if (nextWakeup) {
-        *nextWakeup = mNextWakeup;
-    }
-    return next;
-}
-
 sk_sp<Bitmap> RenderThread::allocateHardwareBitmap(SkBitmap& skBitmap) {
     auto renderType = Properties::getRenderPipelineType();
     switch (renderType) {