xref: /aosp_15_r20/frameworks/base/libs/hwui/thread/CommonPool.cpp (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
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 <utils/Trace.h>
20 
21 #include <array>
22 
23 namespace android {
24 namespace uirenderer {
25 
CommonPool()26 CommonPool::CommonPool() : CommonPoolBase() {
27     ATRACE_CALL();
28 
29     CommonPool* pool = this;
30     std::mutex mLock;
31     std::vector<int> tids(THREAD_COUNT);
32     std::vector<std::condition_variable> tidConditionVars(THREAD_COUNT);
33 
34     // Create 2 workers
35     for (int i = 0; i < THREAD_COUNT; i++) {
36         std::thread worker([pool, i, &mLock, &tids, &tidConditionVars] {
37             pool->setupThread(i, mLock, tids, tidConditionVars);
38             pool->workerLoop();
39         });
40         worker.detach();
41     }
42     {
43         std::unique_lock lock(mLock);
44         for (int i = 0; i < THREAD_COUNT; i++) {
45             while (!tids[i]) {
46                 tidConditionVars[i].wait(lock);
47             }
48         }
49     }
50     if (pool->supportsTid()) {
51         mWorkerThreadIds = std::move(tids);
52     }
53 }
54 
instance()55 CommonPool& CommonPool::instance() {
56     static CommonPool pool;
57     return pool;
58 }
59 
post(Task && task)60 void CommonPool::post(Task&& task) {
61     instance().enqueue(std::move(task));
62 }
63 
getThreadIds()64 std::vector<int> CommonPool::getThreadIds() {
65     return instance().mWorkerThreadIds;
66 }
67 
enqueue(Task && task)68 void CommonPool::enqueue(Task&& task) {
69     std::unique_lock lock(mLock);
70     while (!mWorkQueue.hasSpace()) {
71         lock.unlock();
72         usleep(100);
73         lock.lock();
74     }
75     mWorkQueue.push(std::move(task));
76     if (mWaitingThreads == THREAD_COUNT || (mWaitingThreads > 0 && mWorkQueue.size() > 1)) {
77         mCondition.notify_one();
78     }
79 }
80 
workerLoop()81 void CommonPool::workerLoop() {
82     std::unique_lock lock(mLock);
83     while (!mIsStopping) {
84         if (!mWorkQueue.hasWork()) {
85             mWaitingThreads++;
86             mCondition.wait(lock);
87             mWaitingThreads--;
88         }
89         // Need to double-check that work is still available now that we have the lock
90         // It may have already been grabbed by a different thread
91         while (mWorkQueue.hasWork()) {
92             auto work = mWorkQueue.pop();
93             lock.unlock();
94             work();
95             lock.lock();
96         }
97     }
98 }
99 
waitForIdle()100 void CommonPool::waitForIdle() {
101     instance().doWaitForIdle();
102 }
103 
doWaitForIdle()104 void CommonPool::doWaitForIdle() {
105     std::unique_lock lock(mLock);
106     while (mWaitingThreads != THREAD_COUNT) {
107         lock.unlock();
108         usleep(100);
109         lock.lock();
110     }
111 }
112 
113 }  // namespace uirenderer
114 }  // namespace android
115