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_TASK_TRACKER_H_ 6 #define BASE_TASK_THREAD_POOL_TASK_TRACKER_H_ 7 8 #include <atomic> 9 #include <functional> 10 #include <limits> 11 #include <memory> 12 #include <queue> 13 #include <string> 14 15 #include "base/atomicops.h" 16 #include "base/base_export.h" 17 #include "base/containers/circular_deque.h" 18 #include "base/functional/callback_forward.h" 19 #include "base/sequence_checker.h" 20 #include "base/strings/string_piece.h" 21 #include "base/synchronization/waitable_event.h" 22 #include "base/task/common/checked_lock.h" 23 #include "base/task/common/task_annotator.h" 24 #include "base/task/task_traits.h" 25 #include "base/task/thread_pool/task.h" 26 #include "base/task/thread_pool/task_source.h" 27 #include "base/task/thread_pool/tracked_ref.h" 28 #include "base/thread_annotations.h" 29 #include "base/threading/thread_local.h" 30 31 namespace base { 32 33 class ConditionVariable; 34 35 namespace internal { 36 37 // Determines which tasks are allowed to run. 38 enum class CanRunPolicy { 39 // All tasks are allowed to run. 40 kAll, 41 // Only USER_VISIBLE and USER_BLOCKING tasks are allowed to run. 42 kForegroundOnly, 43 // No tasks can run. 44 kNone, 45 }; 46 47 // TaskTracker enforces policies that determines whether: 48 // - A task can be pushed to a task source (WillPostTask). 49 // - A task source can be queued (WillQueueTaskSource). 50 // - Tasks for a given priority can run (CanRunPriority). 51 // - The next task in a queued task source can run (RunAndPopNextTask). 52 // TaskTracker also sets up the environment to run a task (RunAndPopNextTask) 53 // and records metrics and trace events. This class is thread-safe. 54 class BASE_EXPORT TaskTracker { 55 public: 56 TaskTracker(); 57 TaskTracker(const TaskTracker&) = delete; 58 TaskTracker& operator=(const TaskTracker&) = delete; 59 virtual ~TaskTracker(); 60 61 // Initiates shutdown. Once this is called, only BLOCK_SHUTDOWN tasks will 62 // start running (doesn't affect tasks that are already running). This can 63 // only be called once. 64 void StartShutdown(); 65 66 // Synchronously completes shutdown. StartShutdown() must be called first. 67 // Returns when: 68 // - All SKIP_ON_SHUTDOWN tasks that were already running have completed their 69 // execution. 70 // - All posted BLOCK_SHUTDOWN tasks have completed their execution. 71 // CONTINUE_ON_SHUTDOWN tasks still may be running after Shutdown returns. 72 // This can only be called once. 73 void CompleteShutdown(); 74 75 // Waits until there are no incomplete task sources. May be called in tests 76 // to validate that a condition is met after all task sources have run. 77 // 78 // Does not wait for delayed tasks. Waits for task sources posted from 79 // other threads during the call. Returns immediately when shutdown completes. 80 void FlushForTesting(); 81 82 // Returns and calls |flush_callback| when there are no incomplete undelayed 83 // tasks. |flush_callback| may be called back on any thread and should not 84 // perform a lot of work. May be used when additional work on the current 85 // thread needs to be performed during a flush. Only one 86 // FlushAsyncForTesting() may be pending at any given time. 87 void FlushAsyncForTesting(OnceClosure flush_callback); 88 89 // Sets the new CanRunPolicy policy, possibly affecting result of 90 // CanRunPriority(). The caller must wake up worker as appropriate so that 91 // tasks that are allowed to run by the new policy can be scheduled. 92 void SetCanRunPolicy(CanRunPolicy can_run_policy); 93 94 // Informs this TaskTracker that |task| with |shutdown_behavior| is about to 95 // be pushed to a task source (if non-delayed) or be added to the 96 // DelayedTaskManager (if delayed). Returns true if this operation is allowed 97 // (the operation should be performed if-and-only-if it is). This method may 98 // also modify metadata on |task| if desired. 99 // If this returns false, `task` must be leaked by the caller if deleting it 100 // on the current sequence may invoke sequence-affine code that belongs to 101 // another sequence. 102 bool WillPostTask(Task* task, TaskShutdownBehavior shutdown_behavior); 103 104 // Informs this TaskTracker that |task| that is about to be pushed to a task 105 // source with |priority|. Returns true if this operation is allowed (the 106 // operation should be performed if-and-only-if it is). 107 [[nodiscard]] bool WillPostTaskNow(const Task& task, 108 TaskPriority priority) const; 109 110 // Informs this TaskTracker that |task_source| is about to be queued. Returns 111 // a RegisteredTaskSource that should be queued if-and-only-if it evaluates to 112 // true. 113 RegisteredTaskSource RegisterTaskSource( 114 scoped_refptr<TaskSource> task_source); 115 116 // Returns true if a task with |priority| can run under to the current policy. 117 bool CanRunPriority(TaskPriority priority) const; 118 119 // Runs the next task in |task_source| unless the current shutdown state 120 // prevents that. Then, pops the task from |task_source| (even if it didn't 121 // run). Returns |task_source| if non-empty after popping a task from it 122 // (which indicates that it should be reenqueued). WillPostTask() must have 123 // allowed the task in front of |task_source| to be posted before this is 124 // called. 125 RegisteredTaskSource RunAndPopNextTask(RegisteredTaskSource task_source); 126 127 // Returns true once shutdown has started (StartShutdown() was called). 128 // Note: sequential consistency with the thread calling StartShutdown() isn't 129 // guaranteed by this call. 130 bool HasShutdownStarted() const; 131 132 // Returns true if shutdown has completed (StartShutdown() was called and 133 // no tasks are blocking shutdown). 134 bool IsShutdownComplete() const; 135 GetTrackedRef()136 TrackedRef<TaskTracker> GetTrackedRef() { 137 return tracked_ref_factory_.GetTrackedRef(); 138 } 139 140 void BeginFizzlingBlockShutdownTasks(); 141 void EndFizzlingBlockShutdownTasks(); 142 143 // Returns true if there are task sources that haven't completed their 144 // execution (still queued or in progress). If it returns false: the side- 145 // effects of all completed tasks are guaranteed to be visible to the caller. 146 bool HasIncompleteTaskSourcesForTesting() const; 147 148 protected: 149 // Runs and deletes |task|. |task| is deleted in the environment where it 150 // runs. |task_source| is the task source from which |task| was extracted. 151 // |traits| are the traits of |task_source|. An override is expected to call 152 // its parent's implementation but is free to perform extra work before and 153 // after doing so. 154 virtual void RunTask(Task task, 155 TaskSource* task_source, 156 const TaskTraits& traits); 157 158 // Allow a subclass to wait more interactively for any running shutdown tasks 159 // before blocking the thread. 160 virtual void BeginCompleteShutdown(base::WaitableEvent& shutdown_event); 161 162 // Asserts that FlushForTesting() is allowed to be called. Overridden in tests 163 // in situations where it is not. AssertFlushForTestingAllowed()164 virtual void AssertFlushForTestingAllowed() {} 165 166 private: 167 friend class RegisteredTaskSource; 168 class State; 169 170 void PerformShutdown(); 171 172 // Called before WillPostTask() informs the tracing system that a task has 173 // been posted. Updates |num_items_blocking_shutdown_| if necessary and 174 // returns true if the current shutdown state allows the task to be posted. 175 bool BeforeQueueTaskSource(TaskShutdownBehavior shutdown_behavior); 176 177 // Called before a task with |effective_shutdown_behavior| is run by 178 // RunTask(). Updates |num_items_blocking_shutdown_| if necessary and returns 179 // true if the current shutdown state allows the task to be run. 180 bool BeforeRunTask(TaskShutdownBehavior shutdown_behavior); 181 182 // Called after a task with |effective_shutdown_behavior| has been run by 183 // RunTask(). Updates |num_items_blocking_shutdown_| if necessary. 184 void AfterRunTask(TaskShutdownBehavior shutdown_behavior); 185 186 // Informs this TaskTracker that |task_source| won't be reenqueued and returns 187 // the underlying TaskSource. This is called before destroying a valid 188 // RegisteredTaskSource. Updates |num_items_blocking_shutdown_| if necessary. 189 scoped_refptr<TaskSource> UnregisterTaskSource( 190 scoped_refptr<TaskSource> task_source); 191 192 // Called when an item blocking shutdown finishes after shutdown has started. 193 void DecrementNumItemsBlockingShutdown(); 194 195 // Decrements the number of incomplete task sources and signals |flush_cv_| 196 // if it reaches zero. 197 void DecrementNumIncompleteTaskSources(); 198 199 // Invokes all |flush_callbacks_for_testing_| if any in a lock-safe manner. 200 void InvokeFlushCallbacksForTesting(); 201 202 // Dummy frames to allow identification of shutdown behavior in a stack trace. 203 void RunContinueOnShutdown(Task& task, 204 const TaskTraits& traits, 205 TaskSource* task_source, 206 const SequenceToken& token); 207 void RunSkipOnShutdown(Task& task, 208 const TaskTraits& traits, 209 TaskSource* task_source, 210 const SequenceToken& token); 211 void RunBlockShutdown(Task& task, 212 const TaskTraits& traits, 213 TaskSource* task_source, 214 const SequenceToken& token); 215 void RunTaskWithShutdownBehavior(Task& task, 216 const TaskTraits& traits, 217 TaskSource* task_source, 218 const SequenceToken& token); 219 220 NOT_TAIL_CALLED void RunTaskImpl(Task& task, 221 const TaskTraits& traits, 222 TaskSource* task_source, 223 const SequenceToken& token); 224 225 TaskAnnotator task_annotator_; 226 227 // Indicates whether logging information about TaskPriority::BEST_EFFORT tasks 228 // was enabled with a command line switch. 229 const bool has_log_best_effort_tasks_switch_; 230 231 // Number of tasks blocking shutdown and boolean indicating whether shutdown 232 // has started. |shutdown_lock_| should be held to access |shutdown_event_| 233 // when this indicates that shutdown has started because State doesn't provide 234 // memory barriers. It intentionally trades having to use a Lock on shutdown 235 // with not needing memory barriers at runtime. 236 const std::unique_ptr<State> state_; 237 238 // Number of task sources that haven't completed their execution. Is 239 // decremented with a memory barrier after the last task of a task source 240 // runs. Is accessed with an acquire memory barrier in FlushForTesting(). The 241 // memory barriers ensure that the memory written by flushed task sources is 242 // visible when FlushForTesting() returns. 243 std::atomic_int num_incomplete_task_sources_{0}; 244 245 // Global policy the determines result of CanRunPriority(). 246 std::atomic<CanRunPolicy> can_run_policy_; 247 248 // Lock associated with |flush_cv_|. Partially synchronizes access to 249 // |num_incomplete_task_sources_|. Full synchronization isn't needed 250 // because it's atomic, but synchronization is needed to coordinate waking and 251 // sleeping at the right time. Fully synchronizes access to 252 // |flush_callbacks_for_testing_|. 253 mutable CheckedLock flush_lock_; 254 255 // Signaled when |num_incomplete_task_sources_| is or reaches zero or when 256 // shutdown completes. 257 const std::unique_ptr<ConditionVariable> flush_cv_; 258 259 // All invoked, if any, when |num_incomplete_task_sources_| is zero or when 260 // shutdown completes. 261 base::circular_deque<OnceClosure> flush_callbacks_for_testing_ 262 GUARDED_BY(flush_lock_); 263 264 // Synchronizes access to shutdown related members below. 265 mutable CheckedLock shutdown_lock_; 266 267 // Event instantiated when shutdown starts and signaled when shutdown 268 // completes. 269 std::unique_ptr<WaitableEvent> shutdown_event_ GUARDED_BY(shutdown_lock_); 270 271 // Ensures all state (e.g. dangling cleaned up workers) is coalesced before 272 // destroying the TaskTracker (e.g. in test environments). 273 // Ref. https://crbug.com/827615. 274 TrackedRefFactory<TaskTracker> tracked_ref_factory_; 275 }; 276 277 } // namespace internal 278 } // namespace base 279 280 #endif // BASE_TASK_THREAD_POOL_TASK_TRACKER_H_ 281