Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2788)

Unified Diff: base/timer/alarm_timer.cc

Issue 641943002: components: Introduce AlarmTimer class and use it for GCM heartbeat (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Make some Timer variables protected to reduce duplication, clean up comments Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: base/timer/alarm_timer.cc
diff --git a/base/timer/alarm_timer.cc b/base/timer/alarm_timer.cc
new file mode 100644
index 0000000000000000000000000000000000000000..bb73efbacecbb876f603c4ef273459b979f899be
--- /dev/null
+++ b/base/timer/alarm_timer.cc
@@ -0,0 +1,187 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/timer/alarm_timer.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/pending_task.h"
+
+#if defined(OS_CHROMEOS)
+#include "base/timer/rtc_alarm_chromeos.h"
+#endif
+
+namespace base {
+
+namespace {
+
+// Default delegate for the alarm timer on non-Chrome OS systems. Tells the
+// AlarmTimer class that it doesn't have the ability to wake the system from
+// suspend and that it should just behave as a regular Timer.
+class DefaultAlarmTimerDelegate : public base::AlarmTimer::Delegate {
+ public:
+ DefaultAlarmTimerDelegate() {}
+
+ virtual bool Init(base::WeakPtr<AlarmTimer> timer) override { return false; }
+ virtual void Stop() override {
+ NOTREACHED() << "Attempting to call Stop() on the default alarm timer "
+ << "delegate";
+ }
+ virtual void Reset(base::TimeDelta delay) override {
+ NOTREACHED() << "Attempting to call Reset() on the default alarm timer "
+ << "delegate";
+ }
+
+ protected:
+ virtual ~DefaultAlarmTimerDelegate() {}
+};
+
+} // namespace
+
+AlarmTimer::AlarmTimer(bool retain_user_task, bool is_repeating)
+ : Timer(retain_user_task, is_repeating),
+#if defined(OS_CHROMEOS)
+ delegate_(new RtcAlarmChromeos()),
+#else
+ delegate_(new DefaultAlarmTimerDelegate()),
+#endif
+ can_wake_from_suspend_(false),
+ origin_message_loop_(NULL),
+ weak_factory_(this) {
+ can_wake_from_suspend_ = delegate_->Init(weak_factory_.GetWeakPtr());
+}
+
+AlarmTimer::AlarmTimer(const tracked_objects::Location& posted_from,
+ TimeDelta delay,
+ const Closure& user_task,
+ bool is_repeating)
+ : Timer(posted_from, delay, user_task, is_repeating),
+#if defined(OS_CHROMEOS)
Daniel Erat 2014/10/15 15:04:22 i don't have strong feelings here, but it might be
Chirantan Ekbote 2014/10/16 21:26:38 Done.
+ delegate_(new RtcAlarmChromeos()),
+#else
+ delegate_(new DefaultAlarmTimerDelegate()),
+#endif
+ can_wake_from_suspend_(false),
+ origin_message_loop_(NULL),
+ weak_factory_(this) {
+ can_wake_from_suspend_ = delegate_->Init(weak_factory_.GetWeakPtr());
+}
+
+AlarmTimer::~AlarmTimer() {
+ Stop();
+}
+
+bool AlarmTimer::IsRunning() const {
+ if (!can_wake_from_suspend_)
Daniel Erat 2014/10/15 15:04:21 nit: return can_wake_from_suspend_ ? is_running
+ return Timer::IsRunning();
+
+ return is_running_;
+}
+
+TimeDelta AlarmTimer::GetCurrentDelay() const {
+ if (!can_wake_from_suspend_)
Daniel Erat 2014/10/15 15:04:21 nit: return can_wake_from_suspend_ ? delay_ : T
+ return Timer::GetCurrentDelay();
+
+ return delay_;
+}
+
+void AlarmTimer::Start(const tracked_objects::Location& posted_from,
+ TimeDelta delay,
+ const Closure& user_task) {
+ if (!can_wake_from_suspend_) {
+ Timer::Start(posted_from, delay, user_task);
+ return;
+ }
+
+ // This is identical to the implementation of Timer::Start but we have this
+ // one anyway for clarity.
Daniel Erat 2014/10/15 15:04:21 not sure i understand this. if this method is iden
Chirantan Ekbote 2014/10/16 21:26:38 It's being overridden so that someone reading the
+ Timer::SetTaskInfo(posted_from, delay, user_task);
+ Reset();
+}
+
+void AlarmTimer::Stop() {
+ if (!can_wake_from_suspend_) {
+ Timer::Stop();
+ return;
+ }
+
+ // Clear the running flag, stop the delegate, and delete the pending task.
+ is_running_ = false;
+ delegate_->Stop();
+ pending_task_.reset();
+
+ // Stop is called when the AlarmTimer is destroyed so we need to remove
+ // ourselves as a MessageLoop::DestructionObserver to prevent a segfault
+ // later.
+ if (origin_message_loop_) {
+ origin_message_loop_->RemoveDestructionObserver(this);
+ origin_message_loop_ = NULL;
+ }
+
+ if (!retain_user_task_)
+ user_task_.Reset();
+}
+
+void AlarmTimer::Reset() {
+ if (!can_wake_from_suspend_) {
+ Timer::Reset();
+ return;
+ }
+
+ DCHECK(!user_task_.is_null());
+ DCHECK(!origin_message_loop_ ||
+ origin_message_loop_->task_runner()->RunsTasksOnCurrentThread());
+
+ // Make sure that the timer will stop if the underlying message loop is
+ // destroyed.
+ if (!origin_message_loop_) {
+ origin_message_loop_ = MessageLoop::current();
+ origin_message_loop_->AddDestructionObserver(this);
+ }
+
+ // Set up the pending task.
+ if (delay_ == TimeDelta()) {
+ desired_run_time_ = TimeTicks();
+ pending_task_.reset(new PendingTask(posted_from_, user_task_));
+ } else {
+ desired_run_time_ = TimeTicks::Now() + delay_;
+ pending_task_.reset(
+ new PendingTask(posted_from_, user_task_, desired_run_time_, true));
+ }
+ MessageLoop::current()->task_annotator()->DidQueueTask("AlarmTimer::Reset",
+ *pending_task_);
+
+ // Now start up the timer.
+ delegate_->Reset(delay_);
+ is_running_ = true;
+}
+
+void AlarmTimer::WillDestroyCurrentMessageLoop() {
+ Stop();
+}
+
+void AlarmTimer::OnTimerFired() {
+ if (!is_running_)
+ return;
+
+ DCHECK(pending_task_.get());
+
+ // Take ownership of the pending user task, which is going to be cleared by
+ // the Stop() or Reset() functions below.
+ scoped_ptr<PendingTask> pending_user_task(pending_task_.Pass());
+
+ // Re-schedule or stop the timer as requested.
+ if (is_repeating_)
+ Reset();
+ else
+ Stop();
+
+ // Now lets run the user task.
Daniel Erat 2014/10/15 15:04:22 nit: s/lets/let's/ or just delete that word
Chirantan Ekbote 2014/10/16 21:26:38 Done.
+ MessageLoop::current()->task_annotator()->RunTask(
+ "AlarmTimer::Reset", "AlarmTimer::OnTimerFired", *pending_user_task);
+}
+
+} // namespace base

Powered by Google App Engine
This is Rietveld 408576698