• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     std::mutex mLock;
33     std::vector<int> tids(THREAD_COUNT);
34     std::vector<std::condition_variable> tidConditionVars(THREAD_COUNT);
35 
36     // Create 2 workers
37     for (int i = 0; i < THREAD_COUNT; i++) {
38         std::thread worker([pool, i, &mLock, &tids, &tidConditionVars] {
39             {
40                 std::array<char, 20> name{"hwuiTask"};
41                 snprintf(name.data(), name.size(), "hwuiTask%d", i);
42                 auto self = pthread_self();
43                 pthread_setname_np(self, name.data());
44                 {
45                     std::unique_lock lock(mLock);
46                     tids[i] = pthread_gettid_np(self);
47                     tidConditionVars[i].notify_one();
48                 }
49                 setpriority(PRIO_PROCESS, 0, PRIORITY_FOREGROUND);
50                 auto startHook = renderthread::RenderThread::getOnStartHook();
51                 if (startHook) {
52                     startHook(name.data());
53                 }
54             }
55             pool->workerLoop();
56         });
57         worker.detach();
58     }
59     {
60         std::unique_lock lock(mLock);
61         for (int i = 0; i < THREAD_COUNT; i++) {
62             while (!tids[i]) {
63                 tidConditionVars[i].wait(lock);
64             }
65         }
66     }
67     mWorkerThreadIds = std::move(tids);
68 }
69 
instance()70 CommonPool& CommonPool::instance() {
71     static CommonPool pool;
72     return pool;
73 }
74 
post(Task && task)75 void CommonPool::post(Task&& task) {
76     instance().enqueue(std::move(task));
77 }
78 
getThreadIds()79 std::vector<int> CommonPool::getThreadIds() {
80     return instance().mWorkerThreadIds;
81 }
82 
enqueue(Task && task)83 void CommonPool::enqueue(Task&& task) {
84     std::unique_lock lock(mLock);
85     while (!mWorkQueue.hasSpace()) {
86         lock.unlock();
87         usleep(100);
88         lock.lock();
89     }
90     mWorkQueue.push(std::move(task));
91     if (mWaitingThreads == THREAD_COUNT || (mWaitingThreads > 0 && mWorkQueue.size() > 1)) {
92         mCondition.notify_one();
93     }
94 }
95 
workerLoop()96 void CommonPool::workerLoop() {
97     std::unique_lock lock(mLock);
98     while (true) {
99         if (!mWorkQueue.hasWork()) {
100             mWaitingThreads++;
101             mCondition.wait(lock);
102             mWaitingThreads--;
103         }
104         // Need to double-check that work is still available now that we have the lock
105         // It may have already been grabbed by a different thread
106         while (mWorkQueue.hasWork()) {
107             auto work = mWorkQueue.pop();
108             lock.unlock();
109             work();
110             lock.lock();
111         }
112     }
113 }
114 
waitForIdle()115 void CommonPool::waitForIdle() {
116     instance().doWaitForIdle();
117 }
118 
doWaitForIdle()119 void CommonPool::doWaitForIdle() {
120     std::unique_lock lock(mLock);
121     while (mWaitingThreads != THREAD_COUNT) {
122         lock.unlock();
123         usleep(100);
124         lock.lock();
125     }
126 }
127 
128 }  // namespace uirenderer
129 }  // namespace android
130