1b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// Use of this source code is governed by a BSD-style license that can be 3b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// found in the LICENSE file. 4b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 5b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/threading/worker_pool_posix.h" 6b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 7cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko#include <stddef.h> 8cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko 9b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/bind.h" 10b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/callback.h" 11b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/lazy_instance.h" 12b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/logging.h" 13cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko#include "base/macros.h" 14b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/memory/ref_counted.h" 15b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/strings/stringprintf.h" 16b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/threading/platform_thread.h" 17b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/threading/thread_local.h" 18b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/threading/worker_pool.h" 19b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/trace_event/trace_event.h" 20b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/tracked_objects.h" 21b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 22b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratusing tracked_objects::TrackedTime; 23b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 24b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratnamespace base { 25b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 26b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratnamespace { 27b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 28b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratbase::LazyInstance<ThreadLocalBoolean>::Leaky 29b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat g_worker_pool_running_on_this_thread = LAZY_INSTANCE_INITIALIZER; 30b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 31b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratconst int kIdleSecondsBeforeExit = 10 * 60; 32b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 33b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratclass WorkerPoolImpl { 34b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat public: 35b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat WorkerPoolImpl(); 36b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat ~WorkerPoolImpl(); 37b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 38b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat void PostTask(const tracked_objects::Location& from_here, 39cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko const base::Closure& task, 40cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko bool task_is_slow); 41b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 42b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat private: 43b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat scoped_refptr<base::PosixDynamicThreadPool> pool_; 44b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}; 45b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 46b8cf94937c52feb53b55c39e3f82094d27de464cDaniel EratWorkerPoolImpl::WorkerPoolImpl() 47b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat : pool_(new base::PosixDynamicThreadPool("WorkerPool", 48cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko kIdleSecondsBeforeExit)) {} 49b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 50b8cf94937c52feb53b55c39e3f82094d27de464cDaniel EratWorkerPoolImpl::~WorkerPoolImpl() { 51b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat pool_->Terminate(); 52b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 53b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 54b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid WorkerPoolImpl::PostTask(const tracked_objects::Location& from_here, 5560d96a4a9e0d8c78d46c1f86dec60f9ecdbedbdbChristopher Wiley const base::Closure& task, 5660d96a4a9e0d8c78d46c1f86dec60f9ecdbedbdbChristopher Wiley bool /* task_is_slow */) { 57b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat pool_->PostTask(from_here, task); 58b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 59b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 60b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratbase::LazyInstance<WorkerPoolImpl> g_lazy_worker_pool = 61b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat LAZY_INSTANCE_INITIALIZER; 62b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 63b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratclass WorkerThread : public PlatformThread::Delegate { 64b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat public: 65b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat WorkerThread(const std::string& name_prefix, 66b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat base::PosixDynamicThreadPool* pool) 67cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko : name_prefix_(name_prefix), pool_(pool) {} 68b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 69b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat void ThreadMain() override; 70b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 71b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat private: 72b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat const std::string name_prefix_; 73b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat scoped_refptr<base::PosixDynamicThreadPool> pool_; 74b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 75b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat DISALLOW_COPY_AND_ASSIGN(WorkerThread); 76b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}; 77b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 78b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid WorkerThread::ThreadMain() { 79b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat g_worker_pool_running_on_this_thread.Get().Set(true); 80cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko const std::string name = base::StringPrintf("%s/%d", name_prefix_.c_str(), 81cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko PlatformThread::CurrentId()); 82b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // Note |name.c_str()| must remain valid for for the whole life of the thread. 83b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat PlatformThread::SetName(name); 84b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 85b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat for (;;) { 86b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat PendingTask pending_task = pool_->WaitForTask(); 87b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (pending_task.task.is_null()) 88b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat break; 89b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat TRACE_EVENT2("toplevel", "WorkerThread::ThreadMain::Run", 90b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat "src_file", pending_task.posted_from.file_name(), 91b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat "src_func", pending_task.posted_from.function_name()); 92b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 93b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat tracked_objects::TaskStopwatch stopwatch; 94b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat stopwatch.Start(); 95b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat pending_task.task.Run(); 96b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat stopwatch.Stop(); 97b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 98b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat tracked_objects::ThreadData::TallyRunOnWorkerThreadIfTracking( 99b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat pending_task.birth_tally, pending_task.time_posted, stopwatch); 100b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 101b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 102b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // The WorkerThread is non-joinable, so it deletes itself. 103b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat delete this; 104b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 105b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 106b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} // namespace 107b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 108b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// static 109b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratbool WorkerPool::PostTask(const tracked_objects::Location& from_here, 110cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko const base::Closure& task, 111cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko bool task_is_slow) { 112b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat g_lazy_worker_pool.Pointer()->PostTask(from_here, task, task_is_slow); 113b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat return true; 114b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 115b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 116b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// static 117b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratbool WorkerPool::RunsTasksOnCurrentThread() { 118b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat return g_worker_pool_running_on_this_thread.Get().Get(); 119b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 120b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 121b8cf94937c52feb53b55c39e3f82094d27de464cDaniel EratPosixDynamicThreadPool::PosixDynamicThreadPool(const std::string& name_prefix, 122b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat int idle_seconds_before_exit) 123b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat : name_prefix_(name_prefix), 124b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat idle_seconds_before_exit_(idle_seconds_before_exit), 125b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat pending_tasks_available_cv_(&lock_), 126b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat num_idle_threads_(0), 127b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat terminated_(false) {} 128b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 129b8cf94937c52feb53b55c39e3f82094d27de464cDaniel EratPosixDynamicThreadPool::~PosixDynamicThreadPool() { 130b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat while (!pending_tasks_.empty()) 131b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat pending_tasks_.pop(); 132b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 133b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 134b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid PosixDynamicThreadPool::Terminate() { 135b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat { 136b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat AutoLock locked(lock_); 137b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat DCHECK(!terminated_) << "Thread pool is already terminated."; 138b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat terminated_ = true; 139b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 140b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat pending_tasks_available_cv_.Broadcast(); 141b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 142b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 143b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid PosixDynamicThreadPool::PostTask( 144b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat const tracked_objects::Location& from_here, 145b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat const base::Closure& task) { 146b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat PendingTask pending_task(from_here, task); 147b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat AddTask(&pending_task); 148b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 149b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 150b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid PosixDynamicThreadPool::AddTask(PendingTask* pending_task) { 151b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat AutoLock locked(lock_); 152cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko DCHECK(!terminated_) 153cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko << "This thread pool is already terminated. Do not post new tasks."; 154b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 155b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat pending_tasks_.push(*pending_task); 156b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat pending_task->task.Reset(); 157b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 158b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // We have enough worker threads. 159b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (static_cast<size_t>(num_idle_threads_) >= pending_tasks_.size()) { 160b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat pending_tasks_available_cv_.Signal(); 161b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } else { 162b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // The new PlatformThread will take ownership of the WorkerThread object, 163b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // which will delete itself on exit. 164cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko WorkerThread* worker = new WorkerThread(name_prefix_, this); 165b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat PlatformThread::CreateNonJoinable(0, worker); 166b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 167b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 168b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 169b8cf94937c52feb53b55c39e3f82094d27de464cDaniel EratPendingTask PosixDynamicThreadPool::WaitForTask() { 170b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat AutoLock locked(lock_); 171b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 172b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (terminated_) 173b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat return PendingTask(FROM_HERE, base::Closure()); 174b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 175b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (pending_tasks_.empty()) { // No work available, wait for work. 176b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat num_idle_threads_++; 177b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (num_idle_threads_cv_.get()) 178b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat num_idle_threads_cv_->Signal(); 179b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat pending_tasks_available_cv_.TimedWait( 180b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat TimeDelta::FromSeconds(idle_seconds_before_exit_)); 181b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat num_idle_threads_--; 182b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (num_idle_threads_cv_.get()) 183b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat num_idle_threads_cv_->Signal(); 184b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (pending_tasks_.empty()) { 185b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // We waited for work, but there's still no work. Return NULL to signal 186b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // the thread to terminate. 187b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat return PendingTask(FROM_HERE, base::Closure()); 188b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 189b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 190b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 191b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat PendingTask pending_task = pending_tasks_.front(); 192b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat pending_tasks_.pop(); 193b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat return pending_task; 194b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 195b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 196b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} // namespace base 197