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_WORKER_THREAD_H_ 6 #define BASE_TASK_THREAD_POOL_WORKER_THREAD_H_ 7 8 #include <memory> 9 10 #include "base/base_export.h" 11 #include "base/compiler_specific.h" 12 #include "base/memory/raw_ptr.h" 13 #include "base/memory/ref_counted.h" 14 #include "base/synchronization/atomic_flag.h" 15 #include "base/synchronization/waitable_event.h" 16 #include "base/task/common/checked_lock.h" 17 #include "base/task/thread_pool/task_source.h" 18 #include "base/task/thread_pool/tracked_ref.h" 19 #include "base/thread_annotations.h" 20 #include "base/threading/platform_thread.h" 21 #include "base/time/time.h" 22 #include "build/build_config.h" 23 24 namespace base { 25 26 class WorkerThreadObserver; 27 28 namespace internal { 29 30 class TaskTracker; 31 32 // A worker that manages a single thread to run Tasks from TaskSources returned 33 // by a delegate. 34 // 35 // A WorkerThread starts out sleeping. It is woken up by a call to WakeUp(). 36 // After a wake-up, a WorkerThread runs Tasks from TaskSources returned by 37 // the GetWork() method of its delegate as long as it doesn't return nullptr. It 38 // also periodically checks with its TaskTracker whether shutdown has completed 39 // and exits when it has. 40 // 41 // This class is thread-safe. 42 class BASE_EXPORT WorkerThread : public RefCountedThreadSafe<WorkerThread>, 43 public PlatformThread::Delegate { 44 public: 45 // Labels this WorkerThread's association. This doesn't affect any logic 46 // but will add a stack frame labeling this thread for ease of stack trace 47 // identification. 48 enum class ThreadLabel { 49 POOLED, 50 SHARED, 51 DEDICATED, 52 #if BUILDFLAG(IS_WIN) 53 SHARED_COM, 54 DEDICATED_COM, 55 #endif // BUILDFLAG(IS_WIN) 56 }; 57 58 // Delegate interface for WorkerThread. All methods are called from the 59 // thread managed by the WorkerThread instance. 60 class BASE_EXPORT Delegate { 61 public: 62 virtual ~Delegate() = default; 63 64 // Returns the ThreadLabel the Delegate wants its WorkerThreads' stacks 65 // to be labeled with. 66 virtual ThreadLabel GetThreadLabel() const = 0; 67 68 // Called by |worker|'s thread when it enters its main function. 69 virtual void OnMainEntry(WorkerThread* worker) = 0; 70 71 // Called by |worker|'s thread to get a TaskSource from which to run a Task. 72 virtual RegisteredTaskSource GetWork(WorkerThread* worker) = 0; 73 74 // Called by the WorkerThread after it ran a Task. If the Task's 75 // TaskSource should be reenqueued, it is passed to |task_source|. 76 // Otherwise, |task_source| is nullptr. 77 virtual void DidProcessTask(RegisteredTaskSource task_source) = 0; 78 79 // Called to determine how long to sleep before the next call to GetWork(). 80 // GetWork() may be called before this timeout expires if the worker's 81 // WakeUp() method is called. 82 virtual TimeDelta GetSleepTimeout() = 0; 83 84 // Called by the WorkerThread's thread to wait for work. Override this 85 // method if the thread in question needs special handling to go to sleep. 86 // |wake_up_event| is a manually resettable event and is signaled on 87 // WorkerThread::WakeUp() 88 virtual void WaitForWork(WaitableEvent* wake_up_event); 89 90 // Called by |worker|'s thread right before the main function exits. The 91 // Delegate is free to release any associated resources in this call. It is 92 // guaranteed that WorkerThread won't access the Delegate or the 93 // TaskTracker after calling OnMainExit() on the Delegate. OnMainExit(WorkerThread * worker)94 virtual void OnMainExit(WorkerThread* worker) {} 95 96 // Called by a WorkerThread when it is woken up without any work being 97 // available for it to run. RecordUnnecessaryWakeup()98 virtual void RecordUnnecessaryWakeup() {} 99 100 static constexpr TimeDelta kPurgeThreadCacheIdleDelay = Seconds(1); 101 }; 102 103 // Creates a WorkerThread that runs Tasks from TaskSources returned by 104 // |delegate|. No actual thread will be created for this WorkerThread 105 // before Start() is called. |thread_type_hint| is the preferred thread type; 106 // the actual thread type depends on shutdown state and platform 107 // capabilities. |task_tracker| is used to handle shutdown behavior of Tasks. 108 // |sequence_num| is an index that helps identifying this WorkerThread. 109 // |predecessor_lock| is a lock that is allowed to be held when calling 110 // methods on this WorkerThread. |backward_compatibility| indicates 111 // whether backward compatibility is enabled. Either JoinForTesting() or 112 // Cleanup() must be called before releasing the last external reference. 113 WorkerThread(ThreadType thread_type_hint, 114 std::unique_ptr<Delegate> delegate, 115 TrackedRef<TaskTracker> task_tracker, 116 size_t sequence_num, 117 const CheckedLock* predecessor_lock = nullptr); 118 119 WorkerThread(const WorkerThread&) = delete; 120 WorkerThread& operator=(const WorkerThread&) = delete; 121 122 // Creates a thread to back the WorkerThread. The thread will be in a wait 123 // state pending a WakeUp() call. No thread will be created if Cleanup() was 124 // called. `io_thread_task_runner` is used to setup FileDescriptorWatcher on 125 // worker threads. `io_thread_task_runner` must refer to a Thread with 126 // MessgaePumpType::IO. If specified, |worker_thread_observer| will be 127 // notified when the worker enters and exits its main function. It must not be 128 // destroyed before JoinForTesting() has returned (must never be destroyed in 129 // production). Returns true on success. 130 bool Start(scoped_refptr<SingleThreadTaskRunner> io_thread_task_runner_, 131 WorkerThreadObserver* worker_thread_observer = nullptr); 132 133 // Wakes up this WorkerThread if it wasn't already awake. After this is 134 // called, this WorkerThread will run Tasks from TaskSources returned by 135 // the GetWork() method of its delegate until it returns nullptr. No-op if 136 // Start() wasn't called. DCHECKs if called after Start() has failed or after 137 // Cleanup() has been called. 138 void WakeUp(); 139 delegate()140 WorkerThread::Delegate* delegate() { return delegate_.get(); } 141 142 // Joins this WorkerThread. If a Task is already running, it will be 143 // allowed to complete its execution. This can only be called once. 144 // 145 // Note: A thread that detaches before JoinForTesting() is called may still be 146 // running after JoinForTesting() returns. However, it can't run tasks after 147 // JoinForTesting() returns. 148 void JoinForTesting(); 149 150 // Returns true if the worker is alive. 151 bool ThreadAliveForTesting() const; 152 153 // Makes a request to cleanup the worker. This may be called from any thread. 154 // The caller is expected to release its reference to this object after 155 // calling Cleanup(). Further method calls after Cleanup() returns are 156 // undefined. 157 // 158 // Expected Usage: 159 // scoped_refptr<WorkerThread> worker_ = /* Existing Worker */ 160 // worker_->Cleanup(); 161 // worker_ = nullptr; 162 void Cleanup(); 163 164 // Possibly updates the thread type to the appropriate type based on the 165 // thread type hint, current shutdown state, and platform capabilities. 166 // Must be called on the thread managed by |this|. 167 void MaybeUpdateThreadType(); 168 169 // Informs this WorkerThread about periods during which it is not being 170 // used. Thread-safe. 171 void BeginUnusedPeriod(); 172 void EndUnusedPeriod(); 173 // Returns the last time this WorkerThread was used. Returns a null time if 174 // this WorkerThread is currently in-use. Thread-safe. 175 TimeTicks GetLastUsedTime() const; 176 sequence_num()177 size_t sequence_num() const { return sequence_num_; } 178 179 private: 180 friend class RefCountedThreadSafe<WorkerThread>; 181 class Thread; 182 183 ~WorkerThread() override; 184 185 bool ShouldExit() const; 186 187 // Returns the thread type to use based on the thread type hint, current 188 // shutdown state, and platform capabilities. 189 ThreadType GetDesiredThreadType() const; 190 191 // Changes the thread type to |desired_thread_type|. Must be called on the 192 // thread managed by |this|. 193 void UpdateThreadType(ThreadType desired_thread_type); 194 195 // PlatformThread::Delegate: 196 void ThreadMain() override; 197 198 // Dummy frames to act as "RunLabeledWorker()" (see RunMain() below). Their 199 // impl is aliased to prevent compiler/linker from optimizing them out. 200 void RunPooledWorker(); 201 void RunBackgroundPooledWorker(); 202 void RunSharedWorker(); 203 void RunBackgroundSharedWorker(); 204 void RunDedicatedWorker(); 205 void RunBackgroundDedicatedWorker(); 206 #if BUILDFLAG(IS_WIN) 207 void RunSharedCOMWorker(); 208 void RunBackgroundSharedCOMWorker(); 209 void RunDedicatedCOMWorker(); 210 void RunBackgroundDedicatedCOMWorker(); 211 #endif // BUILDFLAG(IS_WIN) 212 213 // The real main, invoked through : 214 // ThreadMain() -> RunLabeledWorker() -> RunWorker(). 215 // "RunLabeledWorker()" is a dummy frame based on ThreadLabel+ThreadType 216 // and used to easily identify threads in stack traces. 217 NOT_TAIL_CALLED void RunWorker(); 218 219 // Self-reference to prevent destruction of |this| while the thread is alive. 220 // Set in Start() before creating the thread. Reset in ThreadMain() before the 221 // thread exits. No lock required because the first access occurs before the 222 // thread is created and the second access occurs on the thread. 223 scoped_refptr<WorkerThread> self_; 224 225 mutable CheckedLock thread_lock_; 226 227 // Handle for the thread managed by |this|. 228 PlatformThreadHandle thread_handle_ GUARDED_BY(thread_lock_); 229 230 // The last time this worker was used by its owner (e.g. to process work or 231 // stand as a required idle thread). 232 TimeTicks last_used_time_ GUARDED_BY(thread_lock_); 233 234 // Event to wake up the thread managed by |this|. 235 WaitableEvent wake_up_event_{WaitableEvent::ResetPolicy::AUTOMATIC, 236 WaitableEvent::InitialState::NOT_SIGNALED}; 237 238 // Whether the thread should exit. Set by Cleanup(). 239 AtomicFlag should_exit_; 240 241 const std::unique_ptr<Delegate> delegate_; 242 const TrackedRef<TaskTracker> task_tracker_; 243 244 // Optional observer notified when a worker enters and exits its main 245 // function. Set in Start() and never modified afterwards. 246 raw_ptr<WorkerThreadObserver> worker_thread_observer_ = nullptr; 247 248 // Desired thread type. 249 const ThreadType thread_type_hint_; 250 251 // Actual thread type. Can be different than |thread_type_hint_| 252 // depending on system capabilities and shutdown state. No lock required 253 // because all post-construction accesses occur on the thread. 254 ThreadType current_thread_type_; 255 256 // Set once JoinForTesting() has been called. 257 AtomicFlag join_called_for_testing_; 258 259 const size_t sequence_num_; 260 261 // Service thread task runner. 262 scoped_refptr<SingleThreadTaskRunner> io_thread_task_runner_; 263 }; 264 265 } // namespace internal 266 } // namespace base 267 268 #endif // BASE_TASK_THREAD_POOL_WORKER_THREAD_H_ 269