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

base / task / thread_pool / delayed_task_manager.h [blame]

// Copyright 2016 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_THREAD_POOL_DELAYED_TASK_MANAGER_H_
#define BASE_TASK_THREAD_POOL_DELAYED_TASK_MANAGER_H_

#include <functional>
#include <optional>

#include "base/base_export.h"
#include "base/containers/intrusive_heap.h"
#include "base/functional/callback.h"
#include "base/memory/ptr_util.h"
#include "base/memory/raw_ptr.h"
#include "base/synchronization/atomic_flag.h"
#include "base/task/common/checked_lock.h"
#include "base/task/delay_policy.h"
#include "base/task/task_features.h"
#include "base/task/thread_pool/task.h"
#include "base/thread_annotations.h"
#include "base/time/default_tick_clock.h"
#include "base/time/tick_clock.h"

namespace base {

class SequencedTaskRunner;

namespace internal {

// The DelayedTaskManager forwards tasks to post task callbacks when they become
// ripe for execution. Tasks are not forwarded before Start() is called. This
// class is thread-safe.
class BASE_EXPORT DelayedTaskManager {
 public:
  // Posts |task| for execution immediately.
  using PostTaskNowCallback = OnceCallback<void(Task task)>;

  // |tick_clock| can be specified for testing.
  DelayedTaskManager(
      const TickClock* tick_clock = DefaultTickClock::GetInstance());
  DelayedTaskManager(const DelayedTaskManager&) = delete;
  DelayedTaskManager& operator=(const DelayedTaskManager&) = delete;
  ~DelayedTaskManager();

  // Starts the delayed task manager, allowing past and future tasks to be
  // forwarded to their callbacks as they become ripe for execution.
  // |service_thread_task_runner| posts tasks to the ThreadPool service
  // thread.
  void Start(scoped_refptr<SequencedTaskRunner> service_thread_task_runner);

  // Schedules a call to |post_task_now_callback| with |task| as argument when
  // |task| is ripe for execution.
  void AddDelayedTask(Task task, PostTaskNowCallback post_task_now_callback);

  // Pop and post all the ripe tasks in the delayed task queue.
  void ProcessRipeTasks();

  // Returns the |delayed_run_time| of the next scheduled task, if any.
  std::optional<TimeTicks> NextScheduledRunTime() const;

  // Returns the DelayPolicy for the next delayed task.
  subtle::DelayPolicy TopTaskDelayPolicyForTesting() const;

  // Must be invoked before deleting the delayed task manager. The caller must
  // flush tasks posted to the service thread by this before deleting the
  // delayed task manager.
  void Shutdown();

 private:
  struct DelayedTask {
    DelayedTask();
    DelayedTask(Task task, PostTaskNowCallback callback);
    DelayedTask(DelayedTask&& other);
    DelayedTask(const DelayedTask&) = delete;
    DelayedTask& operator=(const DelayedTask&) = delete;
    ~DelayedTask();

    // Required by IntrusiveHeap::insert().
    DelayedTask& operator=(DelayedTask&& other);

    // Used for a min-heap.
    bool operator>(const DelayedTask& other) const;

    Task task;
    PostTaskNowCallback callback;

    // Mark the delayed task as scheduled. Since the sort key is
    // |task.delayed_run_time|, it does not alter sort order when it is called.
    void SetScheduled();

    // Required by IntrusiveHeap.
    void SetHeapHandle(const HeapHandle& handle) {}

    // Required by IntrusiveHeap.
    void ClearHeapHandle() {}

    // Required by IntrusiveHeap.
    HeapHandle GetHeapHandle() const { return HeapHandle::Invalid(); }
  };

  // Get the time at which to schedule the next |ProcessRipeTasks()| execution,
  // or TimeTicks::Max() if none needs to be scheduled (i.e. no task, or next
  // task already scheduled).
  std::pair<TimeTicks, subtle::DelayPolicy>
  GetTimeAndDelayPolicyToScheduleProcessRipeTasksLockRequired()
      EXCLUSIVE_LOCKS_REQUIRED(queue_lock_);

  // Schedule |ProcessRipeTasks()| on the service thread to be executed when
  // the next task is ripe.
  void ScheduleProcessRipeTasksOnServiceThread();

  const RepeatingClosure process_ripe_tasks_closure_;
  const RepeatingClosure schedule_process_ripe_tasks_closure_;

  const raw_ptr<const TickClock> tick_clock_;

  // Synchronizes access to |delayed_task_queue_| and the setting of
  // |service_thread_task_runner_|. Once |service_thread_task_runner_| is set,
  // it is never modified. It is therefore safe to access
  // |service_thread_task_runner_| without synchronization once it is observed
  // that it is non-null.
  mutable CheckedLock queue_lock_{UniversalSuccessor()};

  scoped_refptr<SequencedTaskRunner> service_thread_task_runner_;

  DelayedTaskHandle delayed_task_handle_ GUARDED_BY_CONTEXT(sequence_checker_);

  IntrusiveHeap<DelayedTask, std::greater<>> delayed_task_queue_
      GUARDED_BY(queue_lock_);

  base::TimeDelta max_precise_delay GUARDED_BY(queue_lock_) =
      kDefaultMaxPreciseDelay;

  SEQUENCE_CHECKER(sequence_checker_);
};

}  // namespace internal
}  // namespace base

#endif  // BASE_TASK_THREAD_POOL_DELAYED_TASK_MANAGER_H_