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