mirror of
https://github.com/klzgrad/naiveproxy.git
synced 2025-04-11 05:00:57 +00:00
508 lines
19 KiB
C++
508 lines
19 KiB
C++
// Copyright 2012 The Chromium Authors
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
// A "timer" takes care of invoking a callback in the future, once or
|
|
// repeatedly. The callback is invoked:
|
|
// - OneShotTimer: Once after a `TimeDelta` delay has elapsed.
|
|
// - RetainingOneShotTimer: Same as OneShotTimer, but the callback is retained
|
|
// after being executed, allowing another invocation to be scheduled with
|
|
// Reset() without specifying the callback again.
|
|
// - DeadlineTimer: Once at the specified `TimeTicks` time.
|
|
// - RepeatingTimer: Repeatedly, with a specified `TimeDelta` delay before the
|
|
// first invocation and between invocations.
|
|
// - MetronomeTimer: Repeatedly, with a specified `TimeDelta` delay between the
|
|
// beginning of each invocations such that a constant phase is respected.
|
|
// (Retaining)OneShotTimer and RepeatingTimer automatically apply some leeway to
|
|
// the delay whereas DeadlineTimer and MetronomeTimer allow more control over
|
|
// the requested time. As a result, the former are generally more
|
|
// power-efficient.
|
|
// Prefer using (Retaining)OneShotTimer and RepeatingTimer because they
|
|
// automatically apply some leeway to the delay which enables power-efficient
|
|
// scheduling.
|
|
|
|
// Scheduled invocations can be cancelled with Stop() or by deleting the
|
|
// Timer. The latter makes it easy to ensure that an object is not accessed by a
|
|
// Timer after it has been deleted: just make the Timer a member of the object
|
|
// which receives Timer events (see example below).
|
|
//
|
|
// Sample RepeatingTimer usage:
|
|
//
|
|
// class MyClass {
|
|
// public:
|
|
// void StartDoingStuff() {
|
|
// timer_.Start(FROM_HERE, base::Seconds(1),
|
|
// this, &MyClass::DoStuff);
|
|
// // Alternative form if the callback is not bound to `this` or
|
|
// // requires arguments:
|
|
// // timer_.Start(FROM_HERE, base::Seconds(1),
|
|
// // base::BindRepeating(&MyFunction, 42));
|
|
// }
|
|
// void StopDoingStuff() {
|
|
// timer_.Stop();
|
|
// }
|
|
// private:
|
|
// void DoStuff() {
|
|
// // This method is called every second to do stuff.
|
|
// ...
|
|
// }
|
|
// base::RepeatingTimer timer_;
|
|
// };
|
|
//
|
|
// These APIs are not thread safe. When a method is called (except the
|
|
// constructor), all further method calls must be on the same sequence until
|
|
// Stop(). Once stopped, it may be destroyed or restarted on another sequence.
|
|
//
|
|
// By default, the scheduled tasks will be run on the same sequence that the
|
|
// Timer was *started on*. To mock time in unit tests, some old tests used
|
|
// SetTaskRunner() to schedule the delay on a test-controlled TaskRunner. The
|
|
// modern and preferred approach to mock time is to use TaskEnvironment's
|
|
// MOCK_TIME mode.
|
|
|
|
#ifndef BASE_TIMER_TIMER_H_
|
|
#define BASE_TIMER_TIMER_H_
|
|
|
|
// IMPORTANT: If you change timer code, make sure that all tests (including
|
|
// disabled ones) from timer_unittests.cc pass locally. Some are disabled
|
|
// because they're flaky on the buildbot, but when you run them locally you
|
|
// should be able to tell the difference.
|
|
|
|
#include "base/base_export.h"
|
|
#include "base/functional/bind.h"
|
|
#include "base/functional/callback.h"
|
|
#include "base/functional/callback_helpers.h"
|
|
#include "base/location.h"
|
|
#include "base/memory/raw_ptr.h"
|
|
#include "base/sequence_checker.h"
|
|
#include "base/task/delayed_task_handle.h"
|
|
#include "base/task/sequenced_task_runner.h"
|
|
#include "base/time/time.h"
|
|
#include "base/types/strong_alias.h"
|
|
|
|
namespace base {
|
|
|
|
class TickClock;
|
|
|
|
namespace internal {
|
|
|
|
// This class wraps logic shared by all timers.
|
|
class BASE_EXPORT TimerBase {
|
|
public:
|
|
TimerBase(const TimerBase&) = delete;
|
|
TimerBase& operator=(const TimerBase&) = delete;
|
|
|
|
virtual ~TimerBase();
|
|
|
|
// Returns true if the timer is running (i.e., not stopped).
|
|
bool IsRunning() const;
|
|
|
|
// Sets the task runner on which the delayed task should be scheduled when
|
|
// this Timer is running. This method can only be called while this Timer
|
|
// isn't running. If this is used to mock time in tests, the modern and
|
|
// preferred approach is to use TaskEnvironment::TimeSource::MOCK_TIME. To
|
|
// avoid racy usage of Timer, |task_runner| must run tasks on the same
|
|
// sequence which this Timer is bound to (started from). TODO(gab): Migrate
|
|
// callers using this as a test seam to
|
|
// TaskEnvironment::TimeSource::MOCK_TIME.
|
|
virtual void SetTaskRunner(scoped_refptr<SequencedTaskRunner> task_runner);
|
|
|
|
// Call this method to stop the timer and cancel all previously scheduled
|
|
// tasks. It is a no-op if the timer is not running.
|
|
virtual void Stop();
|
|
|
|
protected:
|
|
// Constructs a timer. Start must be called later to set task info.
|
|
explicit TimerBase(const Location& posted_from = Location());
|
|
|
|
virtual void OnStop() = 0;
|
|
|
|
// Disables the scheduled task and abandons it so that it no longer refers
|
|
// back to this object.
|
|
void AbandonScheduledTask();
|
|
|
|
// Returns the task runner on which the task should be scheduled. If the
|
|
// corresponding |task_runner_| field is null, the task runner for the current
|
|
// sequence is returned.
|
|
scoped_refptr<SequencedTaskRunner> GetTaskRunner();
|
|
|
|
// The task runner on which the task should be scheduled. If it is null, the
|
|
// task runner for the current sequence will be used.
|
|
scoped_refptr<SequencedTaskRunner> task_runner_;
|
|
|
|
// Timer isn't thread-safe and while it is running, it must only be used on
|
|
// the same sequence until fully Stop()'ed. Once stopped, it may be destroyed
|
|
// or restarted on another sequence.
|
|
SEQUENCE_CHECKER(sequence_checker_);
|
|
|
|
// Location in user code.
|
|
Location posted_from_ GUARDED_BY_CONTEXT(sequence_checker_);
|
|
|
|
// The handle to the posted delayed task.
|
|
DelayedTaskHandle delayed_task_handle_ GUARDED_BY_CONTEXT(sequence_checker_);
|
|
|
|
// Callback invoked when the timer is ready. This is saved as a member to
|
|
// avoid rebinding every time the Timer fires. Lazy initialized the first time
|
|
// the Timer is started.
|
|
RepeatingClosure timer_callback_;
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// This class wraps logic shared by (Retaining)OneShotTimer and RepeatingTimer.
|
|
class BASE_EXPORT DelayTimerBase : public TimerBase {
|
|
public:
|
|
DelayTimerBase(const DelayTimerBase&) = delete;
|
|
DelayTimerBase& operator=(const DelayTimerBase&) = delete;
|
|
|
|
~DelayTimerBase() override;
|
|
|
|
// Returns the current delay for this timer.
|
|
TimeDelta GetCurrentDelay() const;
|
|
|
|
// Call this method to reset the timer delay. The user task must be set. If
|
|
// the timer is not running, this will start it by posting a task.
|
|
virtual void Reset();
|
|
|
|
// DEPRECATED. Call Stop() instead.
|
|
// TODO(1262205): Remove this method and all callers.
|
|
void AbandonAndStop();
|
|
|
|
TimeTicks desired_run_time() const {
|
|
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
|
return desired_run_time_;
|
|
}
|
|
|
|
protected:
|
|
// Constructs a timer. Start must be called later to set task info.
|
|
// If |tick_clock| is provided, it is used instead of TimeTicks::Now() to get
|
|
// TimeTicks when scheduling tasks.
|
|
explicit DelayTimerBase(const TickClock* tick_clock = nullptr);
|
|
|
|
// Construct a timer with task info.
|
|
// If |tick_clock| is provided, it is used instead of TimeTicks::Now() to get
|
|
// TimeTicks when scheduling tasks.
|
|
DelayTimerBase(const Location& posted_from,
|
|
TimeDelta delay,
|
|
const TickClock* tick_clock = nullptr);
|
|
|
|
virtual void RunUserTask() = 0;
|
|
|
|
// Schedules |OnScheduledTaskInvoked()| to run on the current sequence with
|
|
// the given |delay|. |desired_run_time_| is reset to Now() + delay.
|
|
void ScheduleNewTask(TimeDelta delay);
|
|
|
|
void StartInternal(const Location& posted_from, TimeDelta delay);
|
|
|
|
private:
|
|
// DCHECKs that the user task is not null. Used to diagnose a recurring bug
|
|
// where Reset() is called on a OneShotTimer that has already fired.
|
|
virtual void EnsureNonNullUserTask() = 0;
|
|
|
|
// Returns the current tick count.
|
|
TimeTicks Now() const;
|
|
|
|
// Called when the scheduled task is invoked. Will run the |user_task| if the
|
|
// timer is still running and |desired_run_time_| was reached.
|
|
void OnScheduledTaskInvoked();
|
|
|
|
// Delay requested by user.
|
|
TimeDelta delay_ GUARDED_BY_CONTEXT(sequence_checker_);
|
|
|
|
// The desired run time of |user_task_|. The user may update this at any time,
|
|
// even if their previous request has not run yet. This time can be a "zero"
|
|
// TimeTicks if the task must be run immediately.
|
|
TimeTicks desired_run_time_ GUARDED_BY_CONTEXT(sequence_checker_);
|
|
|
|
// The tick clock used to calculate the run time for scheduled tasks.
|
|
const raw_ptr<const TickClock> tick_clock_
|
|
GUARDED_BY_CONTEXT(sequence_checker_);
|
|
};
|
|
|
|
} // namespace internal
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// A simple, one-shot timer. See usage notes at the top of the file.
|
|
class BASE_EXPORT OneShotTimer : public internal::DelayTimerBase {
|
|
public:
|
|
OneShotTimer();
|
|
explicit OneShotTimer(const TickClock* tick_clock);
|
|
|
|
OneShotTimer(const OneShotTimer&) = delete;
|
|
OneShotTimer& operator=(const OneShotTimer&) = delete;
|
|
|
|
~OneShotTimer() override;
|
|
|
|
// Start the timer to run at the given |delay| from now. If the timer is
|
|
// already running, it will be replaced to call the given |user_task|.
|
|
virtual void Start(const Location& posted_from,
|
|
TimeDelta delay,
|
|
OnceClosure user_task);
|
|
|
|
// Start the timer to run at the given |delay| from now. If the timer is
|
|
// already running, it will be replaced to call a task formed from
|
|
// |receiver->*method|.
|
|
template <class Receiver>
|
|
void Start(const Location& posted_from,
|
|
TimeDelta delay,
|
|
Receiver* receiver,
|
|
void (Receiver::*method)()) {
|
|
Start(posted_from, delay, BindOnce(method, Unretained(receiver)));
|
|
}
|
|
|
|
// Run the scheduled task immediately, and stop the timer. The timer needs to
|
|
// be running.
|
|
void FireNow();
|
|
|
|
private:
|
|
void OnStop() final;
|
|
void RunUserTask() final;
|
|
void EnsureNonNullUserTask() final;
|
|
|
|
OnceClosure user_task_;
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// A simple, repeating timer. See usage notes at the top of the file.
|
|
class BASE_EXPORT RepeatingTimer : public internal::DelayTimerBase {
|
|
public:
|
|
RepeatingTimer();
|
|
explicit RepeatingTimer(const TickClock* tick_clock);
|
|
|
|
RepeatingTimer(const RepeatingTimer&) = delete;
|
|
RepeatingTimer& operator=(const RepeatingTimer&) = delete;
|
|
|
|
~RepeatingTimer() override;
|
|
|
|
RepeatingTimer(const Location& posted_from,
|
|
TimeDelta delay,
|
|
RepeatingClosure user_task);
|
|
RepeatingTimer(const Location& posted_from,
|
|
TimeDelta delay,
|
|
RepeatingClosure user_task,
|
|
const TickClock* tick_clock);
|
|
|
|
// Start the timer to run at the given |delay| from now. If the timer is
|
|
// already running, it will be replaced to call the given |user_task|.
|
|
virtual void Start(const Location& posted_from,
|
|
TimeDelta delay,
|
|
RepeatingClosure user_task);
|
|
|
|
// Start the timer to run at the given |delay| from now. If the timer is
|
|
// already running, it will be replaced to call a task formed from
|
|
// |receiver->*method|.
|
|
template <class Receiver>
|
|
void Start(const Location& posted_from,
|
|
TimeDelta delay,
|
|
Receiver* receiver,
|
|
void (Receiver::*method)()) {
|
|
Start(posted_from, delay, BindRepeating(method, Unretained(receiver)));
|
|
}
|
|
|
|
const RepeatingClosure& user_task() const { return user_task_; }
|
|
|
|
private:
|
|
// Mark this final, so that the destructor can call this safely.
|
|
void OnStop() final;
|
|
void RunUserTask() override;
|
|
void EnsureNonNullUserTask() final;
|
|
|
|
RepeatingClosure user_task_;
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// A simple, one-shot timer with the retained |user_task| which is reused when
|
|
// Reset() is invoked. See usage notes at the top of the file.
|
|
class BASE_EXPORT RetainingOneShotTimer : public internal::DelayTimerBase {
|
|
public:
|
|
RetainingOneShotTimer();
|
|
explicit RetainingOneShotTimer(const TickClock* tick_clock);
|
|
|
|
RetainingOneShotTimer(const RetainingOneShotTimer&) = delete;
|
|
RetainingOneShotTimer& operator=(const RetainingOneShotTimer&) = delete;
|
|
|
|
~RetainingOneShotTimer() override;
|
|
|
|
RetainingOneShotTimer(const Location& posted_from,
|
|
TimeDelta delay,
|
|
RepeatingClosure user_task);
|
|
RetainingOneShotTimer(const Location& posted_from,
|
|
TimeDelta delay,
|
|
RepeatingClosure user_task,
|
|
const TickClock* tick_clock);
|
|
|
|
// Start the timer to run at the given |delay| from now. If the timer is
|
|
// already running, it will be replaced to call the given |user_task|.
|
|
virtual void Start(const Location& posted_from,
|
|
TimeDelta delay,
|
|
RepeatingClosure user_task);
|
|
|
|
// Start the timer to run at the given |delay| from now. If the timer is
|
|
// already running, it will be replaced to call a task formed from
|
|
// |receiver->*method|.
|
|
template <class Receiver>
|
|
void Start(const Location& posted_from,
|
|
TimeDelta delay,
|
|
Receiver* receiver,
|
|
void (Receiver::*method)()) {
|
|
Start(posted_from, delay, BindRepeating(method, Unretained(receiver)));
|
|
}
|
|
|
|
const RepeatingClosure& user_task() const { return user_task_; }
|
|
|
|
private:
|
|
// Mark this final, so that the destructor can call this safely.
|
|
void OnStop() final;
|
|
void RunUserTask() override;
|
|
void EnsureNonNullUserTask() final;
|
|
|
|
RepeatingClosure user_task_;
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// A Delay timer is like The Button from Lost. Once started, you have to keep
|
|
// calling Reset otherwise it will call the given method on the sequence it was
|
|
// initially Reset() from.
|
|
//
|
|
// Once created, it is inactive until Reset is called. Once |delay| seconds have
|
|
// passed since the last call to Reset, the callback is made. Once the callback
|
|
// has been made, it's inactive until Reset is called again.
|
|
//
|
|
// If destroyed, the timeout is canceled and will not occur even if already
|
|
// inflight.
|
|
class DelayTimer {
|
|
public:
|
|
template <class Receiver>
|
|
DelayTimer(const Location& posted_from,
|
|
TimeDelta delay,
|
|
Receiver* receiver,
|
|
void (Receiver::*method)())
|
|
: DelayTimer(posted_from, delay, receiver, method, nullptr) {}
|
|
|
|
template <class Receiver>
|
|
DelayTimer(const Location& posted_from,
|
|
TimeDelta delay,
|
|
Receiver* receiver,
|
|
void (Receiver::*method)(),
|
|
const TickClock* tick_clock)
|
|
: timer_(posted_from,
|
|
delay,
|
|
BindRepeating(method, Unretained(receiver)),
|
|
tick_clock) {}
|
|
|
|
DelayTimer(const DelayTimer&) = delete;
|
|
DelayTimer& operator=(const DelayTimer&) = delete;
|
|
|
|
void Reset() { timer_.Reset(); }
|
|
|
|
private:
|
|
RetainingOneShotTimer timer_;
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// A one-shot timer that attempts to run |user_task| some time near specified
|
|
// deadline. See usage notes at the top of the file.
|
|
class BASE_EXPORT DeadlineTimer : public internal::TimerBase {
|
|
public:
|
|
DeadlineTimer();
|
|
~DeadlineTimer() override;
|
|
|
|
DeadlineTimer(const DeadlineTimer&) = delete;
|
|
DeadlineTimer& operator=(const DeadlineTimer&) = delete;
|
|
|
|
// Start the timer to run |user_task| near the specified |deadline| following
|
|
// |delay_policy| If the timer is already running, it will be replaced to call
|
|
// the given |user_task|.
|
|
void Start(const Location& posted_from,
|
|
TimeTicks deadline,
|
|
OnceClosure user_task,
|
|
subtle::DelayPolicy delay_policy =
|
|
subtle::DelayPolicy::kFlexiblePreferEarly);
|
|
|
|
// Start the timer to run |user_task| near the specified |deadline|. If the
|
|
// timer is already running, it will be replaced to call a task formed from
|
|
// |receiver->*method|.
|
|
template <class Receiver>
|
|
void Start(const Location& posted_from,
|
|
TimeTicks deadline,
|
|
Receiver* receiver,
|
|
void (Receiver::*method)(),
|
|
subtle::DelayPolicy delay_policy =
|
|
subtle::DelayPolicy::kFlexiblePreferEarly) {
|
|
Start(posted_from, deadline, BindOnce(method, Unretained(receiver)),
|
|
delay_policy);
|
|
}
|
|
|
|
protected:
|
|
void OnStop() override;
|
|
|
|
// Schedules |OnScheduledTaskInvoked()| to run on the current sequence at
|
|
// the given |deadline|.
|
|
void ScheduleNewTask(TimeTicks deadline, subtle::DelayPolicy delay_policy);
|
|
|
|
private:
|
|
// Called when the scheduled task is invoked to run the |user_task|.
|
|
void OnScheduledTaskInvoked();
|
|
|
|
OnceClosure user_task_;
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Repeatedly invokes a callback, waiting for a precise delay between the
|
|
// beginning of each invocation. See usage notes at the top of the file.
|
|
class BASE_EXPORT MetronomeTimer : public internal::TimerBase {
|
|
public:
|
|
MetronomeTimer();
|
|
~MetronomeTimer() override;
|
|
|
|
MetronomeTimer(const MetronomeTimer&) = delete;
|
|
MetronomeTimer& operator=(const MetronomeTimer&) = delete;
|
|
|
|
MetronomeTimer(const Location& posted_from,
|
|
TimeDelta interval,
|
|
RepeatingClosure user_task,
|
|
TimeTicks phase = TimeTicks());
|
|
|
|
// Start the timer to repeatedly run |user_task| at the specified |interval|;
|
|
// If not specified, the phase is up to the scheduler, otherwise each
|
|
// invocation starts as close as possible to `phase + n * delay` for some
|
|
// integer n. If the timer is already running, it will be replaced to call the
|
|
// given |user_task|.
|
|
void Start(const Location& posted_from,
|
|
TimeDelta interval,
|
|
RepeatingClosure user_task,
|
|
TimeTicks phase = TimeTicks());
|
|
|
|
// Same as the previous overload, except that the user task is specified by
|
|
// `receiver` and `method`.
|
|
template <class Receiver>
|
|
void Start(const Location& posted_from,
|
|
TimeDelta interval,
|
|
Receiver* receiver,
|
|
void (Receiver::*method)(),
|
|
TimeTicks phase = TimeTicks()) {
|
|
Start(posted_from, interval, BindRepeating(method, Unretained(receiver)),
|
|
phase);
|
|
}
|
|
|
|
// Call this method to reset the timer delay. The user task must be set. If
|
|
// the timer is not running, this will start it by posting a task.
|
|
void Reset();
|
|
|
|
protected:
|
|
void OnStop() override;
|
|
|
|
// Schedules |OnScheduledTaskInvoked()| to run on the current sequence at
|
|
// the next tick.
|
|
void ScheduleNewTask();
|
|
|
|
private:
|
|
// Called when the scheduled task is invoked to run the |user_task|.
|
|
void OnScheduledTaskInvoked();
|
|
|
|
TimeDelta interval_;
|
|
RepeatingClosure user_task_;
|
|
TimeTicks phase_;
|
|
};
|
|
|
|
} // namespace base
|
|
|
|
#endif // BASE_TIMER_TIMER_H_
|