1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "webkit/browser/fileapi/timed_task_helper.h"
6
7#include "base/bind.h"
8#include "base/logging.h"
9#include "base/sequenced_task_runner.h"
10
11namespace fileapi {
12
13struct TimedTaskHelper::Tracker {
14  explicit Tracker(TimedTaskHelper* timer) : timer(timer) {}
15
16  ~Tracker() {
17    if (timer)
18      timer->tracker_ = NULL;
19  }
20
21  TimedTaskHelper* timer;
22};
23
24TimedTaskHelper::TimedTaskHelper(base::SequencedTaskRunner* task_runner)
25    : task_runner_(task_runner),
26      tracker_(NULL) {
27}
28
29TimedTaskHelper::~TimedTaskHelper() {
30  DCHECK(task_runner_->RunsTasksOnCurrentThread());
31  if (tracker_)
32    tracker_->timer = NULL;
33}
34
35bool TimedTaskHelper::IsRunning() const {
36  DCHECK(task_runner_->RunsTasksOnCurrentThread());
37  return tracker_ != NULL;
38}
39
40void TimedTaskHelper::Start(
41    const tracked_objects::Location& posted_from,
42    base::TimeDelta delay,
43    const base::Closure& user_task) {
44  posted_from_ = posted_from;
45  delay_ = delay;
46  user_task_ = user_task;
47  Reset();
48}
49
50void TimedTaskHelper::Reset() {
51  DCHECK(task_runner_->RunsTasksOnCurrentThread());
52  DCHECK(!user_task_.is_null());
53  desired_run_time_ = base::TimeTicks::Now() + delay_;
54
55  if (tracker_)
56    return;
57
58  // Initialize the tracker for the first time.
59  tracker_ = new Tracker(this);
60  PostDelayedTask(make_scoped_ptr(tracker_), delay_);
61}
62
63// static
64void TimedTaskHelper::Fired(scoped_ptr<Tracker> tracker) {
65  if (!tracker->timer)
66    return;
67  TimedTaskHelper* timer = tracker->timer;
68  timer->OnFired(tracker.Pass());
69}
70
71void TimedTaskHelper::OnFired(scoped_ptr<Tracker> tracker) {
72  DCHECK(task_runner_->RunsTasksOnCurrentThread());
73  base::TimeTicks now = base::TimeTicks::Now();
74  if (desired_run_time_ > now) {
75    PostDelayedTask(tracker.Pass(), desired_run_time_ - now);
76    return;
77  }
78  tracker.reset();
79  base::Closure task = user_task_;
80  user_task_.Reset();
81  task.Run();
82}
83
84void TimedTaskHelper::PostDelayedTask(scoped_ptr<Tracker> tracker,
85                                      base::TimeDelta delay) {
86  task_runner_->PostDelayedTask(
87      posted_from_,
88      base::Bind(&TimedTaskHelper::Fired, base::Passed(&tracker)),
89      delay);
90}
91
92}  // namespace fileapi
93