summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/api/task_queue/task_queue_base.h
blob: f78600de6028083057a2fc93ceee43b683dbcf57 (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
/*
 *  Copyright 2019 The WebRTC Project Authors. All rights reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */
#ifndef API_TASK_QUEUE_TASK_QUEUE_BASE_H_
#define API_TASK_QUEUE_TASK_QUEUE_BASE_H_

#include <memory>
#include <utility>

#include "absl/functional/any_invocable.h"
#include "api/units/time_delta.h"
#include "rtc_base/system/rtc_export.h"
#include "rtc_base/thread_annotations.h"

namespace webrtc {

// Asynchronously executes tasks in a way that guarantees that they're executed
// in FIFO order and that tasks never overlap. Tasks may always execute on the
// same worker thread and they may not. To DCHECK that tasks are executing on a
// known task queue, use IsCurrent().
class RTC_LOCKABLE RTC_EXPORT TaskQueueBase {
 public:
  enum class DelayPrecision {
    // This may include up to a 17 ms leeway in addition to OS timer precision.
    // See PostDelayedTask() for more information.
    kLow,
    // This does not have the additional delay that kLow has, but it is still
    // limited by OS timer precision. See PostDelayedHighPrecisionTask() for
    // more information.
    kHigh,
  };

  // Starts destruction of the task queue.
  // On return ensures no task are running and no new tasks are able to start
  // on the task queue.
  // Responsible for deallocation. Deallocation may happen synchronously during
  // Delete or asynchronously after Delete returns.
  // Code not running on the TaskQueue should not make any assumption when
  // TaskQueue is deallocated and thus should not call any methods after Delete.
  // Code running on the TaskQueue should not call Delete, but can assume
  // TaskQueue still exists and may call other methods, e.g. PostTask.
  // Should be called on the same task queue or thread that this task queue
  // was created on.
  virtual void Delete() = 0;

  // Schedules a `task` to execute. Tasks are executed in FIFO order.
  // When a TaskQueue is deleted, pending tasks will not be executed but they
  // will be deleted.
  //
  // As long as tasks are not posted from task destruction, posted tasks are
  // guaranteed to be destroyed with Current() pointing to the task queue they
  // were posted to, whether they're executed or not. That means SequenceChecker
  // works during task destruction, a fact that can be used to guarantee
  // thread-compatible object deletion happening on a particular task queue
  // which can simplify class design.
  // Note that this guarantee does not apply to delayed tasks.
  //
  // May be called on any thread or task queue, including this task queue.
  virtual void PostTask(absl::AnyInvocable<void() &&> task) = 0;

  // Prefer PostDelayedTask() over PostDelayedHighPrecisionTask() whenever
  // possible.
  //
  // Schedules a `task` to execute a specified `delay` from when the call is
  // made, using "low" precision. All scheduling is affected by OS-specific
  // leeway and current workloads which means that in terms of precision there
  // are no hard guarantees, but in addition to the OS induced leeway, "low"
  // precision adds up to a 17 ms additional leeway. The purpose of this leeway
  // is to achieve more efficient CPU scheduling and reduce Idle Wake Up
  // frequency.
  //
  // The task may execute with [-1, 17 + OS induced leeway) ms additional delay.
  //
  // Avoid making assumptions about the precision of the OS scheduler. On macOS,
  // the OS induced leeway may be 10% of sleep interval. On Windows, 1 ms
  // precision timers may be used but there are cases, such as when running on
  // battery, when the timer precision can be as poor as 15 ms.
  //
  // "Low" precision is not implemented everywhere yet. Where not yet
  // implemented, PostDelayedTask() has "high" precision. See
  // https://crbug.com/webrtc/13583 for more information.
  //
  // May be called on any thread or task queue, including this task queue.
  virtual void PostDelayedTask(absl::AnyInvocable<void() &&> task,
                               TimeDelta delay) = 0;

  // Prefer PostDelayedTask() over PostDelayedHighPrecisionTask() whenever
  // possible.
  //
  // Schedules a `task` to execute a specified `delay` from when the call is
  // made, using "high" precision. All scheduling is affected by OS-specific
  // leeway and current workloads which means that in terms of precision there
  // are no hard guarantees.
  //
  // The task may execute with [-1, OS induced leeway] ms additional delay.
  //
  // Avoid making assumptions about the precision of the OS scheduler. On macOS,
  // the OS induced leeway may be 10% of sleep interval. On Windows, 1 ms
  // precision timers may be used but there are cases, such as when running on
  // battery, when the timer precision can be as poor as 15 ms.
  //
  // May be called on any thread or task queue, including this task queue.
  virtual void PostDelayedHighPrecisionTask(absl::AnyInvocable<void() &&> task,
                                            TimeDelta delay) = 0;

  // As specified by `precision`, calls either PostDelayedTask() or
  // PostDelayedHighPrecisionTask().
  void PostDelayedTaskWithPrecision(DelayPrecision precision,
                                    absl::AnyInvocable<void() &&> task,
                                    TimeDelta delay) {
    switch (precision) {
      case DelayPrecision::kLow:
        PostDelayedTask(std::move(task), delay);
        break;
      case DelayPrecision::kHigh:
        PostDelayedHighPrecisionTask(std::move(task), delay);
        break;
    }
  }

  // Returns the task queue that is running the current thread.
  // Returns nullptr if this thread is not associated with any task queue.
  // May be called on any thread or task queue, including this task queue.
  static TaskQueueBase* Current();
  bool IsCurrent() const { return Current() == this; }

 protected:
  class RTC_EXPORT CurrentTaskQueueSetter {
   public:
    explicit CurrentTaskQueueSetter(TaskQueueBase* task_queue);
    CurrentTaskQueueSetter(const CurrentTaskQueueSetter&) = delete;
    CurrentTaskQueueSetter& operator=(const CurrentTaskQueueSetter&) = delete;
    ~CurrentTaskQueueSetter();

   private:
    TaskQueueBase* const previous_;
  };

  // Users of the TaskQueue should call Delete instead of directly deleting
  // this object.
  virtual ~TaskQueueBase() = default;
};

struct TaskQueueDeleter {
  void operator()(TaskQueueBase* task_queue) const { task_queue->Delete(); }
};

}  // namespace webrtc

#endif  // API_TASK_QUEUE_TASK_QUEUE_BASE_H_