| /* | |
| * Copyright (C) 2019 The Android Open Source Project | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| #include "CommonPool.h" | |
| #include <utils/Trace.h> | |
| #include <array> | |
| namespace android { | |
| namespace uirenderer { | |
| CommonPool::CommonPool() : CommonPoolBase() { | |
| ATRACE_CALL(); | |
| CommonPool* pool = this; | |
| std::mutex mLock; | |
| std::vector<int> tids(THREAD_COUNT); | |
| std::vector<std::condition_variable> tidConditionVars(THREAD_COUNT); | |
| // Create 2 workers | |
| for (int i = 0; i < THREAD_COUNT; i++) { | |
| std::thread worker([pool, i, &mLock, &tids, &tidConditionVars] { | |
| pool->setupThread(i, mLock, tids, tidConditionVars); | |
| pool->workerLoop(); | |
| }); | |
| worker.detach(); | |
| } | |
| { | |
| std::unique_lock lock(mLock); | |
| for (int i = 0; i < THREAD_COUNT; i++) { | |
| while (!tids[i]) { | |
| tidConditionVars[i].wait(lock); | |
| } | |
| } | |
| } | |
| if (pool->supportsTid()) { | |
| mWorkerThreadIds = std::move(tids); | |
| } | |
| } | |
| CommonPool::~CommonPool() { | |
| LOG_ALWAYS_FATAL("CommonPool can't be stopped"); | |
| } | |
| CommonPool& CommonPool::instance() { | |
| static CommonPool* pool = new CommonPool(); | |
| return *pool; | |
| } | |
| void CommonPool::post(Task&& task) { | |
| instance().enqueue(std::move(task)); | |
| } | |
| std::vector<int> CommonPool::getThreadIds() { | |
| return instance().mWorkerThreadIds; | |
| } | |
| void CommonPool::enqueue(Task&& task) { | |
| std::unique_lock lock(mLock); | |
| while (!mWorkQueue.hasSpace()) { | |
| lock.unlock(); | |
| usleep(100); | |
| lock.lock(); | |
| } | |
| mWorkQueue.push(std::move(task)); | |
| if (mWaitingThreads == THREAD_COUNT || (mWaitingThreads > 0 && mWorkQueue.size() > 1)) { | |
| mCondition.notify_one(); | |
| } | |
| } | |
| void CommonPool::workerLoop() { | |
| std::unique_lock lock(mLock); | |
| while (true) { | |
| if (!mWorkQueue.hasWork()) { | |
| mWaitingThreads++; | |
| mCondition.wait(lock); | |
| mWaitingThreads--; | |
| } | |
| // Need to double-check that work is still available now that we have the lock | |
| // It may have already been grabbed by a different thread | |
| while (mWorkQueue.hasWork()) { | |
| auto work = mWorkQueue.pop(); | |
| lock.unlock(); | |
| work(); | |
| lock.lock(); | |
| } | |
| } | |
| } | |
| void CommonPool::waitForIdle() { | |
| instance().doWaitForIdle(); | |
| } | |
| void CommonPool::doWaitForIdle() { | |
| std::unique_lock lock(mLock); | |
| while (mWaitingThreads != THREAD_COUNT) { | |
| lock.unlock(); | |
| usleep(100); | |
| lock.lock(); | |
| } | |
| } | |
| } // namespace uirenderer | |
| } // namespace android |