1 /*
2  * Copyright (C) 2019 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 #include "CommonPool.h"
18 
19 #include <sys/resource.h>
20 #include <utils/Trace.h>
21 #include "renderthread/RenderThread.h"
22 
23 #include <array>
24 
25 namespace android {
26 namespace uirenderer {
27 
CommonPool()28 CommonPool::CommonPool() {
29     ATRACE_CALL();
30 
31     CommonPool* pool = this;
32     // Create 2 workers
33     for (int i = 0; i < THREAD_COUNT; i++) {
34         std::thread worker([pool, i] {
35             {
36                 std::array<char, 20> name{"hwuiTask"};
37                 snprintf(name.data(), name.size(), "hwuiTask%d", i);
38                 auto self = pthread_self();
39                 pthread_setname_np(self, name.data());
40                 setpriority(PRIO_PROCESS, 0, PRIORITY_FOREGROUND);
41                 auto startHook = renderthread::RenderThread::getOnStartHook();
42                 if (startHook) {
43                     startHook(name.data());
44                 }
45             }
46             pool->workerLoop();
47         });
48         worker.detach();
49     }
50 }
51 
instance()52 CommonPool& CommonPool::instance() {
53     static CommonPool pool;
54     return pool;
55 }
56 
post(Task && task)57 void CommonPool::post(Task&& task) {
58     instance().enqueue(std::move(task));
59 }
60 
enqueue(Task && task)61 void CommonPool::enqueue(Task&& task) {
62     std::unique_lock lock(mLock);
63     while (!mWorkQueue.hasSpace()) {
64         lock.unlock();
65         usleep(100);
66         lock.lock();
67     }
68     mWorkQueue.push(std::move(task));
69     if (mWaitingThreads == THREAD_COUNT || (mWaitingThreads > 0 && mWorkQueue.size() > 1)) {
70         mCondition.notify_one();
71     }
72 }
73 
workerLoop()74 void CommonPool::workerLoop() {
75     std::unique_lock lock(mLock);
76     while (true) {
77         if (!mWorkQueue.hasWork()) {
78             mWaitingThreads++;
79             mCondition.wait(lock);
80             mWaitingThreads--;
81         }
82         // Need to double-check that work is still available now that we have the lock
83         // It may have already been grabbed by a different thread
84         while (mWorkQueue.hasWork()) {
85             auto work = mWorkQueue.pop();
86             lock.unlock();
87             work();
88             lock.lock();
89         }
90     }
91 }
92 
waitForIdle()93 void CommonPool::waitForIdle() {
94     instance().doWaitForIdle();
95 }
96 
doWaitForIdle()97 void CommonPool::doWaitForIdle() {
98     std::unique_lock lock(mLock);
99     while (mWaitingThreads != THREAD_COUNT) {
100         lock.unlock();
101         usleep(100);
102         lock.lock();
103     }
104 }
105 
106 }  // namespace uirenderer
107 }  // namespace android