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
11 namespace base {
12
SimpleThread(const std::string & name_prefix)13 SimpleThread::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
SimpleThread(const std::string & name_prefix,const Options & options)18 SimpleThread::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
~SimpleThread()24 SimpleThread::~SimpleThread() {
25 DCHECK(HasBeenStarted()) << "SimpleThread was never started.";
26 DCHECK(HasBeenJoined()) << "SimpleThread destroyed without being Join()ed.";
27 }
28
Start()29 void 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
Join()36 void 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
ThreadMain()43 void 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
DelegateSimpleThread(Delegate * delegate,const std::string & name_prefix)56 DelegateSimpleThread::DelegateSimpleThread(Delegate* delegate,
57 const std::string& name_prefix)
58 : SimpleThread(name_prefix),
59 delegate_(delegate) {
60 }
61
DelegateSimpleThread(Delegate * delegate,const std::string & name_prefix,const Options & options)62 DelegateSimpleThread::DelegateSimpleThread(Delegate* delegate,
63 const std::string& name_prefix,
64 const Options& options)
65 : SimpleThread(name_prefix, options),
66 delegate_(delegate) {
67 }
68
~DelegateSimpleThread()69 DelegateSimpleThread::~DelegateSimpleThread() {
70 }
71
Run()72 void DelegateSimpleThread::Run() {
73 DCHECK(delegate_) << "Tried to call Run without a delegate (called twice?)";
74 delegate_->Run();
75 delegate_ = NULL;
76 }
77
DelegateSimpleThreadPool(const std::string & name_prefix,int num_threads)78 DelegateSimpleThreadPool::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
~DelegateSimpleThreadPool()86 DelegateSimpleThreadPool::~DelegateSimpleThreadPool() {
87 DCHECK(threads_.empty());
88 DCHECK(delegates_.empty());
89 DCHECK(!dry_.IsSignaled());
90 }
91
Start()92 void 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
JoinAll()101 void 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
AddWork(Delegate * delegate,int repeat_count)116 void 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
Run()125 void 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