106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// Copyright (c) 2010 The Chromium Authors. All rights reserved.
206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// Use of this source code is governed by a BSD-style license that can be
306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// found in the LICENSE file.
406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include "chrome/common/worker_thread_ticker.h"
606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include <algorithm>
806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include "base/logging.h"
1006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include "base/message_loop.h"
1106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include "base/task.h"
123f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/threading/thread.h"
1306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
1406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochclass WorkerThreadTicker::TimerTask : public Task {
1506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch public:
1606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  explicit TimerTask(WorkerThreadTicker* ticker) : ticker_(ticker) {
1706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  }
1806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
1906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  virtual void Run() {
2006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    // When the ticker is running, the handler list CANNOT be modified.
2106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    // So we can do the enumeration safely without a lock
2206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    TickHandlerListType* handlers = &ticker_->tick_handler_list_;
2306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    for (TickHandlerListType::const_iterator i = handlers->begin();
2406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch         i != handlers->end(); ++i) {
2506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      (*i)->OnTick();
2606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    }
2706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
2806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    ticker_->ScheduleTimerTask();
2906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  }
3006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
3106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch private:
3206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  WorkerThreadTicker* ticker_;
3306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch};
3406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
3506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen MurdochWorkerThreadTicker::WorkerThreadTicker(int tick_interval)
3606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    : timer_thread_("worker_thread_ticker"),
3706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      is_running_(false),
3806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      tick_interval_(tick_interval) {
3906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch}
4006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
4106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen MurdochWorkerThreadTicker::~WorkerThreadTicker() {
4206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  Stop();
4306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch}
4406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
4506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochbool WorkerThreadTicker::RegisterTickHandler(Callback *tick_handler) {
4606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  DCHECK(tick_handler);
4772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  base::AutoLock lock(lock_);
4806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  // You cannot change the list of handlers when the timer is running.
4906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  // You need to call Stop first.
5006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  if (IsRunning())
5106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    return false;
5206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  tick_handler_list_.push_back(tick_handler);
5306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  return true;
5406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch}
5506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
5606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochbool WorkerThreadTicker::UnregisterTickHandler(Callback *tick_handler) {
5706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  DCHECK(tick_handler);
5872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  base::AutoLock lock(lock_);
5906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  // You cannot change the list of handlers when the timer is running.
6006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  // You need to call Stop first.
6106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  if (IsRunning()) {
6206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    return false;
6306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  }
6406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  TickHandlerListType::iterator index = std::remove(tick_handler_list_.begin(),
6506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch                                                    tick_handler_list_.end(),
6606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch                                                    tick_handler);
6706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  if (index == tick_handler_list_.end()) {
6806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    return false;
6906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  }
7006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  tick_handler_list_.erase(index, tick_handler_list_.end());
7106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  return true;
7206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch}
7306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
7406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochbool WorkerThreadTicker::Start() {
7506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  // Do this in a lock because we don't want 2 threads to
7606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  // call Start at the same time
7772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  base::AutoLock lock(lock_);
7806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  if (IsRunning())
7906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    return false;
8006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  if (!timer_thread_.Start())
8106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    return false;
8206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  is_running_ = true;
8306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  ScheduleTimerTask();
8406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  return true;
8506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch}
8606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
8706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochbool WorkerThreadTicker::Stop() {
8806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  // Do this in a lock because we don't want 2 threads to
8906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  // call Stop at the same time
9072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  base::AutoLock lock(lock_);
9106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  if (!IsRunning())
9206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    return false;
9306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  is_running_ = false;
9406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  timer_thread_.Stop();
9506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  return true;
9606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch}
9706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
9806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochvoid WorkerThreadTicker::ScheduleTimerTask() {
9906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  timer_thread_.message_loop()->PostDelayedTask(FROM_HERE, new TimerTask(this),
10006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch                                                tick_interval_);
10106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch}
102