Home | History | Annotate | Download | only in domain_reliability
      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