1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef HWUI_THREADBASE_H
18 #define HWUI_THREADBASE_H
19 
20 #include "WorkQueue.h"
21 #include "utils/Macros.h"
22 
23 #include <utils/Looper.h>
24 #include <utils/Thread.h>
25 
26 #include <algorithm>
27 
28 namespace android::uirenderer {
29 
30 class ThreadBase : public Thread {
31     PREVENT_COPY_AND_ASSIGN(ThreadBase);
32 
33 public:
ThreadBase()34     ThreadBase()
35             : Thread(false)
36             , mLooper(new Looper(false))
37             , mQueue([this]() { mLooper->wake(); }, mLock) {}
38 
queue()39     WorkQueue& queue() { return mQueue; }
40 
requestExit()41     void requestExit() {
42         Thread::requestExit();
43         mLooper->wake();
44     }
45 
46     void start(const char* name = "ThreadBase") { Thread::run(name); }
47 
join()48     void join() { Thread::join(); }
49 
isRunning()50     bool isRunning() const { return Thread::isRunning(); }
51 
52 protected:
waitForWork()53     void waitForWork() {
54         nsecs_t nextWakeup;
55         {
56             std::unique_lock lock{mLock};
57             nextWakeup = mQueue.nextWakeup(lock);
58         }
59         int timeout = -1;
60         if (nextWakeup < std::numeric_limits<nsecs_t>::max()) {
61             timeout = ns2ms(nextWakeup - WorkQueue::clock::now());
62             if (timeout < 0) timeout = 0;
63         }
64         int result = mLooper->pollOnce(timeout);
65         LOG_ALWAYS_FATAL_IF(result == Looper::POLL_ERROR, "RenderThread Looper POLL_ERROR!");
66     }
67 
processQueue()68     void processQueue() { mQueue.process(); }
69 
threadLoop()70     virtual bool threadLoop() override {
71         Looper::setForThread(mLooper);
72         while (!exitPending()) {
73             waitForWork();
74             processQueue();
75         }
76         Looper::setForThread(nullptr);
77         return false;
78     }
79 
80     sp<Looper> mLooper;
81 
82 private:
83     WorkQueue mQueue;
84     std::mutex mLock;
85 };
86 
87 }  // namespace android::uirenderer
88 
89 #endif  // HWUI_THREADBASE_H
90