/* * 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 #include #include "renderthread/RenderThread.h" #include namespace android { namespace uirenderer { CommonPool::CommonPool() { ATRACE_CALL(); CommonPool* pool = this; // Create 2 workers for (int i = 0; i < THREAD_COUNT; i++) { std::thread worker([pool, i] { { std::array name{"hwuiTask"}; snprintf(name.data(), name.size(), "hwuiTask%d", i); auto self = pthread_self(); pthread_setname_np(self, name.data()); setpriority(PRIO_PROCESS, 0, PRIORITY_FOREGROUND); auto startHook = renderthread::RenderThread::getOnStartHook(); if (startHook) { startHook(name.data()); } } pool->workerLoop(); }); worker.detach(); } } CommonPool& CommonPool::instance() { static CommonPool pool; return pool; } void CommonPool::post(Task&& task) { instance().enqueue(std::move(task)); } 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