blob: b6c30e555a90be168ff3491f9f8e6f4c88c505b1 [file] [log] [blame]
[email protected]3b63f8f42011-03-28 01:54:151// Copyright (c) 2011 The Chromium Authors. All rights reserved.
[email protected]5846da02009-03-06 20:35:452// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]ac9ba8fe2010-12-30 18:08:365#include "base/threading/worker_pool_posix.h"
[email protected]5846da02009-03-06 20:35:456
[email protected]180c85e2011-07-26 18:25:167#include "base/bind.h"
[email protected]19d8a902011-10-03 17:51:258#include "base/debug/trace_event.h"
[email protected]250103f2009-03-24 23:41:539#include "base/lazy_instance.h"
[email protected]56d01f62009-03-12 22:41:5410#include "base/logging.h"
[email protected]3b63f8f42011-03-28 01:54:1511#include "base/memory/ref_counted.h"
[email protected]f1633932010-08-17 23:05:2812#include "base/stringprintf.h"
[email protected]5846da02009-03-06 20:35:4513#include "base/task.h"
[email protected]ce072a72010-12-31 20:02:1614#include "base/threading/platform_thread.h"
[email protected]ac9ba8fe2010-12-30 18:08:3615#include "base/threading/worker_pool.h"
[email protected]180c85e2011-07-26 18:25:1616#include "base/tracked_objects.h"
[email protected]ac9ba8fe2010-12-30 18:08:3617
18namespace base {
[email protected]5846da02009-03-06 20:35:4519
20namespace {
21
[email protected]250103f2009-03-24 23:41:5322const int kIdleSecondsBeforeExit = 10 * 60;
[email protected]82fbbe62009-05-28 08:45:1923// A stack size of 64 KB is too small for the CERT_PKIXVerifyCert
24// function of NSS because of NSS bug 439169.
25const int kWorkerThreadStackSize = 128 * 1024;
[email protected]250103f2009-03-24 23:41:5326
27class WorkerPoolImpl {
28 public:
29 WorkerPoolImpl();
30 ~WorkerPoolImpl();
31
32 void PostTask(const tracked_objects::Location& from_here, Task* task,
33 bool task_is_slow);
[email protected]180c85e2011-07-26 18:25:1634 void PostTask(const tracked_objects::Location& from_here,
35 const base::Closure& task, bool task_is_slow);
[email protected]250103f2009-03-24 23:41:5336
37 private:
[email protected]9f2ca2b2010-12-18 19:53:1838 scoped_refptr<base::PosixDynamicThreadPool> pool_;
[email protected]250103f2009-03-24 23:41:5339};
40
41WorkerPoolImpl::WorkerPoolImpl()
[email protected]ac9ba8fe2010-12-30 18:08:3642 : pool_(new base::PosixDynamicThreadPool("WorkerPool",
43 kIdleSecondsBeforeExit)) {
44}
[email protected]250103f2009-03-24 23:41:5345
46WorkerPoolImpl::~WorkerPoolImpl() {
47 pool_->Terminate();
48}
49
50void WorkerPoolImpl::PostTask(const tracked_objects::Location& from_here,
51 Task* task, bool task_is_slow) {
[email protected]180c85e2011-07-26 18:25:1652 pool_->PostTask(from_here, task);
53}
54
55void WorkerPoolImpl::PostTask(const tracked_objects::Location& from_here,
56 const base::Closure& task, bool task_is_slow) {
57 pool_->PostTask(from_here, task);
[email protected]250103f2009-03-24 23:41:5358}
59
60base::LazyInstance<WorkerPoolImpl> g_lazy_worker_pool(base::LINKER_INITIALIZED);
61
62class WorkerThread : public PlatformThread::Delegate {
63 public:
[email protected]180c85e2011-07-26 18:25:1664 WorkerThread(const std::string& name_prefix,
[email protected]9f2ca2b2010-12-18 19:53:1865 base::PosixDynamicThreadPool* pool)
[email protected]250103f2009-03-24 23:41:5366 : name_prefix_(name_prefix),
[email protected]250103f2009-03-24 23:41:5367 pool_(pool) {}
68
69 virtual void ThreadMain();
70
71 private:
72 const std::string name_prefix_;
[email protected]9f2ca2b2010-12-18 19:53:1873 scoped_refptr<base::PosixDynamicThreadPool> pool_;
[email protected]250103f2009-03-24 23:41:5374
75 DISALLOW_COPY_AND_ASSIGN(WorkerThread);
76};
77
78void WorkerThread::ThreadMain() {
[email protected]f1633932010-08-17 23:05:2879 const std::string name = base::StringPrintf(
80 "%s/%d", name_prefix_.c_str(), PlatformThread::CurrentId());
[email protected]250103f2009-03-24 23:41:5381 PlatformThread::SetName(name.c_str());
82
83 for (;;) {
[email protected]180c85e2011-07-26 18:25:1684 PosixDynamicThreadPool::PendingTask pending_task = pool_->WaitForTask();
85 if (pending_task.task.is_null())
[email protected]250103f2009-03-24 23:41:5386 break;
[email protected]19d8a902011-10-03 17:51:2587 UNSHIPPED_TRACE_EVENT2("task", "WorkerThread::ThreadMain::Run",
88 "src_file", pending_task.posted_from.file_name(),
89 "src_func", pending_task.posted_from.function_name());
[email protected]84b57952011-10-15 23:52:4590
91#if defined(TRACK_ALL_TASK_OBJECTS)
92 TimeTicks start_of_run = tracked_objects::ThreadData::Now();
93#endif // defined(TRACK_ALL_TASK_OBJECTS)
[email protected]180c85e2011-07-26 18:25:1694 pending_task.task.Run();
[email protected]84b57952011-10-15 23:52:4595#if defined(TRACK_ALL_TASK_OBJECTS)
96 tracked_objects::ThreadData::TallyADeathIfActive(pending_task.post_births,
97 pending_task.time_posted, TimeTicks::TimeTicks(), start_of_run);
98#endif // defined(TRACK_ALL_TASK_OBJECTS)
[email protected]250103f2009-03-24 23:41:5399 }
100
101 // The WorkerThread is non-joinable, so it deletes itself.
102 delete this;
[email protected]5846da02009-03-06 20:35:45103}
104
105} // namespace
106
107bool WorkerPool::PostTask(const tracked_objects::Location& from_here,
108 Task* task, bool task_is_slow) {
[email protected]250103f2009-03-24 23:41:53109 g_lazy_worker_pool.Pointer()->PostTask(from_here, task, task_is_slow);
[email protected]5846da02009-03-06 20:35:45110 return true;
111}
[email protected]250103f2009-03-24 23:41:53112
[email protected]180c85e2011-07-26 18:25:16113bool WorkerPool::PostTask(const tracked_objects::Location& from_here,
114 const base::Closure& task, bool task_is_slow) {
115 g_lazy_worker_pool.Pointer()->PostTask(from_here, task, task_is_slow);
116 return true;
117}
118
119PosixDynamicThreadPool::PendingTask::PendingTask(
120 const tracked_objects::Location& posted_from,
121 const base::Closure& task)
[email protected]19d8a902011-10-03 17:51:25122 : posted_from(posted_from),
123 task(task) {
[email protected]84b57952011-10-15 23:52:45124#if defined(TRACK_ALL_TASK_OBJECTS)
125 post_births = tracked_objects::ThreadData::TallyABirthIfActive(posted_from);
126 time_posted = tracked_objects::ThreadData::Now();
127#endif // defined(TRACK_ALL_TASK_OBJECTS)
[email protected]180c85e2011-07-26 18:25:16128}
129
130PosixDynamicThreadPool::PendingTask::~PendingTask() {
131}
132
[email protected]9f2ca2b2010-12-18 19:53:18133PosixDynamicThreadPool::PosixDynamicThreadPool(
[email protected]250103f2009-03-24 23:41:53134 const std::string& name_prefix,
135 int idle_seconds_before_exit)
136 : name_prefix_(name_prefix),
137 idle_seconds_before_exit_(idle_seconds_before_exit),
[email protected]180c85e2011-07-26 18:25:16138 pending_tasks_available_cv_(&lock_),
[email protected]250103f2009-03-24 23:41:53139 num_idle_threads_(0),
140 terminated_(false),
141 num_idle_threads_cv_(NULL) {}
142
[email protected]9f2ca2b2010-12-18 19:53:18143PosixDynamicThreadPool::~PosixDynamicThreadPool() {
[email protected]180c85e2011-07-26 18:25:16144 while (!pending_tasks_.empty()) {
145 PendingTask pending_task = pending_tasks_.front();
146 pending_tasks_.pop();
[email protected]250103f2009-03-24 23:41:53147 }
148}
149
[email protected]9f2ca2b2010-12-18 19:53:18150void PosixDynamicThreadPool::Terminate() {
[email protected]250103f2009-03-24 23:41:53151 {
152 AutoLock locked(lock_);
153 DCHECK(!terminated_) << "Thread pool is already terminated.";
154 terminated_ = true;
155 }
[email protected]180c85e2011-07-26 18:25:16156 pending_tasks_available_cv_.Broadcast();
[email protected]250103f2009-03-24 23:41:53157}
158
[email protected]180c85e2011-07-26 18:25:16159void PosixDynamicThreadPool::PostTask(
160 const tracked_objects::Location& from_here,
161 Task* task) {
162 PendingTask pending_task(from_here,
163 base::Bind(&subtle::TaskClosureAdapter::Run,
164 new subtle::TaskClosureAdapter(task)));
165 // |pending_task| and AddTask() work in conjunction here to ensure that after
166 // a successful AddTask(), the TaskClosureAdapter object is deleted on the
167 // worker thread. In AddTask(), the reference |pending_task.task| is handed
168 // off in a destructive manner to ensure that the local copy of
169 // |pending_task| doesn't keep a ref on the Closure causing the
170 // TaskClosureAdapter to be deleted on the wrong thread.
171 AddTask(&pending_task);
172}
173
174void PosixDynamicThreadPool::PostTask(
175 const tracked_objects::Location& from_here,
176 const base::Closure& task) {
177 PendingTask pending_task(from_here, task);
178 AddTask(&pending_task);
179}
180
181void PosixDynamicThreadPool::AddTask(PendingTask* pending_task) {
[email protected]250103f2009-03-24 23:41:53182 AutoLock locked(lock_);
183 DCHECK(!terminated_) <<
184 "This thread pool is already terminated. Do not post new tasks.";
185
[email protected]180c85e2011-07-26 18:25:16186 pending_tasks_.push(*pending_task);
187 pending_task->task.Reset();
[email protected]250103f2009-03-24 23:41:53188
189 // We have enough worker threads.
[email protected]180c85e2011-07-26 18:25:16190 if (static_cast<size_t>(num_idle_threads_) >= pending_tasks_.size()) {
191 pending_tasks_available_cv_.Signal();
[email protected]250103f2009-03-24 23:41:53192 } else {
193 // The new PlatformThread will take ownership of the WorkerThread object,
194 // which will delete itself on exit.
195 WorkerThread* worker =
[email protected]180c85e2011-07-26 18:25:16196 new WorkerThread(name_prefix_, this);
[email protected]250103f2009-03-24 23:41:53197 PlatformThread::CreateNonJoinable(kWorkerThreadStackSize, worker);
198 }
199}
200
[email protected]180c85e2011-07-26 18:25:16201PosixDynamicThreadPool::PendingTask PosixDynamicThreadPool::WaitForTask() {
[email protected]250103f2009-03-24 23:41:53202 AutoLock locked(lock_);
203
204 if (terminated_)
[email protected]180c85e2011-07-26 18:25:16205 return PendingTask(FROM_HERE, base::Closure());
[email protected]250103f2009-03-24 23:41:53206
[email protected]180c85e2011-07-26 18:25:16207 if (pending_tasks_.empty()) { // No work available, wait for work.
[email protected]250103f2009-03-24 23:41:53208 num_idle_threads_++;
209 if (num_idle_threads_cv_.get())
210 num_idle_threads_cv_->Signal();
[email protected]180c85e2011-07-26 18:25:16211 pending_tasks_available_cv_.TimedWait(
212 TimeDelta::FromSeconds(idle_seconds_before_exit_));
[email protected]250103f2009-03-24 23:41:53213 num_idle_threads_--;
214 if (num_idle_threads_cv_.get())
215 num_idle_threads_cv_->Signal();
[email protected]180c85e2011-07-26 18:25:16216 if (pending_tasks_.empty()) {
[email protected]250103f2009-03-24 23:41:53217 // We waited for work, but there's still no work. Return NULL to signal
218 // the thread to terminate.
[email protected]180c85e2011-07-26 18:25:16219 return PendingTask(FROM_HERE, base::Closure());
[email protected]250103f2009-03-24 23:41:53220 }
221 }
222
[email protected]180c85e2011-07-26 18:25:16223 PendingTask pending_task = pending_tasks_.front();
224 pending_tasks_.pop();
225 return pending_task;
[email protected]250103f2009-03-24 23:41:53226}
227
228} // namespace base