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