1 /* 2 * Copyright (C) 2023 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 "perfetto/ext/base/threading/thread_pool.h" 18 #include <mutex> 19 #include <thread> 20 21 namespace perfetto { 22 namespace base { 23 ThreadPool(uint32_t thread_count)24ThreadPool::ThreadPool(uint32_t thread_count) { 25 for (uint32_t i = 0; i < thread_count; ++i) { 26 threads_.emplace_back(std::bind(&ThreadPool::RunThreadLoop, this)); 27 } 28 } 29 ~ThreadPool()30ThreadPool::~ThreadPool() { 31 { 32 std::lock_guard<std::mutex> guard(mutex_); 33 quit_ = true; 34 } 35 thread_waiter_.notify_all(); 36 for (auto& thread : threads_) { 37 thread.join(); 38 } 39 } 40 PostTask(std::function<void ()> fn)41void ThreadPool::PostTask(std::function<void()> fn) { 42 std::lock_guard<std::mutex> guard(mutex_); 43 pending_tasks_.emplace_back(std::move(fn)); 44 if (thread_waiting_count_ == 0) { 45 return; 46 } 47 thread_waiter_.notify_one(); 48 } 49 RunThreadLoop()50void ThreadPool::RunThreadLoop() PERFETTO_NO_THREAD_SAFETY_ANALYSIS { 51 // 'std::unique_lock' lock doesn't work well with thread annotations 52 // (see https://github.com/llvm/llvm-project/issues/63239), 53 // so we suppress thread safety static analysis for this method. 54 for (;;) { 55 std::function<void()> fn; 56 { 57 std::unique_lock<std::mutex> guard(mutex_); 58 if (quit_) { 59 return; 60 } 61 if (pending_tasks_.empty()) { 62 thread_waiting_count_++; 63 thread_waiter_.wait(guard, 64 [this]() PERFETTO_EXCLUSIVE_LOCKS_REQUIRED(mutex_) { 65 return quit_ || !pending_tasks_.empty(); 66 }); 67 thread_waiting_count_--; 68 continue; 69 } 70 fn = std::move(pending_tasks_.front()); 71 pending_tasks_.pop_front(); 72 } 73 fn(); 74 } 75 } 76 77 } // namespace base 78 } // namespace perfetto 79