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