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 #ifndef INCLUDE_PERFETTO_EXT_BASE_THREADING_THREAD_POOL_H_
18 #define INCLUDE_PERFETTO_EXT_BASE_THREADING_THREAD_POOL_H_
19 
20 #include <condition_variable>
21 #include <functional>
22 #include <list>
23 #include <mutex>
24 #include <optional>
25 #include <thread>
26 #include <vector>
27 
28 #include "perfetto/base/task_runner.h"
29 
30 namespace perfetto {
31 namespace base {
32 
33 // Bounded thread pool designed for CPU-bound tasks.
34 //
35 // This is a classic bounded thread pool designed for running jobs which fully
36 // occupy the CPU without blocking. IO bound tasks which block for long periods
37 // of times will cause starvation for any other tasks which are waiting.
38 // IO-heavy tasks should use base::TaskRunner and async-IO instead of using this
39 // class.
40 //
41 // Threads are created when the thread pool is created and persist for the
42 // lifetime of the ThreadPool. No new threads are created after construction.
43 // When the ThreadPool is destroyed, any active tasks are completed and every
44 // thread joined before returning from the destructor.
45 //
46 // Tasks are executed in a FIFO order without any notion of priority. If a
47 // thread in the pool is free, it will be used to execute the task immediately.
48 // Otherwise, it will be queued for execution when any thread becomes available.
49 class ThreadPool {
50  public:
51   // Initializes this thread_pool |thread_count| threads.
52   explicit ThreadPool(uint32_t thread_count);
53   ~ThreadPool();
54 
55   // Submits a task for execution by any thread in this thread pool.
56   //
57   // This task should not block for IO as this can cause starvation.
58   void PostTask(std::function<void()>);
59 
60  private:
61   void RunThreadLoop();
62 
63   ThreadPool(ThreadPool&&) = delete;
64   ThreadPool& operator=(ThreadPool&&) = delete;
65 
66   // Start of mutex protected members.
67   std::mutex mutex_;
68   std::list<std::function<void()>> pending_tasks_;
69   std::condition_variable thread_waiter_;
70   uint32_t thread_waiting_count_ = 0;
71   bool quit_ = false;
72   // End of mutex protected members.
73 
74   std::vector<std::thread> threads_;
75 };
76 
77 }  // namespace base
78 }  // namespace perfetto
79 
80 #endif  // INCLUDE_PERFETTO_EXT_BASE_THREADING_THREAD_POOL_H_
81