blob: 2ad392546f71d6dc04c9aae8ae1158d79e98d9d4 [file] [log] [blame]
[email protected]e7b3a612012-01-05 02:18:181// Copyright (c) 2012 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]c6944272012-01-06 22:12:288#include "base/callback.h"
[email protected]19d8a902011-10-03 17:51:259#include "base/debug/trace_event.h"
[email protected]250103f2009-03-24 23:41:5310#include "base/lazy_instance.h"
[email protected]56d01f62009-03-12 22:41:5411#include "base/logging.h"
[email protected]3b63f8f42011-03-28 01:54:1512#include "base/memory/ref_counted.h"
[email protected]f1633932010-08-17 23:05:2813#include "base/stringprintf.h"
[email protected]ce072a72010-12-31 20:02:1614#include "base/threading/platform_thread.h"
[email protected]8e1946f92012-04-25 03:15:0515#include "base/threading/thread_local.h"
[email protected]ac9ba8fe2010-12-30 18:08:3616#include "base/threading/worker_pool.h"
[email protected]180c85e2011-07-26 18:25:1617#include "base/tracked_objects.h"
[email protected]ac9ba8fe2010-12-30 18:08:3618
[email protected]dd1f9fe2011-11-15 23:36:3019using tracked_objects::TrackedTime;
20
[email protected]ac9ba8fe2010-12-30 18:08:3621namespace base {
[email protected]5846da02009-03-06 20:35:4522
23namespace {
24
[email protected]8e1946f92012-04-25 03:15:0525base::LazyInstance<ThreadLocalBoolean>::Leaky
26 g_worker_pool_running_on_this_thread = LAZY_INSTANCE_INITIALIZER;
27
[email protected]250103f2009-03-24 23:41:5328const int kIdleSecondsBeforeExit = 10 * 60;
[email protected]73297342012-07-07 08:27:2329
30#ifdef ADDRESS_SANITIZER
31const int kWorkerThreadStackSize = 256 * 1024;
32#else
[email protected]82fbbe62009-05-28 08:45:1933// A stack size of 64 KB is too small for the CERT_PKIXVerifyCert
34// function of NSS because of NSS bug 439169.
35const int kWorkerThreadStackSize = 128 * 1024;
[email protected]73297342012-07-07 08:27:2336#endif
[email protected]250103f2009-03-24 23:41:5337
38class WorkerPoolImpl {
39 public:
40 WorkerPoolImpl();
41 ~WorkerPoolImpl();
42
[email protected]180c85e2011-07-26 18:25:1643 void PostTask(const tracked_objects::Location& from_here,
44 const base::Closure& task, bool task_is_slow);
[email protected]250103f2009-03-24 23:41:5345
46 private:
[email protected]9f2ca2b2010-12-18 19:53:1847 scoped_refptr<base::PosixDynamicThreadPool> pool_;
[email protected]250103f2009-03-24 23:41:5348};
49
50WorkerPoolImpl::WorkerPoolImpl()
[email protected]ac9ba8fe2010-12-30 18:08:3651 : pool_(new base::PosixDynamicThreadPool("WorkerPool",
52 kIdleSecondsBeforeExit)) {
53}
[email protected]250103f2009-03-24 23:41:5354
55WorkerPoolImpl::~WorkerPoolImpl() {
56 pool_->Terminate();
57}
58
59void WorkerPoolImpl::PostTask(const tracked_objects::Location& from_here,
[email protected]180c85e2011-07-26 18:25:1660 const base::Closure& task, bool task_is_slow) {
61 pool_->PostTask(from_here, task);
[email protected]250103f2009-03-24 23:41:5362}
63
[email protected]6de0fd1d2011-11-15 13:31:4964base::LazyInstance<WorkerPoolImpl> g_lazy_worker_pool =
65 LAZY_INSTANCE_INITIALIZER;
[email protected]250103f2009-03-24 23:41:5366
67class WorkerThread : public PlatformThread::Delegate {
68 public:
[email protected]180c85e2011-07-26 18:25:1669 WorkerThread(const std::string& name_prefix,
[email protected]9f2ca2b2010-12-18 19:53:1870 base::PosixDynamicThreadPool* pool)
[email protected]250103f2009-03-24 23:41:5371 : name_prefix_(name_prefix),
[email protected]250103f2009-03-24 23:41:5372 pool_(pool) {}
73
[email protected]44106182012-04-06 03:53:0274 virtual void ThreadMain() OVERRIDE;
[email protected]250103f2009-03-24 23:41:5375
76 private:
77 const std::string name_prefix_;
[email protected]9f2ca2b2010-12-18 19:53:1878 scoped_refptr<base::PosixDynamicThreadPool> pool_;
[email protected]250103f2009-03-24 23:41:5379
80 DISALLOW_COPY_AND_ASSIGN(WorkerThread);
81};
82
83void WorkerThread::ThreadMain() {
[email protected]8e1946f92012-04-25 03:15:0584 g_worker_pool_running_on_this_thread.Get().Set(true);
[email protected]f1633932010-08-17 23:05:2885 const std::string name = base::StringPrintf(
86 "%s/%d", name_prefix_.c_str(), PlatformThread::CurrentId());
[email protected]ab39dc82011-11-08 10:27:1787 // Note |name.c_str()| must remain valid for for the whole life of the thread.
[email protected]250103f2009-03-24 23:41:5388 PlatformThread::SetName(name.c_str());
89
90 for (;;) {
[email protected]dd1f9fe2011-11-15 23:36:3091 PendingTask pending_task = pool_->WaitForTask();
[email protected]180c85e2011-07-26 18:25:1692 if (pending_task.task.is_null())
[email protected]250103f2009-03-24 23:41:5393 break;
[email protected]e8df8be2012-02-23 19:16:3594 TRACE_EVENT2("task", "WorkerThread::ThreadMain::Run",
[email protected]19d8a902011-10-03 17:51:2595 "src_file", pending_task.posted_from.file_name(),
96 "src_func", pending_task.posted_from.function_name());
[email protected]84b57952011-10-15 23:52:4597
[email protected]dd1f9fe2011-11-15 23:36:3098 TrackedTime start_time =
[email protected]8aa1e6e2011-12-14 01:36:4899 tracked_objects::ThreadData::NowForStartOfRun(pending_task.birth_tally);
[email protected]b2a9bbd2011-10-31 22:36:21100
[email protected]180c85e2011-07-26 18:25:16101 pending_task.task.Run();
[email protected]b2a9bbd2011-10-31 22:36:21102
103 tracked_objects::ThreadData::TallyRunOnWorkerThreadIfTracking(
[email protected]dd1f9fe2011-11-15 23:36:30104 pending_task.birth_tally, TrackedTime(pending_task.time_posted),
[email protected]dda97682011-11-14 05:24:07105 start_time, tracked_objects::ThreadData::NowForEndOfRun());
[email protected]250103f2009-03-24 23:41:53106 }
107
108 // The WorkerThread is non-joinable, so it deletes itself.
109 delete this;
[email protected]5846da02009-03-06 20:35:45110}
111
112} // namespace
113
[email protected]8e1946f92012-04-25 03:15:05114// static
[email protected]5846da02009-03-06 20:35:45115bool WorkerPool::PostTask(const tracked_objects::Location& from_here,
[email protected]180c85e2011-07-26 18:25:16116 const base::Closure& task, bool task_is_slow) {
117 g_lazy_worker_pool.Pointer()->PostTask(from_here, task, task_is_slow);
118 return true;
119}
120
[email protected]8e1946f92012-04-25 03:15:05121// static
122bool WorkerPool::RunsTasksOnCurrentThread() {
123 return g_worker_pool_running_on_this_thread.Get().Get();
124}
125
[email protected]9f2ca2b2010-12-18 19:53:18126PosixDynamicThreadPool::PosixDynamicThreadPool(
[email protected]250103f2009-03-24 23:41:53127 const std::string& name_prefix,
128 int idle_seconds_before_exit)
129 : name_prefix_(name_prefix),
130 idle_seconds_before_exit_(idle_seconds_before_exit),
[email protected]180c85e2011-07-26 18:25:16131 pending_tasks_available_cv_(&lock_),
[email protected]250103f2009-03-24 23:41:53132 num_idle_threads_(0),
133 terminated_(false),
134 num_idle_threads_cv_(NULL) {}
135
[email protected]9f2ca2b2010-12-18 19:53:18136PosixDynamicThreadPool::~PosixDynamicThreadPool() {
[email protected]262060ff2011-11-17 23:26:53137 while (!pending_tasks_.empty())
[email protected]180c85e2011-07-26 18:25:16138 pending_tasks_.pop();
[email protected]250103f2009-03-24 23:41:53139}
140
[email protected]9f2ca2b2010-12-18 19:53:18141void PosixDynamicThreadPool::Terminate() {
[email protected]250103f2009-03-24 23:41:53142 {
143 AutoLock locked(lock_);
144 DCHECK(!terminated_) << "Thread pool is already terminated.";
145 terminated_ = true;
146 }
[email protected]180c85e2011-07-26 18:25:16147 pending_tasks_available_cv_.Broadcast();
[email protected]250103f2009-03-24 23:41:53148}
149
[email protected]180c85e2011-07-26 18:25:16150void PosixDynamicThreadPool::PostTask(
151 const tracked_objects::Location& from_here,
[email protected]180c85e2011-07-26 18:25:16152 const base::Closure& task) {
153 PendingTask pending_task(from_here, task);
154 AddTask(&pending_task);
155}
156
157void PosixDynamicThreadPool::AddTask(PendingTask* pending_task) {
[email protected]250103f2009-03-24 23:41:53158 AutoLock locked(lock_);
159 DCHECK(!terminated_) <<
160 "This thread pool is already terminated. Do not post new tasks.";
161
[email protected]180c85e2011-07-26 18:25:16162 pending_tasks_.push(*pending_task);
163 pending_task->task.Reset();
[email protected]250103f2009-03-24 23:41:53164
165 // We have enough worker threads.
[email protected]180c85e2011-07-26 18:25:16166 if (static_cast<size_t>(num_idle_threads_) >= pending_tasks_.size()) {
167 pending_tasks_available_cv_.Signal();
[email protected]250103f2009-03-24 23:41:53168 } else {
169 // The new PlatformThread will take ownership of the WorkerThread object,
170 // which will delete itself on exit.
171 WorkerThread* worker =
[email protected]180c85e2011-07-26 18:25:16172 new WorkerThread(name_prefix_, this);
[email protected]250103f2009-03-24 23:41:53173 PlatformThread::CreateNonJoinable(kWorkerThreadStackSize, worker);
174 }
175}
176
[email protected]dd1f9fe2011-11-15 23:36:30177PendingTask PosixDynamicThreadPool::WaitForTask() {
[email protected]250103f2009-03-24 23:41:53178 AutoLock locked(lock_);
179
180 if (terminated_)
[email protected]180c85e2011-07-26 18:25:16181 return PendingTask(FROM_HERE, base::Closure());
[email protected]250103f2009-03-24 23:41:53182
[email protected]180c85e2011-07-26 18:25:16183 if (pending_tasks_.empty()) { // No work available, wait for work.
[email protected]250103f2009-03-24 23:41:53184 num_idle_threads_++;
185 if (num_idle_threads_cv_.get())
186 num_idle_threads_cv_->Signal();
[email protected]180c85e2011-07-26 18:25:16187 pending_tasks_available_cv_.TimedWait(
188 TimeDelta::FromSeconds(idle_seconds_before_exit_));
[email protected]250103f2009-03-24 23:41:53189 num_idle_threads_--;
190 if (num_idle_threads_cv_.get())
191 num_idle_threads_cv_->Signal();
[email protected]180c85e2011-07-26 18:25:16192 if (pending_tasks_.empty()) {
[email protected]250103f2009-03-24 23:41:53193 // We waited for work, but there's still no work. Return NULL to signal
194 // the thread to terminate.
[email protected]180c85e2011-07-26 18:25:16195 return PendingTask(FROM_HERE, base::Closure());
[email protected]250103f2009-03-24 23:41:53196 }
197 }
198
[email protected]180c85e2011-07-26 18:25:16199 PendingTask pending_task = pending_tasks_.front();
200 pending_tasks_.pop();
201 return pending_task;
[email protected]250103f2009-03-24 23:41:53202}
203
204} // namespace base