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 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 52 CommonPool& CommonPool::instance() { 53 static CommonPool pool; 54 return pool; 55 } 56 57 void CommonPool::post(Task&& task) { 58 instance().enqueue(std::move(task)); 59 } 60 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 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 93 void CommonPool::waitForIdle() { 94 instance().doWaitForIdle(); 95 } 96 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