• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 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 "components/domain_reliability/dispatcher.h"
6 
7 #include "base/bind.h"
8 #include "base/callback.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/stl_util.h"
11 #include "base/timer/timer.h"
12 #include "components/domain_reliability/util.h"
13 
14 namespace domain_reliability {
15 
16 struct DomainReliabilityDispatcher::Task {
17   Task(const base::Closure& closure,
18        scoped_ptr<MockableTime::Timer> timer,
19        base::TimeDelta min_delay,
20        base::TimeDelta max_delay);
21   ~Task();
22 
23   base::Closure closure;
24   scoped_ptr<MockableTime::Timer> timer;
25   base::TimeDelta min_delay;
26   base::TimeDelta max_delay;
27   bool eligible;
28 };
29 
Task(const base::Closure & closure,scoped_ptr<MockableTime::Timer> timer,base::TimeDelta min_delay,base::TimeDelta max_delay)30 DomainReliabilityDispatcher::Task::Task(const base::Closure& closure,
31                                         scoped_ptr<MockableTime::Timer> timer,
32                                         base::TimeDelta min_delay,
33                                         base::TimeDelta max_delay)
34     : closure(closure),
35       timer(timer.Pass()),
36       min_delay(min_delay),
37       max_delay(max_delay),
38       eligible(false) {}
39 
~Task()40 DomainReliabilityDispatcher::Task::~Task() {}
41 
DomainReliabilityDispatcher(MockableTime * time)42 DomainReliabilityDispatcher::DomainReliabilityDispatcher(MockableTime* time)
43     : time_(time) {}
44 
~DomainReliabilityDispatcher()45 DomainReliabilityDispatcher::~DomainReliabilityDispatcher() {
46   // TODO(ttuttle): STLElementDeleter?
47   STLDeleteElements(&tasks_);
48 }
49 
ScheduleTask(const base::Closure & closure,base::TimeDelta min_delay,base::TimeDelta max_delay)50 void DomainReliabilityDispatcher::ScheduleTask(
51     const base::Closure& closure,
52     base::TimeDelta min_delay,
53     base::TimeDelta max_delay) {
54   DCHECK(!closure.is_null());
55   // Would be DCHECK_LE, but you can't << a TimeDelta.
56   DCHECK(min_delay <= max_delay);
57 
58   Task* task = new Task(closure, time_->CreateTimer(), min_delay, max_delay);
59   tasks_.insert(task);
60   if (max_delay.InMicroseconds() < 0)
61     RunAndDeleteTask(task);
62   else if (min_delay.InMicroseconds() < 0)
63     MakeTaskEligible(task);
64   else
65     MakeTaskWaiting(task);
66 }
67 
RunEligibleTasks()68 void DomainReliabilityDispatcher::RunEligibleTasks() {
69   // Move all eligible tasks to a separate set so that eligible_tasks_.erase in
70   // RunAndDeleteTask won't erase elements out from under the iterator.  (Also
71   // keeps RunEligibleTasks from running forever if a task adds a new, already-
72   // eligible task that does the same, and so on.)
73   std::set<Task*> tasks;
74   tasks.swap(eligible_tasks_);
75 
76   for (std::set<Task*>::const_iterator it = tasks.begin();
77        it != tasks.end();
78        ++it) {
79     Task* task = *it;
80     DCHECK(task);
81     DCHECK(task->eligible);
82     RunAndDeleteTask(task);
83   }
84 }
85 
MakeTaskWaiting(Task * task)86 void DomainReliabilityDispatcher::MakeTaskWaiting(Task* task) {
87   DCHECK(task);
88   DCHECK(!task->eligible);
89   DCHECK(!task->timer->IsRunning());
90   task->timer->Start(FROM_HERE,
91                      task->min_delay,
92                      base::Bind(&DomainReliabilityDispatcher::MakeTaskEligible,
93                                 base::Unretained(this),
94                                 task));
95 }
96 
97 void
MakeTaskEligible(Task * task)98 DomainReliabilityDispatcher::MakeTaskEligible(Task* task) {
99   DCHECK(task);
100   DCHECK(!task->eligible);
101   task->eligible = true;
102   eligible_tasks_.insert(task);
103   task->timer->Start(FROM_HERE,
104                      task->max_delay - task->min_delay,
105                      base::Bind(&DomainReliabilityDispatcher::RunAndDeleteTask,
106                                 base::Unretained(this),
107                                 task));
108 }
109 
RunAndDeleteTask(Task * task)110 void DomainReliabilityDispatcher::RunAndDeleteTask(Task* task) {
111   DCHECK(task);
112   DCHECK(!task->closure.is_null());
113   task->closure.Run();
114   if (task->eligible)
115     eligible_tasks_.erase(task);
116   tasks_.erase(task);
117   delete task;
118 }
119 
120 }  // namespace domain_reliability
121