blob: 3ddc08c540f244a4935b150ac5c295ac42dbc834 [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]ab39dc82011-11-08 10:27:1781 // Note |name.c_str()| must remain valid for for the whole life of the thread.
[email protected]250103f2009-03-24 23:41:5382 PlatformThread::SetName(name.c_str());
83
84 for (;;) {
[email protected]180c85e2011-07-26 18:25:1685 PosixDynamicThreadPool::PendingTask pending_task = pool_->WaitForTask();
86 if (pending_task.task.is_null())
[email protected]250103f2009-03-24 23:41:5387 break;
[email protected]19d8a902011-10-03 17:51:2588 UNSHIPPED_TRACE_EVENT2("task", "WorkerThread::ThreadMain::Run",
89 "src_file", pending_task.posted_from.file_name(),
90 "src_func", pending_task.posted_from.function_name());
[email protected]84b57952011-10-15 23:52:4591
[email protected]b2a9bbd2011-10-31 22:36:2192 tracked_objects::TrackedTime start_time =
93 tracked_objects::ThreadData::Now();
94
[email protected]180c85e2011-07-26 18:25:1695 pending_task.task.Run();
[email protected]b2a9bbd2011-10-31 22:36:2196
97 tracked_objects::ThreadData::TallyRunOnWorkerThreadIfTracking(
98 pending_task.birth_tally, pending_task.time_posted,
99 start_time, tracked_objects::ThreadData::Now());
[email protected]250103f2009-03-24 23:41:53100 }
101
102 // The WorkerThread is non-joinable, so it deletes itself.
103 delete this;
[email protected]5846da02009-03-06 20:35:45104}
105
106} // namespace
107
108bool WorkerPool::PostTask(const tracked_objects::Location& from_here,
109 Task* task, bool task_is_slow) {
[email protected]250103f2009-03-24 23:41:53110 g_lazy_worker_pool.Pointer()->PostTask(from_here, task, task_is_slow);
[email protected]5846da02009-03-06 20:35:45111 return true;
112}
[email protected]250103f2009-03-24 23:41:53113
[email protected]180c85e2011-07-26 18:25:16114bool WorkerPool::PostTask(const tracked_objects::Location& from_here,
115 const base::Closure& task, bool task_is_slow) {
116 g_lazy_worker_pool.Pointer()->PostTask(from_here, task, task_is_slow);
117 return true;
118}
119
120PosixDynamicThreadPool::PendingTask::PendingTask(
121 const tracked_objects::Location& posted_from,
122 const base::Closure& task)
[email protected]19d8a902011-10-03 17:51:25123 : posted_from(posted_from),
124 task(task) {
[email protected]b2a9bbd2011-10-31 22:36:21125 birth_tally = tracked_objects::ThreadData::TallyABirthIfActive(posted_from);
[email protected]84b57952011-10-15 23:52:45126 time_posted = tracked_objects::ThreadData::Now();
[email protected]180c85e2011-07-26 18:25:16127}
128
129PosixDynamicThreadPool::PendingTask::~PendingTask() {
130}
131
[email protected]9f2ca2b2010-12-18 19:53:18132PosixDynamicThreadPool::PosixDynamicThreadPool(
[email protected]250103f2009-03-24 23:41:53133 const std::string& name_prefix,
134 int idle_seconds_before_exit)
135 : name_prefix_(name_prefix),
136 idle_seconds_before_exit_(idle_seconds_before_exit),
[email protected]180c85e2011-07-26 18:25:16137 pending_tasks_available_cv_(&lock_),
[email protected]250103f2009-03-24 23:41:53138 num_idle_threads_(0),
139 terminated_(false),
140 num_idle_threads_cv_(NULL) {}
141
[email protected]9f2ca2b2010-12-18 19:53:18142PosixDynamicThreadPool::~PosixDynamicThreadPool() {
[email protected]180c85e2011-07-26 18:25:16143 while (!pending_tasks_.empty()) {
144 PendingTask pending_task = pending_tasks_.front();
145 pending_tasks_.pop();
[email protected]250103f2009-03-24 23:41:53146 }
147}
148
[email protected]9f2ca2b2010-12-18 19:53:18149void PosixDynamicThreadPool::Terminate() {
[email protected]250103f2009-03-24 23:41:53150 {
151 AutoLock locked(lock_);
152 DCHECK(!terminated_) << "Thread pool is already terminated.";
153 terminated_ = true;
154 }
[email protected]180c85e2011-07-26 18:25:16155 pending_tasks_available_cv_.Broadcast();
[email protected]250103f2009-03-24 23:41:53156}
157
[email protected]180c85e2011-07-26 18:25:16158void PosixDynamicThreadPool::PostTask(
159 const tracked_objects::Location& from_here,
160 Task* task) {
161 PendingTask pending_task(from_here,
162 base::Bind(&subtle::TaskClosureAdapter::Run,
163 new subtle::TaskClosureAdapter(task)));
164 // |pending_task| and AddTask() work in conjunction here to ensure that after
165 // a successful AddTask(), the TaskClosureAdapter object is deleted on the
166 // worker thread. In AddTask(), the reference |pending_task.task| is handed
167 // off in a destructive manner to ensure that the local copy of
168 // |pending_task| doesn't keep a ref on the Closure causing the
169 // TaskClosureAdapter to be deleted on the wrong thread.
170 AddTask(&pending_task);
171}
172
173void PosixDynamicThreadPool::PostTask(
174 const tracked_objects::Location& from_here,
175 const base::Closure& task) {
176 PendingTask pending_task(from_here, task);
177 AddTask(&pending_task);
178}
179
180void PosixDynamicThreadPool::AddTask(PendingTask* pending_task) {
[email protected]250103f2009-03-24 23:41:53181 AutoLock locked(lock_);
182 DCHECK(!terminated_) <<
183 "This thread pool is already terminated. Do not post new tasks.";
184
[email protected]180c85e2011-07-26 18:25:16185 pending_tasks_.push(*pending_task);
186 pending_task->task.Reset();
[email protected]250103f2009-03-24 23:41:53187
188 // We have enough worker threads.
[email protected]180c85e2011-07-26 18:25:16189 if (static_cast<size_t>(num_idle_threads_) >= pending_tasks_.size()) {
190 pending_tasks_available_cv_.Signal();
[email protected]250103f2009-03-24 23:41:53191 } else {
192 // The new PlatformThread will take ownership of the WorkerThread object,
193 // which will delete itself on exit.
194 WorkerThread* worker =
[email protected]180c85e2011-07-26 18:25:16195 new WorkerThread(name_prefix_, this);
[email protected]250103f2009-03-24 23:41:53196 PlatformThread::CreateNonJoinable(kWorkerThreadStackSize, worker);
197 }
198}
199
[email protected]180c85e2011-07-26 18:25:16200PosixDynamicThreadPool::PendingTask PosixDynamicThreadPool::WaitForTask() {
[email protected]250103f2009-03-24 23:41:53201 AutoLock locked(lock_);
202
203 if (terminated_)
[email protected]180c85e2011-07-26 18:25:16204 return PendingTask(FROM_HERE, base::Closure());
[email protected]250103f2009-03-24 23:41:53205
[email protected]180c85e2011-07-26 18:25:16206 if (pending_tasks_.empty()) { // No work available, wait for work.
[email protected]250103f2009-03-24 23:41:53207 num_idle_threads_++;
208 if (num_idle_threads_cv_.get())
209 num_idle_threads_cv_->Signal();
[email protected]180c85e2011-07-26 18:25:16210 pending_tasks_available_cv_.TimedWait(
211 TimeDelta::FromSeconds(idle_seconds_before_exit_));
[email protected]250103f2009-03-24 23:41:53212 num_idle_threads_--;
213 if (num_idle_threads_cv_.get())
214 num_idle_threads_cv_->Signal();
[email protected]180c85e2011-07-26 18:25:16215 if (pending_tasks_.empty()) {
[email protected]250103f2009-03-24 23:41:53216 // We waited for work, but there's still no work. Return NULL to signal
217 // the thread to terminate.
[email protected]180c85e2011-07-26 18:25:16218 return PendingTask(FROM_HERE, base::Closure());
[email protected]250103f2009-03-24 23:41:53219 }
220 }
221
[email protected]180c85e2011-07-26 18:25:16222 PendingTask pending_task = pending_tasks_.front();
223 pending_tasks_.pop();
224 return pending_task;
[email protected]250103f2009-03-24 23:41:53225}
226
227} // namespace base