summaryrefslogtreecommitdiff
path: root/chromium/content/browser/scheduler/browser_task_queues.h
blob: 39c11ddaf02f3e2baebc025c61d8280fd96c2ebd (plain)
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
// Copyright 2019 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 CONTENT_BROWSER_SCHEDULER_BROWSER_TASK_QUEUES_H_
#define CONTENT_BROWSER_SCHEDULER_BROWSER_TASK_QUEUES_H_

#include <array>

#include "base/callback_helpers.h"
#include "base/memory/scoped_refptr.h"
#include "base/task/sequence_manager/task_queue.h"
#include "content/common/content_export.h"
#include "content/public/browser/browser_thread.h"

namespace base {
namespace sequence_manager {
class SequenceManager;
class TimeDomain;
}  // 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 the 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,

    // For tasks on the critical path up to issuing the initial navigation.
    kBootstrap,

    // For preconnection-related tasks.
    kPreconnection,

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

    kMaxValue = kUserVisible
  };

  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
    // ThreadTaskRunnerHandle::Get().
    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)];
    }

    // Initializes any scheduler experiments. Should be called after
    // FeatureLists have been initialized (which usually happens after task
    // queues are set up).
    void PostFeatureListInitializationSetup();

    // Enables all tasks queues. Can be called multiple times.
    void EnableAllQueues();

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

   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.
    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| and |time_domain| must outlive this instance.
  explicit BrowserTaskQueues(
      BrowserThread::ID thread_id,
      base::sequence_manager::SequenceManager* sequence_manager,
      base::sequence_manager::TimeDomain* time_domain);

  // Destroys all queues.
  ~BrowserTaskQueues();

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

 private:
  // 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 EnableAllQueues();
  void EnableAllExceptBestEffortQueues();
  void PostFeatureListInitializationSetup();

  base::sequence_manager::TaskQueue* GetBrowserTaskQueue(QueueType type) const {
    return queue_data_[static_cast<size_t>(type)].task_queue.get();
  }

  std::array<scoped_refptr<base::SingleThreadTaskRunner>, kNumQueueTypes>
  CreateBrowserTaskRunners() const;

  struct QueueData {
    QueueData();
    ~QueueData();
    scoped_refptr<base::sequence_manager::TaskQueue> task_queue;
    std::unique_ptr<base::sequence_manager::TaskQueue::QueueEnabledVoter> voter;
  };
  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.
  scoped_refptr<base::sequence_manager::TaskQueue> control_queue_;

  // Queue that backs the default TaskRunner registered with SequenceManager.
  // This will be the one returned by ThreadTaskRunnerHandle::Get(). Note this
  // is different from QueueType:kDefault as this queue needs to be enabled from
  // the beginning.
  scoped_refptr<base::sequence_manager::TaskQueue> default_task_queue_;

  // Helper queue to run all pending tasks.
  scoped_refptr<base::sequence_manager::TaskQueue> 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_