blob: 83c5951acd0135f3f33ed642e3abb8004c544f5d [file] [log] [blame]
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROMECAST_BASE_ALARM_MANAGER_H_
#define CHROMECAST_BASE_ALARM_MANAGER_H_
#include <memory>
#include <queue>
#include <vector>
#include "base/functional/callback.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
namespace base {
class Clock;
class SingleThreadTaskRunner;
}
namespace chromecast {
// Alarm handle for scoping the in-flight alarm.
class AlarmHandle final {
public:
AlarmHandle();
~AlarmHandle();
base::WeakPtr<AlarmHandle> AsWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
private:
base::WeakPtrFactory<AlarmHandle> weak_ptr_factory_{this};
};
// Alarm manager allows setting a task for wall clock time rather than for an
// elapsed amount of time. This is different from using long PostDelayedTasks
// that are sensitive to time changes, clock drift, and other factors.
//
// Alarm manager polls the wall clock time every 5 seconds. If the clock is
// equal or past the requested time, the alarm will fire.
class AlarmManager {
public:
// Construct and start the alarm manager. The clock poller will run on the
// caller's thread.
AlarmManager();
AlarmManager(const AlarmManager&) = delete;
AlarmManager& operator=(const AlarmManager&) = delete;
~AlarmManager();
// For testing only. Allows setting a fake clock and using a custom task
// runner.
AlarmManager(const base::Clock* clock,
scoped_refptr<base::SingleThreadTaskRunner> task_runner);
// Add an alarm.
// |task| will be executed at around |time|.
// Returns an AlarmHandle that must be kept alive. If the AlarmHandle is
// destroyed, the alarm will not fire.
//
// Any thread can add alarms. The alarm will be fired on the original
// thread used to set the alarm.
//
// When an alarm is added to the alarm manager, the task is guaranteed to not
// run before the clock passes the requested time. The task may not run even
// if it is past the requested time if the software is suspended. However,
// once woken up, the event will fire within 5 seconds if the target time has
// passed.
[[nodiscard]] std::unique_ptr<AlarmHandle> PostAlarmTask(
base::OnceClosure task,
base::Time time);
private:
class AlarmInfo {
public:
AlarmInfo(base::OnceClosure task,
base::Time time,
scoped_refptr<base::SingleThreadTaskRunner> task_runner);
AlarmInfo(const AlarmInfo&) = delete;
AlarmInfo& operator=(const AlarmInfo&) = delete;
~AlarmInfo();
void PostTask();
base::Time time() const { return time_; }
private:
base::OnceClosure task_;
const base::Time time_;
const scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
};
// Check if an alarm should fire.
void CheckAlarm();
// Add the alarm to the queue.
void AddAlarm(base::OnceClosure task,
base::Time time,
scoped_refptr<base::SingleThreadTaskRunner> task_runner);
// Ordering alarms by earliest time.
struct alarm_compare {
bool operator()(const std::unique_ptr<AlarmInfo>& lhs,
const std::unique_ptr<AlarmInfo>& rhs) const {
return lhs->time() > rhs->time();
}
};
// Store a list of the alarms to fire with the earliest getting priority.
std::priority_queue<std::unique_ptr<AlarmInfo>,
std::vector<std::unique_ptr<AlarmInfo>>,
alarm_compare>
next_alarm_;
// Poller for wall clock time.
const base::Clock* const clock_;
base::RepeatingTimer clock_tick_timer_;
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
base::WeakPtrFactory<AlarmManager> weak_factory_;
};
} // namespace chromecast
#endif // CHROMECAST_BASE_ALARM_MANAGER_H_