[email protected] | e7b3a61 | 2012-01-05 02:18:18 | [diff] [blame] | 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
[email protected] | 5846da0 | 2009-03-06 20:35:45 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
[email protected] | ac9ba8fe | 2010-12-30 18:08:36 | [diff] [blame] | 5 | #include "base/threading/worker_pool_posix.h" |
[email protected] | 5846da0 | 2009-03-06 20:35:45 | [diff] [blame] | 6 | |
[email protected] | 180c85e | 2011-07-26 18:25:16 | [diff] [blame] | 7 | #include "base/bind.h" |
[email protected] | c694427 | 2012-01-06 22:12:28 | [diff] [blame] | 8 | #include "base/callback.h" |
[email protected] | 19d8a90 | 2011-10-03 17:51:25 | [diff] [blame] | 9 | #include "base/debug/trace_event.h" |
[email protected] | 250103f | 2009-03-24 23:41:53 | [diff] [blame] | 10 | #include "base/lazy_instance.h" |
[email protected] | 56d01f6 | 2009-03-12 22:41:54 | [diff] [blame] | 11 | #include "base/logging.h" |
[email protected] | 3b63f8f4 | 2011-03-28 01:54:15 | [diff] [blame] | 12 | #include "base/memory/ref_counted.h" |
[email protected] | f163393 | 2010-08-17 23:05:28 | [diff] [blame] | 13 | #include "base/stringprintf.h" |
[email protected] | ce072a7 | 2010-12-31 20:02:16 | [diff] [blame] | 14 | #include "base/threading/platform_thread.h" |
[email protected] | 8e1946f9 | 2012-04-25 03:15:05 | [diff] [blame] | 15 | #include "base/threading/thread_local.h" |
[email protected] | ac9ba8fe | 2010-12-30 18:08:36 | [diff] [blame] | 16 | #include "base/threading/worker_pool.h" |
[email protected] | 180c85e | 2011-07-26 18:25:16 | [diff] [blame] | 17 | #include "base/tracked_objects.h" |
[email protected] | ac9ba8fe | 2010-12-30 18:08:36 | [diff] [blame] | 18 | |
[email protected] | dd1f9fe | 2011-11-15 23:36:30 | [diff] [blame] | 19 | using tracked_objects::TrackedTime; |
| 20 | |
[email protected] | ac9ba8fe | 2010-12-30 18:08:36 | [diff] [blame] | 21 | namespace base { |
[email protected] | 5846da0 | 2009-03-06 20:35:45 | [diff] [blame] | 22 | |
| 23 | namespace { |
| 24 | |
[email protected] | 8e1946f9 | 2012-04-25 03:15:05 | [diff] [blame] | 25 | base::LazyInstance<ThreadLocalBoolean>::Leaky |
| 26 | g_worker_pool_running_on_this_thread = LAZY_INSTANCE_INITIALIZER; |
| 27 | |
[email protected] | 250103f | 2009-03-24 23:41:53 | [diff] [blame] | 28 | const int kIdleSecondsBeforeExit = 10 * 60; |
[email protected] | 7329734 | 2012-07-07 08:27:23 | [diff] [blame] | 29 | |
| 30 | #ifdef ADDRESS_SANITIZER |
| 31 | const int kWorkerThreadStackSize = 256 * 1024; |
| 32 | #else |
[email protected] | 82fbbe6 | 2009-05-28 08:45:19 | [diff] [blame] | 33 | // A stack size of 64 KB is too small for the CERT_PKIXVerifyCert |
| 34 | // function of NSS because of NSS bug 439169. |
| 35 | const int kWorkerThreadStackSize = 128 * 1024; |
[email protected] | 7329734 | 2012-07-07 08:27:23 | [diff] [blame] | 36 | #endif |
[email protected] | 250103f | 2009-03-24 23:41:53 | [diff] [blame] | 37 | |
| 38 | class WorkerPoolImpl { |
| 39 | public: |
| 40 | WorkerPoolImpl(); |
| 41 | ~WorkerPoolImpl(); |
| 42 | |
[email protected] | 180c85e | 2011-07-26 18:25:16 | [diff] [blame] | 43 | void PostTask(const tracked_objects::Location& from_here, |
| 44 | const base::Closure& task, bool task_is_slow); |
[email protected] | 250103f | 2009-03-24 23:41:53 | [diff] [blame] | 45 | |
| 46 | private: |
[email protected] | 9f2ca2b | 2010-12-18 19:53:18 | [diff] [blame] | 47 | scoped_refptr<base::PosixDynamicThreadPool> pool_; |
[email protected] | 250103f | 2009-03-24 23:41:53 | [diff] [blame] | 48 | }; |
| 49 | |
| 50 | WorkerPoolImpl::WorkerPoolImpl() |
[email protected] | ac9ba8fe | 2010-12-30 18:08:36 | [diff] [blame] | 51 | : pool_(new base::PosixDynamicThreadPool("WorkerPool", |
| 52 | kIdleSecondsBeforeExit)) { |
| 53 | } |
[email protected] | 250103f | 2009-03-24 23:41:53 | [diff] [blame] | 54 | |
| 55 | WorkerPoolImpl::~WorkerPoolImpl() { |
| 56 | pool_->Terminate(); |
| 57 | } |
| 58 | |
| 59 | void WorkerPoolImpl::PostTask(const tracked_objects::Location& from_here, |
[email protected] | 180c85e | 2011-07-26 18:25:16 | [diff] [blame] | 60 | const base::Closure& task, bool task_is_slow) { |
| 61 | pool_->PostTask(from_here, task); |
[email protected] | 250103f | 2009-03-24 23:41:53 | [diff] [blame] | 62 | } |
| 63 | |
[email protected] | 6de0fd1d | 2011-11-15 13:31:49 | [diff] [blame] | 64 | base::LazyInstance<WorkerPoolImpl> g_lazy_worker_pool = |
| 65 | LAZY_INSTANCE_INITIALIZER; |
[email protected] | 250103f | 2009-03-24 23:41:53 | [diff] [blame] | 66 | |
| 67 | class WorkerThread : public PlatformThread::Delegate { |
| 68 | public: |
[email protected] | 180c85e | 2011-07-26 18:25:16 | [diff] [blame] | 69 | WorkerThread(const std::string& name_prefix, |
[email protected] | 9f2ca2b | 2010-12-18 19:53:18 | [diff] [blame] | 70 | base::PosixDynamicThreadPool* pool) |
[email protected] | 250103f | 2009-03-24 23:41:53 | [diff] [blame] | 71 | : name_prefix_(name_prefix), |
[email protected] | 250103f | 2009-03-24 23:41:53 | [diff] [blame] | 72 | pool_(pool) {} |
| 73 | |
[email protected] | 4410618 | 2012-04-06 03:53:02 | [diff] [blame] | 74 | virtual void ThreadMain() OVERRIDE; |
[email protected] | 250103f | 2009-03-24 23:41:53 | [diff] [blame] | 75 | |
| 76 | private: |
| 77 | const std::string name_prefix_; |
[email protected] | 9f2ca2b | 2010-12-18 19:53:18 | [diff] [blame] | 78 | scoped_refptr<base::PosixDynamicThreadPool> pool_; |
[email protected] | 250103f | 2009-03-24 23:41:53 | [diff] [blame] | 79 | |
| 80 | DISALLOW_COPY_AND_ASSIGN(WorkerThread); |
| 81 | }; |
| 82 | |
| 83 | void WorkerThread::ThreadMain() { |
[email protected] | 8e1946f9 | 2012-04-25 03:15:05 | [diff] [blame] | 84 | g_worker_pool_running_on_this_thread.Get().Set(true); |
[email protected] | f163393 | 2010-08-17 23:05:28 | [diff] [blame] | 85 | const std::string name = base::StringPrintf( |
| 86 | "%s/%d", name_prefix_.c_str(), PlatformThread::CurrentId()); |
[email protected] | ab39dc8 | 2011-11-08 10:27:17 | [diff] [blame] | 87 | // Note |name.c_str()| must remain valid for for the whole life of the thread. |
[email protected] | 250103f | 2009-03-24 23:41:53 | [diff] [blame] | 88 | PlatformThread::SetName(name.c_str()); |
| 89 | |
| 90 | for (;;) { |
[email protected] | dd1f9fe | 2011-11-15 23:36:30 | [diff] [blame] | 91 | PendingTask pending_task = pool_->WaitForTask(); |
[email protected] | 180c85e | 2011-07-26 18:25:16 | [diff] [blame] | 92 | if (pending_task.task.is_null()) |
[email protected] | 250103f | 2009-03-24 23:41:53 | [diff] [blame] | 93 | break; |
[email protected] | e8df8be | 2012-02-23 19:16:35 | [diff] [blame] | 94 | TRACE_EVENT2("task", "WorkerThread::ThreadMain::Run", |
[email protected] | 19d8a90 | 2011-10-03 17:51:25 | [diff] [blame] | 95 | "src_file", pending_task.posted_from.file_name(), |
| 96 | "src_func", pending_task.posted_from.function_name()); |
[email protected] | 84b5795 | 2011-10-15 23:52:45 | [diff] [blame] | 97 | |
[email protected] | dd1f9fe | 2011-11-15 23:36:30 | [diff] [blame] | 98 | TrackedTime start_time = |
[email protected] | 8aa1e6e | 2011-12-14 01:36:48 | [diff] [blame] | 99 | tracked_objects::ThreadData::NowForStartOfRun(pending_task.birth_tally); |
[email protected] | b2a9bbd | 2011-10-31 22:36:21 | [diff] [blame] | 100 | |
[email protected] | 180c85e | 2011-07-26 18:25:16 | [diff] [blame] | 101 | pending_task.task.Run(); |
[email protected] | b2a9bbd | 2011-10-31 22:36:21 | [diff] [blame] | 102 | |
| 103 | tracked_objects::ThreadData::TallyRunOnWorkerThreadIfTracking( |
[email protected] | dd1f9fe | 2011-11-15 23:36:30 | [diff] [blame] | 104 | pending_task.birth_tally, TrackedTime(pending_task.time_posted), |
[email protected] | dda9768 | 2011-11-14 05:24:07 | [diff] [blame] | 105 | start_time, tracked_objects::ThreadData::NowForEndOfRun()); |
[email protected] | 250103f | 2009-03-24 23:41:53 | [diff] [blame] | 106 | } |
| 107 | |
| 108 | // The WorkerThread is non-joinable, so it deletes itself. |
| 109 | delete this; |
[email protected] | 5846da0 | 2009-03-06 20:35:45 | [diff] [blame] | 110 | } |
| 111 | |
| 112 | } // namespace |
| 113 | |
[email protected] | 8e1946f9 | 2012-04-25 03:15:05 | [diff] [blame] | 114 | // static |
[email protected] | 5846da0 | 2009-03-06 20:35:45 | [diff] [blame] | 115 | bool WorkerPool::PostTask(const tracked_objects::Location& from_here, |
[email protected] | 180c85e | 2011-07-26 18:25:16 | [diff] [blame] | 116 | 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] | 8e1946f9 | 2012-04-25 03:15:05 | [diff] [blame] | 121 | // static |
| 122 | bool WorkerPool::RunsTasksOnCurrentThread() { |
| 123 | return g_worker_pool_running_on_this_thread.Get().Get(); |
| 124 | } |
| 125 | |
[email protected] | 9f2ca2b | 2010-12-18 19:53:18 | [diff] [blame] | 126 | PosixDynamicThreadPool::PosixDynamicThreadPool( |
[email protected] | 250103f | 2009-03-24 23:41:53 | [diff] [blame] | 127 | 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] | 180c85e | 2011-07-26 18:25:16 | [diff] [blame] | 131 | pending_tasks_available_cv_(&lock_), |
[email protected] | 250103f | 2009-03-24 23:41:53 | [diff] [blame] | 132 | num_idle_threads_(0), |
| 133 | terminated_(false), |
| 134 | num_idle_threads_cv_(NULL) {} |
| 135 | |
[email protected] | 9f2ca2b | 2010-12-18 19:53:18 | [diff] [blame] | 136 | PosixDynamicThreadPool::~PosixDynamicThreadPool() { |
[email protected] | 262060ff | 2011-11-17 23:26:53 | [diff] [blame] | 137 | while (!pending_tasks_.empty()) |
[email protected] | 180c85e | 2011-07-26 18:25:16 | [diff] [blame] | 138 | pending_tasks_.pop(); |
[email protected] | 250103f | 2009-03-24 23:41:53 | [diff] [blame] | 139 | } |
| 140 | |
[email protected] | 9f2ca2b | 2010-12-18 19:53:18 | [diff] [blame] | 141 | void PosixDynamicThreadPool::Terminate() { |
[email protected] | 250103f | 2009-03-24 23:41:53 | [diff] [blame] | 142 | { |
| 143 | AutoLock locked(lock_); |
| 144 | DCHECK(!terminated_) << "Thread pool is already terminated."; |
| 145 | terminated_ = true; |
| 146 | } |
[email protected] | 180c85e | 2011-07-26 18:25:16 | [diff] [blame] | 147 | pending_tasks_available_cv_.Broadcast(); |
[email protected] | 250103f | 2009-03-24 23:41:53 | [diff] [blame] | 148 | } |
| 149 | |
[email protected] | 180c85e | 2011-07-26 18:25:16 | [diff] [blame] | 150 | void PosixDynamicThreadPool::PostTask( |
| 151 | const tracked_objects::Location& from_here, |
[email protected] | 180c85e | 2011-07-26 18:25:16 | [diff] [blame] | 152 | const base::Closure& task) { |
| 153 | PendingTask pending_task(from_here, task); |
| 154 | AddTask(&pending_task); |
| 155 | } |
| 156 | |
| 157 | void PosixDynamicThreadPool::AddTask(PendingTask* pending_task) { |
[email protected] | 250103f | 2009-03-24 23:41:53 | [diff] [blame] | 158 | AutoLock locked(lock_); |
| 159 | DCHECK(!terminated_) << |
| 160 | "This thread pool is already terminated. Do not post new tasks."; |
| 161 | |
[email protected] | 180c85e | 2011-07-26 18:25:16 | [diff] [blame] | 162 | pending_tasks_.push(*pending_task); |
| 163 | pending_task->task.Reset(); |
[email protected] | 250103f | 2009-03-24 23:41:53 | [diff] [blame] | 164 | |
| 165 | // We have enough worker threads. |
[email protected] | 180c85e | 2011-07-26 18:25:16 | [diff] [blame] | 166 | if (static_cast<size_t>(num_idle_threads_) >= pending_tasks_.size()) { |
| 167 | pending_tasks_available_cv_.Signal(); |
[email protected] | 250103f | 2009-03-24 23:41:53 | [diff] [blame] | 168 | } else { |
| 169 | // The new PlatformThread will take ownership of the WorkerThread object, |
| 170 | // which will delete itself on exit. |
| 171 | WorkerThread* worker = |
[email protected] | 180c85e | 2011-07-26 18:25:16 | [diff] [blame] | 172 | new WorkerThread(name_prefix_, this); |
[email protected] | 250103f | 2009-03-24 23:41:53 | [diff] [blame] | 173 | PlatformThread::CreateNonJoinable(kWorkerThreadStackSize, worker); |
| 174 | } |
| 175 | } |
| 176 | |
[email protected] | dd1f9fe | 2011-11-15 23:36:30 | [diff] [blame] | 177 | PendingTask PosixDynamicThreadPool::WaitForTask() { |
[email protected] | 250103f | 2009-03-24 23:41:53 | [diff] [blame] | 178 | AutoLock locked(lock_); |
| 179 | |
| 180 | if (terminated_) |
[email protected] | 180c85e | 2011-07-26 18:25:16 | [diff] [blame] | 181 | return PendingTask(FROM_HERE, base::Closure()); |
[email protected] | 250103f | 2009-03-24 23:41:53 | [diff] [blame] | 182 | |
[email protected] | 180c85e | 2011-07-26 18:25:16 | [diff] [blame] | 183 | if (pending_tasks_.empty()) { // No work available, wait for work. |
[email protected] | 250103f | 2009-03-24 23:41:53 | [diff] [blame] | 184 | num_idle_threads_++; |
| 185 | if (num_idle_threads_cv_.get()) |
| 186 | num_idle_threads_cv_->Signal(); |
[email protected] | 180c85e | 2011-07-26 18:25:16 | [diff] [blame] | 187 | pending_tasks_available_cv_.TimedWait( |
| 188 | TimeDelta::FromSeconds(idle_seconds_before_exit_)); |
[email protected] | 250103f | 2009-03-24 23:41:53 | [diff] [blame] | 189 | num_idle_threads_--; |
| 190 | if (num_idle_threads_cv_.get()) |
| 191 | num_idle_threads_cv_->Signal(); |
[email protected] | 180c85e | 2011-07-26 18:25:16 | [diff] [blame] | 192 | if (pending_tasks_.empty()) { |
[email protected] | 250103f | 2009-03-24 23:41:53 | [diff] [blame] | 193 | // We waited for work, but there's still no work. Return NULL to signal |
| 194 | // the thread to terminate. |
[email protected] | 180c85e | 2011-07-26 18:25:16 | [diff] [blame] | 195 | return PendingTask(FROM_HERE, base::Closure()); |
[email protected] | 250103f | 2009-03-24 23:41:53 | [diff] [blame] | 196 | } |
| 197 | } |
| 198 | |
[email protected] | 180c85e | 2011-07-26 18:25:16 | [diff] [blame] | 199 | PendingTask pending_task = pending_tasks_.front(); |
| 200 | pending_tasks_.pop(); |
| 201 | return pending_task; |
[email protected] | 250103f | 2009-03-24 23:41:53 | [diff] [blame] | 202 | } |
| 203 | |
| 204 | } // namespace base |