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 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 40 DomainReliabilityDispatcher::Task::~Task() {} 41 42 DomainReliabilityDispatcher::DomainReliabilityDispatcher(MockableTime* time) 43 : time_(time) {} 44 45 DomainReliabilityDispatcher::~DomainReliabilityDispatcher() { 46 // TODO(ttuttle): STLElementDeleter? 47 STLDeleteElements(&tasks_); 48 } 49 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 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 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 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 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