1 // Copyright 2023 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_WORKER_DELEGATE_H_ 6 #define BASE_TASK_THREAD_POOL_THREAD_GROUP_WORKER_DELEGATE_H_ 7 8 #include <optional> 9 10 #include "base/metrics/histogram_macros.h" 11 #include "base/task/task_traits.h" 12 #include "base/task/thread_pool/thread_group.h" 13 #include "base/task/thread_pool/worker_thread.h" 14 #include "base/threading/scoped_blocking_call.h" 15 #include "base/threading/scoped_blocking_call_internal.h" 16 #include "base/threading/thread_checker.h" 17 18 namespace base::internal { 19 20 // This class is not a WorkerThread::Delegate, instead implementing 21 // functionality which is common to all WorkerThread::Delegates present in a 22 // ThreadGroup. 23 class ThreadGroup::ThreadGroupWorkerDelegate : public BlockingObserver { 24 public: 25 explicit ThreadGroupWorkerDelegate(TrackedRef<ThreadGroup> outer, 26 bool is_excess); 27 ThreadGroupWorkerDelegate(const ThreadGroupWorkerDelegate&) = delete; 28 ThreadGroupWorkerDelegate& operator=(const ThreadGroupWorkerDelegate&) = 29 delete; 30 31 ~ThreadGroupWorkerDelegate() override; 32 33 TimeDelta ThreadPoolSleepTimeout(); 34 35 // BlockingObserver: 36 void BlockingStarted(BlockingType blocking_type) override; 37 void BlockingTypeUpgraded() override; 38 void BlockingEnded() override; 39 40 // Notifies the worker of shutdown, possibly marking the running task as 41 // MAY_BLOCK. 42 void OnShutdownStartedLockRequired(BaseScopedCommandsExecutor* executor) 43 EXCLUSIVE_LOCKS_REQUIRED(outer_->lock_); 44 45 // Increments max [best effort] tasks iff this worker has been within a 46 // ScopedBlockingCall for more than |may_block_threshold|. 47 void MaybeIncrementMaxTasksLockRequired() 48 EXCLUSIVE_LOCKS_REQUIRED(outer_->lock_); 49 50 // Increments max [best effort] tasks. 51 void IncrementMaxTasksLockRequired() EXCLUSIVE_LOCKS_REQUIRED(outer_->lock_); 52 current_task_priority_lock_required()53 TaskPriority current_task_priority_lock_required() const 54 EXCLUSIVE_LOCKS_REQUIRED(outer_->lock_) { 55 return *read_any().current_task_priority; 56 } 57 58 // Exposed for AnnotateAcquiredLockAlias. lock()59 const CheckedLock& lock() const LOCK_RETURNED(outer_->lock_) { 60 return outer_->lock_; 61 } 62 63 protected: 64 // Returns true if |worker| is allowed to cleanup and remove itself from the 65 // thread group. Called from GetWork() when no work is available. 66 virtual bool CanCleanupLockRequired(const WorkerThread* worker) 67 EXCLUSIVE_LOCKS_REQUIRED(outer_->lock_) = 0; 68 69 // Returns true iff the worker can get work. Cleans up the worker or puts it 70 // on the idle set if it can't get work. 71 virtual bool CanGetWorkLockRequired(BaseScopedCommandsExecutor* executor, 72 WorkerThread* worker) 73 EXCLUSIVE_LOCKS_REQUIRED(outer_->lock_) = 0; 74 75 RegisteredTaskSource GetWorkLockRequired(BaseScopedCommandsExecutor* executor, 76 WorkerThread* worker) 77 EXCLUSIVE_LOCKS_REQUIRED(outer_->lock_); 78 79 // Calls cleanup on |worker| and removes it from the thread group. Called from 80 // GetWork() when no work is available and CanCleanupLockRequired() returns 81 // true. 82 virtual void CleanupLockRequired(BaseScopedCommandsExecutor* executor, 83 WorkerThread* worker) 84 EXCLUSIVE_LOCKS_REQUIRED(outer_->lock_) = 0; 85 86 // Called in GetWork() when a worker becomes idle. 87 virtual void OnWorkerBecomesIdleLockRequired( 88 BaseScopedCommandsExecutor* executor, 89 WorkerThread* worker) EXCLUSIVE_LOCKS_REQUIRED(outer_->lock_) = 0; 90 91 // See worker_thread.h for documentation. 92 void OnMainEntryImpl(WorkerThread* worker); 93 void RecordUnnecessaryWakeupImpl(); 94 95 // Only used in DCHECKs. 96 template <typename Worker> ContainsWorker(const std::vector<scoped_refptr<Worker>> & workers,const WorkerThread * worker)97 bool ContainsWorker(const std::vector<scoped_refptr<Worker>>& workers, 98 const WorkerThread* worker) { 99 auto it = ranges::find_if( 100 workers, 101 [worker](const scoped_refptr<Worker>& i) { return i.get() == worker; }); 102 return it != workers.end(); 103 } 104 105 // Accessed only from the worker thread. 106 struct WorkerOnly { 107 WorkerOnly(); 108 ~WorkerOnly(); 109 // Associated WorkerThread, if any, initialized in OnMainEntry(). 110 raw_ptr<WorkerThread> worker_thread_; 111 112 #if BUILDFLAG(IS_WIN) 113 std::unique_ptr<win::ScopedWindowsThreadEnvironment> win_thread_environment; 114 #endif // BUILDFLAG(IS_WIN) 115 } worker_only_; 116 117 // Writes from the worker thread protected by |outer_->lock_|. Reads from any 118 // thread, protected by |outer_->lock_| when not on the worker thread. 119 struct WriteWorkerReadAny { 120 // The priority of the task the worker is currently running if any. 121 std::optional<TaskPriority> current_task_priority; 122 // The shutdown behavior of the task the worker is currently running if any. 123 std::optional<TaskShutdownBehavior> current_shutdown_behavior; 124 125 // Time when MayBlockScopeEntered() was last called. Reset when 126 // BlockingScopeExited() is called. 127 TimeTicks blocking_start_time; 128 129 // Whether the worker is currently running a task (i.e. GetWork() has 130 // returned a non-empty task source and DidProcessTask() hasn't been called 131 // yet). is_running_taskWriteWorkerReadAny132 bool is_running_task() const { return !!current_shutdown_behavior; } 133 } write_worker_read_any_; 134 worker_only()135 WorkerOnly& worker_only() { 136 DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_); 137 return worker_only_; 138 } 139 write_worker()140 WriteWorkerReadAny& write_worker() EXCLUSIVE_LOCKS_REQUIRED(outer_->lock_) { 141 DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_); 142 return write_worker_read_any_; 143 } 144 read_any()145 const WriteWorkerReadAny& read_any() const 146 EXCLUSIVE_LOCKS_REQUIRED(outer_->lock_) { 147 return write_worker_read_any_; 148 } 149 read_worker()150 const WriteWorkerReadAny& read_worker() const { 151 DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_); 152 return write_worker_read_any_; 153 } 154 155 const TrackedRef<ThreadGroup> outer_; 156 157 // Whether the worker is in excess. This must be decided at worker creation 158 // time to prevent unnecessarily discarding TLS state, as well as any behavior 159 // the OS has learned about a given thread. 160 const bool is_excess_; 161 162 // Whether |outer_->max_tasks_|/|outer_->max_best_effort_tasks_| were 163 // incremented due to a ScopedBlockingCall on the thread. 164 bool incremented_max_tasks_since_blocked_ GUARDED_BY(outer_->lock_) = false; 165 bool incremented_max_best_effort_tasks_since_blocked_ 166 GUARDED_BY(outer_->lock_) = false; 167 // Whether |outer_->max_tasks_| and |outer_->max_best_effort_tasks_| was 168 // incremented due to running CONTINUE_ON_SHUTDOWN on the thread during 169 // shutdown. 170 bool incremented_max_tasks_for_shutdown_ GUARDED_BY(outer_->lock_) = false; 171 172 // Verifies that specific calls are always made from the worker thread. 173 THREAD_CHECKER(worker_thread_checker_); 174 }; 175 176 } // namespace base::internal 177 178 #endif // BASE_TASK_THREAD_POOL_THREAD_GROUP_WORKER_DELEGATE_H_ 179