blob: 0dd1c17674a5e2b1b19c9dfeebd9cdbad18c5b5c [file] [log] [blame]
[email protected]bda8e362014-03-24 18:21:031// 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
avi12ce31d2016-08-30 16:38:057#include <algorithm>
Gyuyoung Kim6afb5082018-01-19 13:35:578#include <memory>
dcheng51606352015-12-26 21:16:239#include <utility>
10
[email protected]bda8e362014-03-24 18:21:0311#include "base/bind.h"
[email protected]b5c2b742014-06-14 22:21:4212#include "base/callback.h"
[email protected]bda8e362014-03-24 18:21:0313#include "base/timer/timer.h"
14#include "components/domain_reliability/util.h"
15
16namespace domain_reliability {
17
[email protected]84d2a492014-05-09 22:18:5018struct DomainReliabilityDispatcher::Task {
19 Task(const base::Closure& closure,
dcheng04a35cd2016-04-22 15:07:2420 std::unique_ptr<MockableTime::Timer> timer,
[email protected]84d2a492014-05-09 22:18:5021 base::TimeDelta min_delay,
22 base::TimeDelta max_delay);
23 ~Task();
24
25 base::Closure closure;
dcheng04a35cd2016-04-22 15:07:2426 std::unique_ptr<MockableTime::Timer> timer;
[email protected]84d2a492014-05-09 22:18:5027 base::TimeDelta min_delay;
28 base::TimeDelta max_delay;
29 bool eligible;
30};
31
dcheng04a35cd2016-04-22 15:07:2432DomainReliabilityDispatcher::Task::Task(
33 const base::Closure& closure,
34 std::unique_ptr<MockableTime::Timer> timer,
35 base::TimeDelta min_delay,
36 base::TimeDelta max_delay)
[email protected]84d2a492014-05-09 22:18:5037 : closure(closure),
dcheng51606352015-12-26 21:16:2338 timer(std::move(timer)),
[email protected]84d2a492014-05-09 22:18:5039 min_delay(min_delay),
40 max_delay(max_delay),
41 eligible(false) {}
42
43DomainReliabilityDispatcher::Task::~Task() {}
44
[email protected]bda8e362014-03-24 18:21:0345DomainReliabilityDispatcher::DomainReliabilityDispatcher(MockableTime* time)
46 : time_(time) {}
47
avi12ce31d2016-08-30 16:38:0548DomainReliabilityDispatcher::~DomainReliabilityDispatcher() {}
[email protected]bda8e362014-03-24 18:21:0349
50void 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
Gyuyoung Kim6afb5082018-01-19 13:35:5758 std::unique_ptr<Task> owned_task = std::make_unique<Task>(
avi12ce31d2016-08-30 16:38:0559 closure, time_->CreateTimer(), min_delay, max_delay);
60 Task* task = owned_task.get();
61 tasks_.insert(std::move(owned_task));
[email protected]bda8e362014-03-24 18:21:0362 if (max_delay.InMicroseconds() < 0)
63 RunAndDeleteTask(task);
64 else if (min_delay.InMicroseconds() < 0)
65 MakeTaskEligible(task);
66 else
67 MakeTaskWaiting(task);
68}
69
70void DomainReliabilityDispatcher::RunEligibleTasks() {
71 // Move all eligible tasks to a separate set so that eligible_tasks_.erase in
72 // RunAndDeleteTask won't erase elements out from under the iterator. (Also
73 // keeps RunEligibleTasks from running forever if a task adds a new, already-
74 // eligible task that does the same, and so on.)
75 std::set<Task*> tasks;
76 tasks.swap(eligible_tasks_);
77
vmpstr2de366b2016-07-20 21:35:4878 for (auto* task : tasks) {
[email protected]bda8e362014-03-24 18:21:0379 DCHECK(task);
80 DCHECK(task->eligible);
81 RunAndDeleteTask(task);
82 }
83}
84
juliatuttle127604ea2016-12-19 19:13:0485void DomainReliabilityDispatcher::RunAllTasksForTesting() {
86 std::set<Task*> tasks;
87 for (auto& task : tasks_)
88 tasks.insert(task.get());
89
90 for (auto* task : tasks) {
91 DCHECK(task);
92 RunAndDeleteTask(task);
93 }
94}
95
[email protected]bda8e362014-03-24 18:21:0396void DomainReliabilityDispatcher::MakeTaskWaiting(Task* task) {
97 DCHECK(task);
98 DCHECK(!task->eligible);
99 DCHECK(!task->timer->IsRunning());
[email protected]84d2a492014-05-09 22:18:50100 task->timer->Start(FROM_HERE,
101 task->min_delay,
102 base::Bind(&DomainReliabilityDispatcher::MakeTaskEligible,
103 base::Unretained(this),
104 task));
[email protected]bda8e362014-03-24 18:21:03105}
106
107void
108DomainReliabilityDispatcher::MakeTaskEligible(Task* task) {
109 DCHECK(task);
110 DCHECK(!task->eligible);
111 task->eligible = true;
112 eligible_tasks_.insert(task);
[email protected]84d2a492014-05-09 22:18:50113 task->timer->Start(FROM_HERE,
114 task->max_delay - task->min_delay,
115 base::Bind(&DomainReliabilityDispatcher::RunAndDeleteTask,
116 base::Unretained(this),
117 task));
[email protected]bda8e362014-03-24 18:21:03118}
119
120void DomainReliabilityDispatcher::RunAndDeleteTask(Task* task) {
121 DCHECK(task);
122 DCHECK(!task->closure.is_null());
123 task->closure.Run();
124 if (task->eligible)
125 eligible_tasks_.erase(task);
avi12ce31d2016-08-30 16:38:05126
127 auto it = std::find_if(tasks_.begin(), tasks_.end(),
128 [task](const std::unique_ptr<Task>& task_ptr) {
129 return task_ptr.get() == task;
130 });
131
132 DCHECK(it != tasks_.end());
133 tasks_.erase(it);
[email protected]bda8e362014-03-24 18:21:03134}
135
136} // namespace domain_reliability