1 // Copyright 2016 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef BASE_TASK_THREAD_POOL_THREAD_GROUP_IMPL_H_ 6 #define BASE_TASK_THREAD_POOL_THREAD_GROUP_IMPL_H_ 7 8 #include <optional> 9 #include <string_view> 10 #include <vector> 11 12 #include "base/base_export.h" 13 #include "base/gtest_prod_util.h" 14 #include "base/synchronization/condition_variable.h" 15 #include "base/synchronization/waitable_event.h" 16 #include "base/task/thread_pool/task_source.h" 17 #include "base/task/thread_pool/thread_group.h" 18 #include "base/task/thread_pool/tracked_ref.h" 19 #include "base/task/thread_pool/worker_thread.h" 20 #include "base/task/thread_pool/worker_thread_set.h" 21 #include "base/time/time.h" 22 23 namespace base { 24 25 class WorkerThreadObserver; 26 27 namespace internal { 28 29 class TaskTracker; 30 31 // A group of |WorkerThread|s that run |Task|s. 32 // 33 // The thread group doesn't create threads until Start() is called. Tasks can be 34 // posted at any time but will not run until after Start() is called. 35 // 36 // This class is thread-safe. 37 class BASE_EXPORT ThreadGroupImpl : public ThreadGroup { 38 public: 39 // Constructs a group without workers. 40 // 41 // |histogram_label| is used to label the thread group's histograms as 42 // "ThreadPool." + histogram_name + "." + |histogram_label| + extra suffixes. 43 // It must not be empty. |thread group_label| is used to label the thread 44 // group's threads, it must not be empty. |thread_type_hint| is the preferred 45 // thread type; the actual thread type depends on shutdown state and platform 46 // capabilities. |task_tracker| keeps track of tasks. 47 ThreadGroupImpl(std::string_view histogram_label, 48 std::string_view thread_group_label, 49 ThreadType thread_type_hint, 50 TrackedRef<TaskTracker> task_tracker, 51 TrackedRef<Delegate> delegate); 52 53 ThreadGroupImpl(const ThreadGroupImpl&) = delete; 54 ThreadGroupImpl& operator=(const ThreadGroupImpl&) = delete; 55 // Destroying a ThreadGroupImpl returned by Create() is not allowed 56 // in production; it is always leaked. In tests, it can only be destroyed 57 // after JoinForTesting() has returned. 58 ~ThreadGroupImpl() override; 59 60 // ThreadGroup: 61 void Start(size_t max_tasks, 62 size_t max_best_effort_tasks, 63 TimeDelta suggested_reclaim_time, 64 scoped_refptr<SingleThreadTaskRunner> service_thread_task_runner, 65 WorkerThreadObserver* worker_thread_observer, 66 WorkerEnvironment worker_environment, 67 bool synchronous_thread_start_for_testing = false, 68 std::optional<TimeDelta> may_block_threshold = 69 std::optional<TimeDelta>()) override; 70 void JoinForTesting() override; 71 void DidUpdateCanRunPolicy() override; 72 void OnShutdownStarted() override; 73 // Returns the number of workers that are idle (i.e. not running tasks). 74 size_t NumberOfIdleWorkersLockRequiredForTesting() const 75 EXCLUSIVE_LOCKS_REQUIRED(lock_) override; 76 77 private: 78 class ScopedCommandsExecutor; 79 class WorkerDelegate; 80 friend class WorkerDelegate; 81 82 // friend tests so that they can access |blocked_workers_poll_period| and 83 // may_block_threshold(), both in ThreadGroup. 84 friend class ThreadGroupImplBlockingTest; 85 friend class ThreadGroupImplMayBlockTest; 86 FRIEND_TEST_ALL_PREFIXES(ThreadGroupImplBlockingTest, 87 ThreadBlockUnblockPremature); 88 FRIEND_TEST_ALL_PREFIXES(ThreadGroupImplBlockingTest, 89 ThreadBlockUnblockPrematureBestEffort); 90 91 // ThreadGroup: 92 void UpdateSortKey(TaskSource::Transaction transaction) override; 93 void PushTaskSourceAndWakeUpWorkers( 94 RegisteredTaskSourceAndTransaction transaction_with_task_source) override; 95 void EnsureEnoughWorkersLockRequired(BaseScopedCommandsExecutor* executor) 96 override EXCLUSIVE_LOCKS_REQUIRED(lock_); 97 void ScheduleAdjustMaxTasks() override; 98 void AdjustMaxTasks() override; 99 100 // Creates a worker and schedules its start, if needed, to maintain one idle 101 // worker, |max_tasks_| permitting. 102 void MaintainAtLeastOneIdleWorkerLockRequired( 103 ScopedCommandsExecutor* executor) EXCLUSIVE_LOCKS_REQUIRED(lock_); 104 105 // Creates a worker, adds it to the thread group, schedules its start and 106 // returns it. Cannot be called before Start(). 107 scoped_refptr<WorkerThread> CreateAndRegisterWorkerLockRequired( 108 ScopedCommandsExecutor* executor) EXCLUSIVE_LOCKS_REQUIRED(lock_); 109 110 // Returns the number of workers that are awake (i.e. not on the idle set). 111 size_t GetNumAwakeWorkersLockRequired() const EXCLUSIVE_LOCKS_REQUIRED(lock_); 112 113 bool IsOnIdleSetLockRequired(WorkerThread* worker) const 114 EXCLUSIVE_LOCKS_REQUIRED(lock_); 115 116 size_t worker_sequence_num_ GUARDED_BY(lock_) = 0; 117 118 // Ordered set of idle workers; the order uses pointer comparison, this is 119 // arbitrary but stable. Initially, all workers are on this set. A worker is 120 // removed from the set before its WakeUp() function is called and when it 121 // receives work from GetWork() (a worker calls GetWork() when its sleep 122 // timeout expires, even if its WakeUp() method hasn't been called). A worker 123 // is inserted on this set when it receives nullptr from GetWork(). 124 WorkerThreadSet idle_workers_set_ GUARDED_BY(lock_); 125 126 // Ensures recently cleaned up workers (ref. 127 // WorkerDelegate::CleanupLockRequired()) had time to exit as 128 // they have a raw reference to |this| (and to TaskTracker) which can 129 // otherwise result in racy use-after-frees per no longer being part of 130 // |workers_| and hence not being explicitly joined in JoinForTesting(): 131 // https://crbug.com/810464. Uses AtomicRefCount to make its only public 132 // method thread-safe. 133 TrackedRefFactory<ThreadGroupImpl> tracked_ref_factory_; 134 }; 135 136 } // namespace internal 137 } // namespace base 138 139 #endif // BASE_TASK_THREAD_POOL_THREAD_GROUP_IMPL_H_ 140