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

base / task / sequence_manager / tasks.h [blame]

// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef BASE_TASK_SEQUENCE_MANAGER_TASKS_H_
#define BASE_TASK_SEQUENCE_MANAGER_TASKS_H_

#include <optional>

#include "base/base_export.h"
#include "base/check.h"
#include "base/containers/intrusive_heap.h"
#include "base/dcheck_is_on.h"
#include "base/pending_task.h"
#include "base/task/delay_policy.h"
#include "base/task/sequence_manager/delayed_task_handle_delegate.h"
#include "base/task/sequence_manager/enqueue_order.h"
#include "base/task/sequenced_task_runner.h"
#include "third_party/abseil-cpp/absl/types/variant.h"

namespace base {
namespace sequence_manager {

using TaskType = uint8_t;
constexpr TaskType kTaskTypeNone = 0;

class TaskOrder;

namespace internal {

// Wrapper around PostTask method arguments and the assigned task type.
// Eventually it becomes a PendingTask once accepted by a TaskQueueImpl.
struct BASE_EXPORT PostedTask {
  explicit PostedTask(scoped_refptr<SequencedTaskRunner> task_runner,
                      OnceClosure callback,
                      Location location,
                      TimeDelta delay = base::TimeDelta(),
                      Nestable nestable = Nestable::kNestable,
                      TaskType task_type = kTaskTypeNone,
                      WeakPtr<DelayedTaskHandleDelegate>
                          delayed_task_handle_delegate = nullptr);
  explicit PostedTask(scoped_refptr<SequencedTaskRunner> task_runner,
                      OnceClosure callback,
                      Location location,
                      TimeTicks delayed_run_time,
                      subtle::DelayPolicy delay_policy,
                      Nestable nestable = Nestable::kNestable,
                      TaskType task_type = kTaskTypeNone,
                      WeakPtr<DelayedTaskHandleDelegate>
                          delayed_task_handle_delegate = nullptr);
  PostedTask(PostedTask&& move_from) noexcept;
  PostedTask(const PostedTask&) = delete;
  PostedTask& operator=(const PostedTask&) = delete;
  ~PostedTask();

  bool is_delayed() const {
    return absl::holds_alternative<TimeTicks>(delay_or_delayed_run_time)
               ? !absl::get<TimeTicks>(delay_or_delayed_run_time).is_null()
               : !absl::get<TimeDelta>(delay_or_delayed_run_time).is_zero();
  }

  OnceClosure callback;
  Location location;
  Nestable nestable = Nestable::kNestable;
  TaskType task_type = kTaskTypeNone;
  absl::variant<TimeDelta, TimeTicks> delay_or_delayed_run_time;
  subtle::DelayPolicy delay_policy = subtle::DelayPolicy::kFlexibleNoSooner;
  // The task runner this task is running on. Can be used by task runners that
  // support posting back to the "current sequence".
  scoped_refptr<SequencedTaskRunner> task_runner;
  // The delegate for the DelayedTaskHandle, if this task was posted through
  // PostCancelableDelayedTask(), nullptr otherwise.
  WeakPtr<DelayedTaskHandleDelegate> delayed_task_handle_delegate;
};

}  // namespace internal

enum class WakeUpResolution { kLow, kHigh };

// Represents a time at which a task wants to run.
struct WakeUp {
  // is_null() for immediate wake up.
  TimeTicks time;
  // These are meaningless if is_immediate().
  TimeDelta leeway;
  WakeUpResolution resolution = WakeUpResolution::kLow;
  subtle::DelayPolicy delay_policy = subtle::DelayPolicy::kFlexibleNoSooner;

  bool operator!=(const WakeUp& other) const {
    return time != other.time || leeway != other.leeway ||
           resolution != other.resolution || delay_policy != other.delay_policy;
  }

  bool operator==(const WakeUp& other) const { return !(*this != other); }

  bool is_immediate() const { return time.is_null(); }

  TimeTicks earliest_time() const;
  TimeTicks latest_time() const;
};

// PendingTask with extra metadata for SequenceManager.
struct BASE_EXPORT Task : public PendingTask {
  Task(internal::PostedTask posted_task,
       EnqueueOrder sequence_order,
       EnqueueOrder enqueue_order = EnqueueOrder(),
       TimeTicks queue_time = TimeTicks(),
       WakeUpResolution wake_up_resolution = WakeUpResolution::kLow,
       TimeDelta leeway = TimeDelta());
  Task(Task&& move_from);
  ~Task();
  Task& operator=(Task&& other);

  // SequenceManager is particularly sensitive to enqueue order,
  // so we have accessors for safety.
  EnqueueOrder enqueue_order() const {
    DCHECK(enqueue_order_);
    return enqueue_order_;
  }

  void set_enqueue_order(EnqueueOrder enqueue_order) {
    DCHECK(!enqueue_order_);
    enqueue_order_ = enqueue_order;
  }

  bool enqueue_order_set() const { return enqueue_order_; }

  TaskOrder task_order() const;

  // OK to dispatch from a nested loop.
  Nestable nestable = Nestable::kNonNestable;

  // Needs high resolution timers.
  bool is_high_res = false;

  TaskType task_type;

  // The task runner this task is running on. Can be used by task runners that
  // support posting back to the "current sequence".
  scoped_refptr<SequencedTaskRunner> task_runner;

#if DCHECK_IS_ON()
  bool cross_thread_;
#endif

  // Implement the intrusive heap contract.
  void SetHeapHandle(HeapHandle heap_handle);
  void ClearHeapHandle();
  HeapHandle GetHeapHandle() const;

  // Returns true if this task was canceled, either through weak pointer
  // invalidation or through |delayed_task_handle_delegate_|.
  bool IsCanceled() const;

  // Must be invoked before running the task. Returns true if the task must run
  // (any delayed task handle will have been invalidated by this method), false
  // if it mustn't run (e.g. delayed task handle was invalidated prior to
  // calling this method).
  bool WillRunTask();

 private:
  // `enqueue_order_` is the primary component used to order tasks (see
  // `TaskOrder`). For immediate tasks, `enqueue_order` is set when posted, but
  // for delayed tasks it's not defined until they are enqueued. This is because
  // otherwise delayed tasks could run before an immediate task posted after the
  // delayed task.
  EnqueueOrder enqueue_order_;

  // The delegate for the DelayedTaskHandle, if this task was posted through
  // `PostCancelableDelayedTask()`, not set otherwise. The task is canceled if
  // `WeakPtr::WasInvalidated` is true. Note: if the task was not posted via
  // `PostCancelableDelayedTask()`. the weak pointer won't be valid, but
  // `WeakPtr::WasInvalidated` will be false.
  WeakPtr<internal::DelayedTaskHandleDelegate> delayed_task_handle_delegate_;
};

}  // namespace sequence_manager
}  // namespace base

#endif  // BASE_TASK_SEQUENCE_MANAGER_TASKS_H_