1// Copyright (c) 2010 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "base/threading/simple_thread.h" 6 7#include "base/logging.h" 8#include "base/threading/platform_thread.h" 9#include "base/string_number_conversions.h" 10 11namespace base { 12 13SimpleThread::SimpleThread(const std::string& name_prefix) 14 : name_prefix_(name_prefix), name_(name_prefix), 15 thread_(), event_(true, false), tid_(0), joined_(false) { 16} 17 18SimpleThread::SimpleThread(const std::string& name_prefix, 19 const Options& options) 20 : name_prefix_(name_prefix), name_(name_prefix), options_(options), 21 thread_(), event_(true, false), tid_(0), joined_(false) { 22} 23 24SimpleThread::~SimpleThread() { 25 DCHECK(HasBeenStarted()) << "SimpleThread was never started."; 26 DCHECK(HasBeenJoined()) << "SimpleThread destroyed without being Join()ed."; 27} 28 29void SimpleThread::Start() { 30 DCHECK(!HasBeenStarted()) << "Tried to Start a thread multiple times."; 31 bool success = PlatformThread::Create(options_.stack_size(), this, &thread_); 32 CHECK(success); 33 event_.Wait(); // Wait for the thread to complete initialization. 34} 35 36void SimpleThread::Join() { 37 DCHECK(HasBeenStarted()) << "Tried to Join a never-started thread."; 38 DCHECK(!HasBeenJoined()) << "Tried to Join a thread multiple times."; 39 PlatformThread::Join(thread_); 40 joined_ = true; 41} 42 43void SimpleThread::ThreadMain() { 44 tid_ = PlatformThread::CurrentId(); 45 // Construct our full name of the form "name_prefix_/TID". 46 name_.push_back('/'); 47 name_.append(IntToString(tid_)); 48 PlatformThread::SetName(name_.c_str()); 49 50 // We've initialized our new thread, signal that we're done to Start(). 51 event_.Signal(); 52 53 Run(); 54} 55 56DelegateSimpleThread::DelegateSimpleThread(Delegate* delegate, 57 const std::string& name_prefix) 58 : SimpleThread(name_prefix), 59 delegate_(delegate) { 60} 61 62DelegateSimpleThread::DelegateSimpleThread(Delegate* delegate, 63 const std::string& name_prefix, 64 const Options& options) 65 : SimpleThread(name_prefix, options), 66 delegate_(delegate) { 67} 68 69DelegateSimpleThread::~DelegateSimpleThread() { 70} 71 72void DelegateSimpleThread::Run() { 73 DCHECK(delegate_) << "Tried to call Run without a delegate (called twice?)"; 74 delegate_->Run(); 75 delegate_ = NULL; 76} 77 78DelegateSimpleThreadPool::DelegateSimpleThreadPool( 79 const std::string& name_prefix, 80 int num_threads) 81 : name_prefix_(name_prefix), 82 num_threads_(num_threads), 83 dry_(true, false) { 84} 85 86DelegateSimpleThreadPool::~DelegateSimpleThreadPool() { 87 DCHECK(threads_.empty()); 88 DCHECK(delegates_.empty()); 89 DCHECK(!dry_.IsSignaled()); 90} 91 92void DelegateSimpleThreadPool::Start() { 93 DCHECK(threads_.empty()) << "Start() called with outstanding threads."; 94 for (int i = 0; i < num_threads_; ++i) { 95 DelegateSimpleThread* thread = new DelegateSimpleThread(this, name_prefix_); 96 thread->Start(); 97 threads_.push_back(thread); 98 } 99} 100 101void DelegateSimpleThreadPool::JoinAll() { 102 DCHECK(!threads_.empty()) << "JoinAll() called with no outstanding threads."; 103 104 // Tell all our threads to quit their worker loop. 105 AddWork(NULL, num_threads_); 106 107 // Join and destroy all the worker threads. 108 for (int i = 0; i < num_threads_; ++i) { 109 threads_[i]->Join(); 110 delete threads_[i]; 111 } 112 threads_.clear(); 113 DCHECK(delegates_.empty()); 114} 115 116void DelegateSimpleThreadPool::AddWork(Delegate* delegate, int repeat_count) { 117 AutoLock locked(lock_); 118 for (int i = 0; i < repeat_count; ++i) 119 delegates_.push(delegate); 120 // If we were empty, signal that we have work now. 121 if (!dry_.IsSignaled()) 122 dry_.Signal(); 123} 124 125void DelegateSimpleThreadPool::Run() { 126 Delegate* work = NULL; 127 128 while (true) { 129 dry_.Wait(); 130 { 131 AutoLock locked(lock_); 132 if (!dry_.IsSignaled()) 133 continue; 134 135 DCHECK(!delegates_.empty()); 136 work = delegates_.front(); 137 delegates_.pop(); 138 139 // Signal to any other threads that we're currently out of work. 140 if (delegates_.empty()) 141 dry_.Reset(); 142 } 143 144 // A NULL delegate pointer signals us to quit. 145 if (!work) 146 break; 147 148 work->Run(); 149 } 150} 151 152} // namespace base 153