1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192
  193
  194
  195
  196
  197
  198
  199
  200
  201
  202
  203
  204
  205
  206
  207
  208
  209
  210
  211
  212
  213
  214
  215
  216
  217
  218
  219
  220
  221
  222
  223
  224
  225
  226
  227
  228

content / browser / scheduler / browser_task_queues.h [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. Thic 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,

    // Those are tasks that affect the UI, but not urgent enough to run
    // immediately, those tasks are either deferred or run based on the
    // scheduling policy.
    kDeferrableUserBlocking,

    // 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,

    kMaxValue = kBeforeUnloadBrowserResponse
  };

  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.
    // Note: default_task_queue_ doesn't need to be enabled as it is not
    // disabled during startup.
    // Enables all task queues except the effort ones. Can be called multiple
    // times.
    void EnableAllExceptBestEffortQueues();

    // 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_;
  };

  // Creates queue voters for all task queues created within this
  // BrowserTaskQueues object.
  // NOTE: You can only call this function from the thread that owns the
  // task queues, and you can only use the voters on the same thread.
  std::array<
      std::unique_ptr<base::sequence_manager::TaskQueue::QueueEnabledVoter>,
      kNumQueueTypes>
  CreateQueueEnabledVoters() const;

  // |sequence_manager| must outlive this instance.
  explicit BrowserTaskQueues(
      BrowserThread::ID thread_id,
      base::sequence_manager::SequenceManager* sequence_manager);

  // Destroys all queues.
  ~BrowserTaskQueues();

  scoped_refptr<Handle> GetHandle() { return handle_; }

 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();

  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_