1 // Copyright 2018 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_SEQUENCE_MANAGER_TASK_QUEUE_H_ 6 #define BASE_TASK_SEQUENCE_MANAGER_TASK_QUEUE_H_ 7 8 #include "base/macros.h" 9 #include "base/memory/weak_ptr.h" 10 #include "base/message_loop/message_loop.h" 11 #include "base/optional.h" 12 #include "base/single_thread_task_runner.h" 13 #include "base/synchronization/lock.h" 14 #include "base/task/sequence_manager/lazy_now.h" 15 #include "base/task/sequence_manager/moveable_auto_lock.h" 16 #include "base/threading/platform_thread.h" 17 #include "base/time/time.h" 18 19 namespace base { 20 21 namespace trace_event { 22 class BlameContext; 23 } 24 25 namespace sequence_manager { 26 27 namespace internal { 28 class GracefulQueueShutdownHelper; 29 class SequenceManagerImpl; 30 class TaskQueueImpl; 31 } // namespace internal 32 33 class TimeDomain; 34 35 class BASE_EXPORT TaskQueue : public SingleThreadTaskRunner { 36 public: 37 class Observer { 38 public: 39 virtual ~Observer() = default; 40 41 // Notify observer that the time at which this queue wants to run 42 // the next task has changed. |next_wakeup| can be in the past 43 // (e.g. TimeTicks() can be used to notify about immediate work). 44 // Can be called on any thread 45 // All methods but SetObserver, SetTimeDomain and GetTimeDomain can be 46 // called on |queue|. 47 // 48 // TODO(altimin): Make it Optional<TimeTicks> to tell 49 // observer about cancellations. 50 virtual void OnQueueNextWakeUpChanged(TaskQueue* queue, 51 TimeTicks next_wake_up) = 0; 52 }; 53 54 // A wrapper around OnceClosure with additional metadata to be passed 55 // to PostTask and plumbed until PendingTask is created. 56 struct BASE_EXPORT PostedTask { 57 PostedTask(OnceClosure callback, 58 Location posted_from, 59 TimeDelta delay = TimeDelta(), 60 Nestable nestable = Nestable::kNestable, 61 int task_type = 0); 62 PostedTask(PostedTask&& move_from); 63 PostedTask(const PostedTask& copy_from) = delete; 64 ~PostedTask(); 65 66 OnceClosure callback; 67 Location posted_from; 68 TimeDelta delay; 69 Nestable nestable; 70 int task_type; 71 }; 72 73 // Prepare the task queue to get released. 74 // All tasks posted after this call will be discarded. 75 virtual void ShutdownTaskQueue(); 76 77 // TODO(scheduler-dev): Could we define a more clear list of priorities? 78 // See https://crbug.com/847858. 79 enum QueuePriority { 80 // Queues with control priority will run before any other queue, and will 81 // explicitly starve other queues. Typically this should only be used for 82 // private queues which perform control operations. 83 kControlPriority, 84 85 // The selector will prioritize highest over high, normal and low; and 86 // high over normal and low; and normal over low. However it will ensure 87 // neither of the lower priority queues can be completely starved by higher 88 // priority tasks. All three of these queues will always take priority over 89 // and can starve the best effort queue. 90 kHighestPriority, 91 92 kHighPriority, 93 94 // Queues with normal priority are the default. 95 kNormalPriority, 96 kLowPriority, 97 98 // Queues with best effort priority will only be run if all other queues are 99 // empty. They can be starved by the other queues. 100 kBestEffortPriority, 101 // Must be the last entry. 102 kQueuePriorityCount, 103 kFirstQueuePriority = kControlPriority, 104 }; 105 106 // Can be called on any thread. 107 static const char* PriorityToString(QueuePriority priority); 108 109 // Options for constructing a TaskQueue. 110 struct Spec { SpecSpec111 explicit Spec(const char* name) 112 : name(name), 113 should_monitor_quiescence(false), 114 time_domain(nullptr), 115 should_notify_observers(true) {} 116 SetShouldMonitorQuiescenceSpec117 Spec SetShouldMonitorQuiescence(bool should_monitor) { 118 should_monitor_quiescence = should_monitor; 119 return *this; 120 } 121 SetShouldNotifyObserversSpec122 Spec SetShouldNotifyObservers(bool run_observers) { 123 should_notify_observers = run_observers; 124 return *this; 125 } 126 SetTimeDomainSpec127 Spec SetTimeDomain(TimeDomain* domain) { 128 time_domain = domain; 129 return *this; 130 } 131 132 const char* name; 133 bool should_monitor_quiescence; 134 TimeDomain* time_domain; 135 bool should_notify_observers; 136 }; 137 138 // Interface to pass per-task metadata to RendererScheduler. 139 class BASE_EXPORT Task : public PendingTask { 140 public: 141 Task(PostedTask posted_task, TimeTicks desired_run_time); 142 task_type()143 int task_type() const { return task_type_; } 144 145 private: 146 int task_type_; 147 }; 148 149 // Information about task execution. 150 // 151 // Wall-time related methods (start_time, end_time, wall_duration) can be 152 // called only when |has_wall_time()| is true. 153 // Thread-time related mehtods (start_thread_time, end_thread_time, 154 // thread_duration) can be called only when |has_thread_time()| is true. 155 // 156 // start_* should be called after RecordTaskStart. 157 // end_* and *_duration should be called after RecordTaskEnd. 158 class BASE_EXPORT TaskTiming { 159 public: 160 TaskTiming(bool has_wall_time, bool has_thread_time); 161 has_wall_time()162 bool has_wall_time() const { return has_wall_time_; } has_thread_time()163 bool has_thread_time() const { return has_thread_time_; } 164 start_time()165 base::TimeTicks start_time() const { 166 DCHECK(has_wall_time()); 167 return start_time_; 168 } end_time()169 base::TimeTicks end_time() const { 170 DCHECK(has_wall_time()); 171 return end_time_; 172 } wall_duration()173 base::TimeDelta wall_duration() const { 174 DCHECK(has_wall_time()); 175 return end_time_ - start_time_; 176 } start_thread_time()177 base::ThreadTicks start_thread_time() const { 178 DCHECK(has_thread_time()); 179 return start_thread_time_; 180 } end_thread_time()181 base::ThreadTicks end_thread_time() const { 182 DCHECK(has_thread_time()); 183 return end_thread_time_; 184 } thread_duration()185 base::TimeDelta thread_duration() const { 186 DCHECK(has_thread_time()); 187 return end_thread_time_ - start_thread_time_; 188 } 189 190 void RecordTaskStart(LazyNow* now); 191 void RecordTaskEnd(LazyNow* now); 192 193 // Protected for tests. 194 protected: 195 bool has_wall_time_; 196 bool has_thread_time_; 197 198 base::TimeTicks start_time_; 199 base::TimeTicks end_time_; 200 base::ThreadTicks start_thread_time_; 201 base::ThreadTicks end_thread_time_; 202 }; 203 204 // An interface that lets the owner vote on whether or not the associated 205 // TaskQueue should be enabled. 206 class QueueEnabledVoter { 207 public: 208 QueueEnabledVoter() = default; 209 virtual ~QueueEnabledVoter() = default; 210 211 // Votes to enable or disable the associated TaskQueue. The TaskQueue will 212 // only be enabled if all the voters agree it should be enabled, or if there 213 // are no voters. 214 // NOTE this must be called on the thread the associated TaskQueue was 215 // created on. 216 virtual void SetQueueEnabled(bool enabled) = 0; 217 218 private: 219 DISALLOW_COPY_AND_ASSIGN(QueueEnabledVoter); 220 }; 221 222 // Returns an interface that allows the caller to vote on whether or not this 223 // TaskQueue is enabled. The TaskQueue will be enabled if there are no voters 224 // or if all agree it should be enabled. 225 // NOTE this must be called on the thread this TaskQueue was created by. 226 std::unique_ptr<QueueEnabledVoter> CreateQueueEnabledVoter(); 227 228 // NOTE this must be called on the thread this TaskQueue was created by. 229 bool IsQueueEnabled() const; 230 231 // Returns true if the queue is completely empty. 232 bool IsEmpty() const; 233 234 // Returns the number of pending tasks in the queue. 235 size_t GetNumberOfPendingTasks() const; 236 237 // Returns true if the queue has work that's ready to execute now. 238 // NOTE: this must be called on the thread this TaskQueue was created by. 239 bool HasTaskToRunImmediately() const; 240 241 // Returns requested run time of next scheduled wake-up for a delayed task 242 // which is not ready to run. If there are no such tasks (immediate tasks 243 // don't count) or the queue is disabled it returns nullopt. 244 // NOTE: this must be called on the thread this TaskQueue was created by. 245 Optional<TimeTicks> GetNextScheduledWakeUp(); 246 247 // Can be called on any thread. 248 virtual const char* GetName() const; 249 250 // Set the priority of the queue to |priority|. NOTE this must be called on 251 // the thread this TaskQueue was created by. 252 void SetQueuePriority(QueuePriority priority); 253 254 // Returns the current queue priority. 255 QueuePriority GetQueuePriority() const; 256 257 // These functions can only be called on the same thread that the task queue 258 // manager executes its tasks on. 259 void AddTaskObserver(MessageLoop::TaskObserver* task_observer); 260 void RemoveTaskObserver(MessageLoop::TaskObserver* task_observer); 261 262 // Set the blame context which is entered and left while executing tasks from 263 // this task queue. |blame_context| must be null or outlive this task queue. 264 // Must be called on the thread this TaskQueue was created by. 265 void SetBlameContext(trace_event::BlameContext* blame_context); 266 267 // Removes the task queue from the previous TimeDomain and adds it to 268 // |domain|. This is a moderately expensive operation. 269 void SetTimeDomain(TimeDomain* domain); 270 271 // Returns the queue's current TimeDomain. Can be called from any thread. 272 TimeDomain* GetTimeDomain() const; 273 274 enum class InsertFencePosition { 275 kNow, // Tasks posted on the queue up till this point further may run. 276 // All further tasks are blocked. 277 kBeginningOfTime, // No tasks posted on this queue may run. 278 }; 279 280 // Inserts a barrier into the task queue which prevents tasks with an enqueue 281 // order greater than the fence from running until either the fence has been 282 // removed or a subsequent fence has unblocked some tasks within the queue. 283 // Note: delayed tasks get their enqueue order set once their delay has 284 // expired, and non-delayed tasks get their enqueue order set when posted. 285 // 286 // Fences come in three flavours: 287 // - Regular (InsertFence(NOW)) - all tasks posted after this moment 288 // are blocked. 289 // - Fully blocking (InsertFence(kBeginningOfTime)) - all tasks including 290 // already posted are blocked. 291 // - Delayed (InsertFenceAt(timestamp)) - blocks all tasks posted after given 292 // point in time (must be in the future). 293 // 294 // Only one fence can be scheduled at a time. Inserting a new fence 295 // will automatically remove the previous one, regardless of fence type. 296 void InsertFence(InsertFencePosition position); 297 void InsertFenceAt(TimeTicks time); 298 299 // Removes any previously added fence and unblocks execution of any tasks 300 // blocked by it. 301 void RemoveFence(); 302 303 // Returns true if the queue has a fence but it isn't necessarily blocking 304 // execution of tasks (it may be the case if tasks enqueue order hasn't 305 // reached the number set for a fence). 306 bool HasActiveFence(); 307 308 // Returns true if the queue has a fence which is blocking execution of tasks. 309 bool BlockedByFence() const; 310 311 void SetObserver(Observer* observer); 312 313 // SingleThreadTaskRunner implementation 314 bool RunsTasksInCurrentSequence() const override; 315 bool PostDelayedTask(const Location& from_here, 316 OnceClosure task, 317 TimeDelta delay) override; 318 bool PostNonNestableDelayedTask(const Location& from_here, 319 OnceClosure task, 320 TimeDelta delay) override; 321 322 bool PostTaskWithMetadata(PostedTask task); 323 324 protected: 325 TaskQueue(std::unique_ptr<internal::TaskQueueImpl> impl, 326 const TaskQueue::Spec& spec); 327 ~TaskQueue() override; 328 GetTaskQueueImpl()329 internal::TaskQueueImpl* GetTaskQueueImpl() const { return impl_.get(); } 330 331 private: 332 friend class internal::SequenceManagerImpl; 333 friend class internal::TaskQueueImpl; 334 335 bool IsOnMainThread() const; 336 337 Optional<MoveableAutoLock> AcquireImplReadLockIfNeeded() const; 338 339 // TaskQueue has ownership of an underlying implementation but in certain 340 // cases (e.g. detached frames) their lifetime may diverge. 341 // This method should be used to take away the impl for graceful shutdown. 342 // TaskQueue will disregard any calls or posting tasks thereafter. 343 std::unique_ptr<internal::TaskQueueImpl> TakeTaskQueueImpl(); 344 345 // |impl_| can be written to on the main thread but can be read from 346 // any thread. 347 // |impl_lock_| must be acquired when writing to |impl_| or when accessing 348 // it from non-main thread. Reading from the main thread does not require 349 // a lock. 350 mutable Lock impl_lock_; 351 std::unique_ptr<internal::TaskQueueImpl> impl_; 352 353 const PlatformThreadId thread_id_; 354 355 const WeakPtr<internal::SequenceManagerImpl> sequence_manager_; 356 357 const scoped_refptr<internal::GracefulQueueShutdownHelper> 358 graceful_queue_shutdown_helper_; 359 360 THREAD_CHECKER(main_thread_checker_); 361 362 DISALLOW_COPY_AND_ASSIGN(TaskQueue); 363 }; 364 365 } // namespace sequence_manager 366 } // namespace base 367 368 #endif // BASE_TASK_SEQUENCE_MANAGER_TASK_QUEUE_H_ 369