blob: 03c06dcaba2bed6a0ec7cf3b0df8e5a2eedb3529 [file] [log] [blame]
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_BROWSER_SCHEDULER_BROWSER_TASK_QUEUES_H_
#define CONTENT_BROWSER_SCHEDULER_BROWSER_TASK_QUEUES_H_
#include <array>
#include "base/functional/callback_helpers.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/task/sequence_manager/task_queue.h"
#include "base/task/single_thread_task_runner.h"
#include "content/common/content_export.h"
#include "content/public/browser/browser_thread.h"
namespace base {
namespace sequence_manager {
class SequenceManager;
} // namespace sequence_manager
} // namespace base
namespace content {
// Common task queues for browser threads. This class holds all the queues
// needed by browser threads. This makes it easy for all browser threads to have
// the same queues. This class also provides a Handler to act on the queues from
// any thread.
//
// Instances must be created and destroyed on the same thread as the
// underlying SequenceManager and instances are not allowed to outlive this
// SequenceManager. All methods of this class must be called from the
// associated thread unless noted otherwise. If you need to perform operations
// from a different thread use a Handle instance instead.
//
// Attention: All queues are initially disabled, that is, tasks will not be run
// for them.
class CONTENT_EXPORT BrowserTaskQueues {
public:
enum class QueueType {
// Catch all for tasks that don't fit other categories.
// TODO(alexclarke): Introduce new semantic types as needed to minimize the
// number of default tasks. Has the same priority as kUserBlocking.
kDefault,
// For non-urgent work, that will only execute if there's nothing else to
// do. Can theoretically be starved indefinitely although that's unlikely in
// practice.
kBestEffort,
// base::TaskPriority::kUserBlocking maps to this task queue. It's for tasks
// that affect the UI immediately after a user interaction. Has the same
// priority as kDefault.
kUserBlocking,
// base::TaskPriority::kUserVisible maps to this task queue. The result of
// these tasks are visible to the user (in the UI or as a side-effect on the
// system) but they are not an immediate response to a user interaction.
kUserVisible,
// For tasks directly related to handling input events. This also changes
// the priority of yielding to native (to get the user input events faster).
// This is higher priority than kUserBlocking.
kUserInput,
// For tasks processing navigation network request's response from the
// network service.
kNavigationNetworkResponse,
// For tasks processing ServiceWorker's storage control's response. This has
// the highest priority during startup, and is updated to normal priority
// after startup.
kServiceWorkerStorageControlResponse,
// For before unload navigation continuation tasks.
kBeforeUnloadBrowserResponse,
// Tasks that are critical for startup performance. Note that tasks in other
// queues may run during startup too.
kStartup,
kMaxValue = kStartup
};
static constexpr size_t kNumQueueTypes =
static_cast<size_t>(QueueType::kMaxValue) + 1;
// Handle to a BrowserTaskQueues instance that can be used from any thread
// as all operations are thread safe.
//
// If the underlying BrowserTaskQueues is destroyed all methods of this
// class become no-ops, that is it is safe for this class to outlive its
// parent BrowserTaskQueues.
class CONTENT_EXPORT Handle : public base::RefCountedThreadSafe<Handle> {
public:
REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE();
// Returns the task runner that should be returned by
// SingleThreadTaskRunner::GetCurrentDefault().
const scoped_refptr<base::SingleThreadTaskRunner>& GetDefaultTaskRunner() {
return default_task_runner_;
}
const scoped_refptr<base::SingleThreadTaskRunner>& GetBrowserTaskRunner(
QueueType queue_type) const {
return browser_task_runners_[static_cast<size_t>(queue_type)];
}
// Called after startup is complete, enables all task queues and can
// be called multiple times.
void OnStartupComplete();
// Called quite early in startup after initialising the owning thread's
// scheduler, before we call RunLoop::Run on the thread.
// Enables all task queues except the effort ones. Can be called multiple
// times.
void EnableAllExceptBestEffortQueues();
// Enables the specified task queue. Called early in startup when
// BrowserTaskExecutor is created to enabled the default IO task queue.
void EnableTaskQueue(QueueType type);
// Schedules |on_pending_task_ran| to run when all pending tasks (at the
// time this method was invoked) have run. Only "runnable" tasks are taken
// into account, that is tasks from disabled queues are ignored, also this
// only works reliably for immediate tasks, delayed tasks might or might not
// run depending on timing.
//
// The callback will run on the thread associated with this Handle, unless
// that thread is no longer accepting tasks; in which case it will be run
// inline immediately.
//
// The recommended usage pattern is:
// RunLoop run_loop;
// handle.ScheduleRunAllPendingTasksForTesting(run_loop.QuitClosure());
// run_loop.Run();
void ScheduleRunAllPendingTasksForTesting(
base::OnceClosure on_pending_task_ran);
// Drop back-pointer to resource about to be freed.
void OnTaskQueuesDestroyed() { outer_ = nullptr; }
private:
friend base::RefCountedThreadSafe<Handle>;
// Only BrowserTaskQueues can create new instances
friend class BrowserTaskQueues;
~Handle();
explicit Handle(BrowserTaskQueues* task_queues);
// |outer_| can only be safely used from a task posted to one of the
// runners.
raw_ptr<BrowserTaskQueues> outer_ = nullptr;
scoped_refptr<base::SingleThreadTaskRunner> control_task_runner_;
scoped_refptr<base::SingleThreadTaskRunner> default_task_runner_;
std::array<scoped_refptr<base::SingleThreadTaskRunner>, kNumQueueTypes>
browser_task_runners_;
};
// |sequence_manager| must outlive this instance.
explicit BrowserTaskQueues(
BrowserThread::ID thread_id,
base::sequence_manager::SequenceManager* sequence_manager);
void SetOnTaskCompletedHandler(
base::sequence_manager::TaskQueue::OnTaskCompletedHandler handler);
// Destroys all queues.
~BrowserTaskQueues();
scoped_refptr<Handle> GetHandle() { return handle_; }
void AddTaskObserver(base::TaskObserver* task_observer);
private:
struct QueueData {
public:
QueueData();
~QueueData();
QueueData(QueueData&& other);
base::sequence_manager::TaskQueue::Handle task_queue;
std::unique_ptr<base::sequence_manager::TaskQueue::QueueEnabledVoter> voter;
};
// All these methods can only be called from the associated thread. To make
// sure that is the case they will always be called from a task posted to the
// |control_queue_|.
void StartRunAllPendingTasksForTesting(
base::ScopedClosureRunner on_pending_task_ran);
void EndRunAllPendingTasksForTesting(
base::ScopedClosureRunner on_pending_task_ran);
void OnStartupComplete();
void EnableAllExceptBestEffortQueues();
void EnableTaskQueue(QueueType type);
base::sequence_manager::TaskQueue* GetBrowserTaskQueue(QueueType type) const {
return queue_data_[static_cast<size_t>(type)].task_queue.get();
}
base::sequence_manager::TaskQueue* GetDefaultTaskQueue() const {
return GetBrowserTaskQueue(QueueType::kDefault);
}
std::array<scoped_refptr<base::SingleThreadTaskRunner>, kNumQueueTypes>
CreateBrowserTaskRunners() const;
std::array<QueueData, kNumQueueTypes> queue_data_;
// Helper queue to make sure private methods run on the associated thread. the
// control queue has maximum priority and will never be disabled.
base::sequence_manager::TaskQueue::Handle control_queue_;
// Helper queue to run all pending tasks.
base::sequence_manager::TaskQueue::Handle run_all_pending_tasks_queue_;
int run_all_pending_nesting_level_ = 0;
scoped_refptr<Handle> handle_;
};
} // namespace content
#endif // CONTENT_BROWSER_SCHEDULER_BROWSER_TASK_QUEUES_H_