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