Home | History | Annotate | Download | only in common
      1 // Copyright (c) 2012 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 "chrome/common/worker_thread_ticker.h"
      6 
      7 #include <algorithm>
      8 
      9 #include "base/bind.h"
     10 #include "base/bind_helpers.h"
     11 #include "base/logging.h"
     12 #include "base/message_loop/message_loop.h"
     13 #include "base/threading/thread.h"
     14 
     15 WorkerThreadTicker::WorkerThreadTicker(int tick_interval)
     16     : timer_thread_("worker_thread_ticker"),
     17       is_running_(false),
     18       tick_interval_(base::TimeDelta::FromMilliseconds(tick_interval)) {
     19 }
     20 
     21 WorkerThreadTicker::~WorkerThreadTicker() {
     22   Stop();
     23 }
     24 
     25 bool WorkerThreadTicker::RegisterTickHandler(Callback *tick_handler) {
     26   DCHECK(tick_handler);
     27   base::AutoLock lock(lock_);
     28   // You cannot change the list of handlers when the timer is running.
     29   // You need to call Stop first.
     30   if (IsRunning())
     31     return false;
     32   tick_handler_list_.push_back(tick_handler);
     33   return true;
     34 }
     35 
     36 bool WorkerThreadTicker::UnregisterTickHandler(Callback *tick_handler) {
     37   DCHECK(tick_handler);
     38   base::AutoLock lock(lock_);
     39   // You cannot change the list of handlers when the timer is running.
     40   // You need to call Stop first.
     41   if (IsRunning()) {
     42     return false;
     43   }
     44   TickHandlerListType::iterator index = std::remove(tick_handler_list_.begin(),
     45                                                     tick_handler_list_.end(),
     46                                                     tick_handler);
     47   if (index == tick_handler_list_.end()) {
     48     return false;
     49   }
     50   tick_handler_list_.erase(index, tick_handler_list_.end());
     51   return true;
     52 }
     53 
     54 bool WorkerThreadTicker::Start() {
     55   // Do this in a lock because we don't want 2 threads to
     56   // call Start at the same time
     57   base::AutoLock lock(lock_);
     58   if (IsRunning())
     59     return false;
     60   if (!timer_thread_.Start())
     61     return false;
     62   is_running_ = true;
     63   ScheduleTimerTask();
     64   return true;
     65 }
     66 
     67 bool WorkerThreadTicker::Stop() {
     68   // Do this in a lock because we don't want 2 threads to
     69   // call Stop at the same time
     70   base::AutoLock lock(lock_);
     71   if (!IsRunning())
     72     return false;
     73   is_running_ = false;
     74   timer_thread_.Stop();
     75   return true;
     76 }
     77 
     78 void WorkerThreadTicker::ScheduleTimerTask() {
     79   timer_thread_.message_loop()->PostDelayedTask(
     80       FROM_HERE,
     81       base::Bind(&WorkerThreadTicker::TimerTask, base::Unretained(this)),
     82       tick_interval_);
     83 }
     84 
     85 void WorkerThreadTicker::TimerTask() {
     86   // When the ticker is running, the handler list CANNOT be modified.
     87   // So we can do the enumeration safely without a lock
     88   const TickHandlerListType& handlers = tick_handler_list_;
     89   for (TickHandlerListType::const_iterator i = handlers.begin();
     90        i != handlers.end(); ++i) {
     91     (*i)->OnTick();
     92   }
     93 
     94   ScheduleTimerTask();
     95 }
     96 
     97