| // Copyright 2015 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_TASK_QUEUE_H_ |
| #define THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_TASK_QUEUE_H_ |
| |
| #include "base/macros.h" |
| #include "base/message_loop/message_loop.h" |
| #include "base/optional.h" |
| #include "base/single_thread_task_runner.h" |
| #include "base/synchronization/lock.h" |
| #include "base/threading/platform_thread.h" |
| #include "base/time/time.h" |
| #include "platform/PlatformExport.h" |
| #include "platform/scheduler/base/graceful_queue_shutdown_helper.h" |
| #include "platform/scheduler/base/moveable_auto_lock.h" |
| #include "public/platform/TaskType.h" |
| |
| namespace base { |
| namespace trace_event { |
| class BlameContext; |
| } |
| } |
| |
| namespace blink { |
| namespace scheduler { |
| namespace task_queue_throttler_unittest { |
| class TaskQueueThrottlerTest; |
| } |
| namespace internal { |
| class TaskQueueImpl; |
| } |
| |
| class TimeDomain; |
| class TaskQueueManager; |
| |
| class PLATFORM_EXPORT TaskQueue : public base::SingleThreadTaskRunner { |
| public: |
| class PLATFORM_EXPORT Observer { |
| public: |
| virtual ~Observer() {} |
| |
| // Notify observer that the time at which this queue wants to run |
| // the next task has changed. |next_wakeup| can be in the past |
| // (e.g. base::TimeTicks() can be used to notify about immediate work). |
| // Can be called on any thread |
| // All methods but SetObserver, SetTimeDomain and GetTimeDomain can be |
| // called on |queue|. |
| // |
| // TODO(altimin): Make it base::Optional<base::TimeTicks> to tell |
| // observer about cancellations. |
| virtual void OnQueueNextWakeUpChanged(TaskQueue* queue, |
| base::TimeTicks next_wake_up) = 0; |
| }; |
| |
| // A wrapper around base::OnceClosure with additional metadata to be passed |
| // to PostTask and plumbed until PendingTask is created. |
| struct PLATFORM_EXPORT PostedTask { |
| PostedTask(base::OnceClosure callback, |
| base::Location posted_from, |
| base::TimeDelta delay = base::TimeDelta(), |
| base::Nestable nestable = base::Nestable::kNestable, |
| base::Optional<TaskType> task_type = base::nullopt); |
| |
| base::OnceClosure callback; |
| base::Location posted_from; |
| base::TimeDelta delay; |
| base::Nestable nestable; |
| base::Optional<TaskType> task_type; |
| }; |
| |
| // Unregisters the task queue after which no tasks posted to it will run and |
| // the TaskQueueManager's reference to it will be released soon. |
| virtual void ShutdownTaskQueue(); |
| |
| enum QueuePriority { |
| // Queues with control priority will run before any other queue, and will |
| // explicitly starve other queues. Typically this should only be used for |
| // private queues which perform control operations. |
| kControlPriority, |
| |
| // The selector will prioritize high over normal and low and normal over |
| // low. However it will ensure neither of the lower priority queues can be |
| // completely starved by higher priority tasks. All three of these queues |
| // will always take priority over and can starve the best effort queue. |
| kHighPriority, |
| // Queues with normal priority are the default. |
| kNormalPriority, |
| kLowPriority, |
| |
| // Queues with best effort priority will only be run if all other queues are |
| // empty. They can be starved by the other queues. |
| kBestEffortPriority, |
| // Must be the last entry. |
| kQueuePriorityCount, |
| kFirstQueuePriority = kControlPriority, |
| }; |
| |
| // Can be called on any thread. |
| static const char* PriorityToString(QueuePriority priority); |
| |
| // Options for constructing a TaskQueue. |
| struct Spec { |
| explicit Spec(const char* name) |
| : name(name), |
| should_monitor_quiescence(false), |
| time_domain(nullptr), |
| should_notify_observers(true), |
| should_report_when_execution_blocked(false) {} |
| |
| Spec SetShouldMonitorQuiescence(bool should_monitor) { |
| should_monitor_quiescence = should_monitor; |
| return *this; |
| } |
| |
| Spec SetShouldNotifyObservers(bool run_observers) { |
| should_notify_observers = run_observers; |
| return *this; |
| } |
| |
| Spec SetTimeDomain(TimeDomain* domain) { |
| time_domain = domain; |
| return *this; |
| } |
| |
| // See TaskQueueManager::Observer::OnTriedToExecuteBlockedTask. |
| Spec SetShouldReportWhenExecutionBlocked(bool should_report) { |
| should_report_when_execution_blocked = should_report; |
| return *this; |
| } |
| |
| const char* name; |
| bool should_monitor_quiescence; |
| TimeDomain* time_domain; |
| bool should_notify_observers; |
| bool should_report_when_execution_blocked; |
| }; |
| |
| // Interface to pass per-task metadata to RendererScheduler. |
| class PLATFORM_EXPORT Task : public base::PendingTask { |
| public: |
| Task(PostedTask posted_task, base::TimeTicks desired_run_time); |
| |
| base::Optional<TaskType> task_type() const { return task_type_; } |
| |
| private: |
| base::Optional<TaskType> task_type_; |
| }; |
| |
| // An interface that lets the owner vote on whether or not the associated |
| // TaskQueue should be enabled. |
| class QueueEnabledVoter { |
| public: |
| QueueEnabledVoter() {} |
| virtual ~QueueEnabledVoter() {} |
| |
| // Votes to enable or disable the associated TaskQueue. The TaskQueue will |
| // only be enabled if all the voters agree it should be enabled, or if there |
| // are no voters. |
| // NOTE this must be called on the thread the associated TaskQueue was |
| // created on. |
| virtual void SetQueueEnabled(bool enabled) = 0; |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(QueueEnabledVoter); |
| }; |
| |
| // Returns an interface that allows the caller to vote on whether or not this |
| // TaskQueue is enabled. The TaskQueue will be enabled if there are no voters |
| // or if all agree it should be enabled. |
| // NOTE this must be called on the thread this TaskQueue was created by. |
| std::unique_ptr<QueueEnabledVoter> CreateQueueEnabledVoter(); |
| |
| // NOTE this must be called on the thread this TaskQueue was created by. |
| bool IsQueueEnabled() const; |
| |
| // Returns true if the queue is completely empty. |
| bool IsEmpty() const; |
| |
| // Returns the number of pending tasks in the queue. |
| size_t GetNumberOfPendingTasks() const; |
| |
| // Returns true if the queue has work that's ready to execute now. |
| // NOTE: this must be called on the thread this TaskQueue was created by. |
| bool HasTaskToRunImmediately() const; |
| |
| // Returns requested run time of next scheduled wake-up for a delayed task |
| // which is not ready to run. If there are no such tasks or the queue is |
| // disabled (by a QueueEnabledVoter) it returns base::nullopt. |
| // NOTE: this must be called on the thread this TaskQueue was created by. |
| base::Optional<base::TimeTicks> GetNextScheduledWakeUp(); |
| |
| // Can be called on any thread. |
| virtual const char* GetName() const; |
| |
| // Set the priority of the queue to |priority|. NOTE this must be called on |
| // the thread this TaskQueue was created by. |
| void SetQueuePriority(QueuePriority priority); |
| |
| // Returns the current queue priority. |
| QueuePriority GetQueuePriority() const; |
| |
| // These functions can only be called on the same thread that the task queue |
| // manager executes its tasks on. |
| void AddTaskObserver(base::MessageLoop::TaskObserver* task_observer); |
| void RemoveTaskObserver(base::MessageLoop::TaskObserver* task_observer); |
| |
| // Set the blame context which is entered and left while executing tasks from |
| // this task queue. |blame_context| must be null or outlive this task queue. |
| // Must be called on the thread this TaskQueue was created by. |
| void SetBlameContext(base::trace_event::BlameContext* blame_context); |
| |
| // Removes the task queue from the previous TimeDomain and adds it to |
| // |domain|. This is a moderately expensive operation. |
| void SetTimeDomain(TimeDomain* domain); |
| |
| // Returns the queue's current TimeDomain. Can be called from any thread. |
| TimeDomain* GetTimeDomain() const; |
| |
| enum class InsertFencePosition { |
| kNow, // Tasks posted on the queue up till this point further may run. |
| // All further tasks are blocked. |
| kBeginningOfTime, // No tasks posted on this queue may run. |
| }; |
| |
| // Inserts a barrier into the task queue which prevents tasks with an enqueue |
| // order greater than the fence from running until either the fence has been |
| // removed or a subsequent fence has unblocked some tasks within the queue. |
| // Note: delayed tasks get their enqueue order set once their delay has |
| // expired, and non-delayed tasks get their enqueue order set when posted. |
| // |
| // Fences come in three flavours: |
| // - Regular (InsertFence(NOW)) - all tasks posted after this moment |
| // are blocked. |
| // - Fully blocking (InsertFence(kBeginningOfTime)) - all tasks including |
| // already posted are blocked. |
| // - Delayed (InsertFenceAt(timestamp)) - blocks all tasks posted after given |
| // point in time (must be in the future). |
| // |
| // Only one fence can be scheduled at a time. Inserting a new fence |
| // will automatically remove the previous one, regardless of fence type. |
| void InsertFence(InsertFencePosition position); |
| void InsertFenceAt(base::TimeTicks time); |
| |
| // Removes any previously added fence and unblocks execution of any tasks |
| // blocked by it. |
| void RemoveFence(); |
| |
| bool HasActiveFence(); |
| |
| // Returns true if the queue has a fence which is blocking execution of tasks. |
| bool BlockedByFence() const; |
| |
| void SetObserver(Observer* observer); |
| |
| // base::SingleThreadTaskRunner implementation |
| bool RunsTasksInCurrentSequence() const override; |
| bool PostDelayedTask(const base::Location& from_here, |
| base::OnceClosure task, |
| base::TimeDelta delay) override; |
| bool PostNonNestableDelayedTask(const base::Location& from_here, |
| base::OnceClosure task, |
| base::TimeDelta delay) override; |
| |
| bool PostTaskWithMetadata(PostedTask task); |
| |
| protected: |
| TaskQueue(std::unique_ptr<internal::TaskQueueImpl> impl, |
| const TaskQueue::Spec& spec); |
| ~TaskQueue() override; |
| |
| internal::TaskQueueImpl* GetTaskQueueImpl() const { return impl_.get(); } |
| |
| private: |
| friend class internal::TaskQueueImpl; |
| friend class TaskQueueManager; |
| |
| friend class task_queue_throttler_unittest::TaskQueueThrottlerTest; |
| |
| bool IsOnMainThread() const; |
| |
| base::Optional<MoveableAutoLock> AcquireImplReadLockIfNeeded() const; |
| |
| // |impl_| can be written to on the main thread but can be read from |
| // any thread. |
| // |impl_lock_| must be acquired when writing to |impl_| or when accessing |
| // it from non-main thread. Reading from the main thread does not require |
| // a lock. |
| mutable base::Lock impl_lock_; |
| std::unique_ptr<internal::TaskQueueImpl> impl_; |
| |
| const base::PlatformThreadId thread_id_; |
| |
| const base::WeakPtr<TaskQueueManager> task_queue_manager_; |
| |
| const scoped_refptr<internal::GracefulQueueShutdownHelper> |
| graceful_queue_shutdown_helper_; |
| |
| THREAD_CHECKER(main_thread_checker_); |
| |
| DISALLOW_COPY_AND_ASSIGN(TaskQueue); |
| }; |
| |
| } // namespace scheduler |
| } // namespace blink |
| |
| #endif // THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_TASK_QUEUE_H_ |