1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Use of this source code is governed by a BSD-style license that can be
3c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// found in the LICENSE file.
4c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
53f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/threading/worker_pool_posix.h"
6c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
7c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/lazy_instance.h"
8c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/logging.h"
9ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/ref_counted.h"
103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/stringprintf.h"
11c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/task.h"
123f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/threading/platform_thread.h"
133f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/threading/worker_pool.h"
143f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen
153f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsennamespace base {
16c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
17c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottnamespace {
18c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
19c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottconst int kIdleSecondsBeforeExit = 10 * 60;
20c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// A stack size of 64 KB is too small for the CERT_PKIXVerifyCert
21c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// function of NSS because of NSS bug 439169.
22c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottconst int kWorkerThreadStackSize = 128 * 1024;
23c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
24c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottclass WorkerPoolImpl {
25c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott public:
26c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  WorkerPoolImpl();
27c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ~WorkerPoolImpl();
28c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
29c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  void PostTask(const tracked_objects::Location& from_here, Task* task,
30c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                bool task_is_slow);
31c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
32c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott private:
3321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  scoped_refptr<base::PosixDynamicThreadPool> pool_;
34c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott};
35c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
36c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottWorkerPoolImpl::WorkerPoolImpl()
373f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    : pool_(new base::PosixDynamicThreadPool("WorkerPool",
383f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen                                             kIdleSecondsBeforeExit)) {
393f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen}
40c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
41c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottWorkerPoolImpl::~WorkerPoolImpl() {
42c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  pool_->Terminate();
43c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
44c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
45c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid WorkerPoolImpl::PostTask(const tracked_objects::Location& from_here,
46c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                              Task* task, bool task_is_slow) {
47c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  task->SetBirthPlace(from_here);
48c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  pool_->PostTask(task);
49c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
50c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
51c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbase::LazyInstance<WorkerPoolImpl> g_lazy_worker_pool(base::LINKER_INITIALIZED);
52c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
53c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottclass WorkerThread : public PlatformThread::Delegate {
54c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott public:
55c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  WorkerThread(const std::string& name_prefix, int idle_seconds_before_exit,
5621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen               base::PosixDynamicThreadPool* pool)
57c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      : name_prefix_(name_prefix),
58c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        idle_seconds_before_exit_(idle_seconds_before_exit),
59c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        pool_(pool) {}
60c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
61c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  virtual void ThreadMain();
62c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
63c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott private:
64c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  const std::string name_prefix_;
65c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  const int idle_seconds_before_exit_;
6621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  scoped_refptr<base::PosixDynamicThreadPool> pool_;
67c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
68c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DISALLOW_COPY_AND_ASSIGN(WorkerThread);
69c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott};
70c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
71c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid WorkerThread::ThreadMain() {
723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  const std::string name = base::StringPrintf(
733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      "%s/%d", name_prefix_.c_str(), PlatformThread::CurrentId());
74c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  PlatformThread::SetName(name.c_str());
75c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
76c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  for (;;) {
77c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    Task* task = pool_->WaitForTask();
78c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (!task)
79c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      break;
80c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    task->Run();
81c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    delete task;
82c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
83c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
84c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // The WorkerThread is non-joinable, so it deletes itself.
85c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  delete this;
86c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
87c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
88c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}  // namespace
89c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
90c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool WorkerPool::PostTask(const tracked_objects::Location& from_here,
91c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                          Task* task, bool task_is_slow) {
92c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  g_lazy_worker_pool.Pointer()->PostTask(from_here, task, task_is_slow);
93c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return true;
94c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
95c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
9621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian MonsenPosixDynamicThreadPool::PosixDynamicThreadPool(
97c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    const std::string& name_prefix,
98c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    int idle_seconds_before_exit)
99c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    : name_prefix_(name_prefix),
100c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      idle_seconds_before_exit_(idle_seconds_before_exit),
101c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      tasks_available_cv_(&lock_),
102c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      num_idle_threads_(0),
103c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      terminated_(false),
104c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      num_idle_threads_cv_(NULL) {}
105c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
10621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian MonsenPosixDynamicThreadPool::~PosixDynamicThreadPool() {
107c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  while (!tasks_.empty()) {
108c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    Task* task = tasks_.front();
109c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    tasks_.pop();
110c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    delete task;
111c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
112c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
113c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
11421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenvoid PosixDynamicThreadPool::Terminate() {
115c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  {
116c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    AutoLock locked(lock_);
117c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    DCHECK(!terminated_) << "Thread pool is already terminated.";
118c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    terminated_ = true;
119c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
120c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  tasks_available_cv_.Broadcast();
121c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
122c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
12321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenvoid PosixDynamicThreadPool::PostTask(Task* task) {
124c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  AutoLock locked(lock_);
125c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(!terminated_) <<
126c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      "This thread pool is already terminated.  Do not post new tasks.";
127c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
128c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  tasks_.push(task);
129c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
130c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // We have enough worker threads.
131c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (static_cast<size_t>(num_idle_threads_) >= tasks_.size()) {
132c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    tasks_available_cv_.Signal();
133c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  } else {
134c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // The new PlatformThread will take ownership of the WorkerThread object,
135c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // which will delete itself on exit.
136c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    WorkerThread* worker =
137c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        new WorkerThread(name_prefix_, idle_seconds_before_exit_, this);
138c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    PlatformThread::CreateNonJoinable(kWorkerThreadStackSize, worker);
139c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
140c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
141c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
14221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian MonsenTask* PosixDynamicThreadPool::WaitForTask() {
143c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  AutoLock locked(lock_);
144c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
145c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (terminated_)
146c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return NULL;
147c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
148c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (tasks_.empty()) {  // No work available, wait for work.
149c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    num_idle_threads_++;
150c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (num_idle_threads_cv_.get())
151c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      num_idle_threads_cv_->Signal();
152c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    tasks_available_cv_.TimedWait(
153c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        TimeDelta::FromSeconds(kIdleSecondsBeforeExit));
154c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    num_idle_threads_--;
155c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (num_idle_threads_cv_.get())
156c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      num_idle_threads_cv_->Signal();
157c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (tasks_.empty()) {
158c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      // We waited for work, but there's still no work.  Return NULL to signal
159c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      // the thread to terminate.
160c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return NULL;
161c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
162c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
163c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
164c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  Task* task = tasks_.front();
165c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  tasks_.pop();
166c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return task;
167c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
168c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
169c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}  // namespace base
170