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