1 : // Copyright (c) 2006-2008 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/simple_thread.h"
6 :
7 : #include "base/waitable_event.h"
8 : #include "base/logging.h"
9 : #include "base/platform_thread.h"
10 : #include "base/string_util.h"
11 :
12 : namespace base {
13 :
14 0 : void SimpleThread::Start() {
15 0 : DCHECK(!HasBeenStarted()) << "Tried to Start a thread multiple times.";
16 0 : bool success = PlatformThread::Create(options_.stack_size(), this, &thread_);
17 0 : CHECK(success);
18 0 : event_.Wait(); // Wait for the thread to complete initialization.
19 0 : }
20 :
21 0 : void SimpleThread::Join() {
22 0 : DCHECK(HasBeenStarted()) << "Tried to Join a never-started thread.";
23 0 : DCHECK(!HasBeenJoined()) << "Tried to Join a thread multiple times.";
24 0 : PlatformThread::Join(thread_);
25 0 : joined_ = true;
26 0 : }
27 :
28 0 : void SimpleThread::ThreadMain() {
29 0 : tid_ = PlatformThread::CurrentId();
30 : // Construct our full name of the form "name_prefix_/TID".
31 0 : name_.push_back('/');
32 0 : name_.append(IntToString(tid_));
33 0 : PlatformThread::SetName(name_.c_str());
34 :
35 : // We've initialized our new thread, signal that we're done to Start().
36 0 : event_.Signal();
37 :
38 0 : Run();
39 0 : }
40 :
41 0 : SimpleThread::~SimpleThread() {
42 0 : DCHECK(HasBeenStarted()) << "SimpleThread was never started.";
43 0 : DCHECK(HasBeenJoined()) << "SimpleThread destroyed without being Join()ed.";
44 0 : }
45 :
46 0 : void DelegateSimpleThread::Run() {
47 0 : DCHECK(delegate_) << "Tried to call Run without a delegate (called twice?)";
48 0 : delegate_->Run();
49 0 : delegate_ = NULL;
50 0 : }
51 :
52 0 : DelegateSimpleThreadPool::~DelegateSimpleThreadPool() {
53 0 : DCHECK(threads_.empty());
54 0 : DCHECK(delegates_.empty());
55 0 : DCHECK(!dry_.IsSignaled());
56 0 : }
57 :
58 0 : void DelegateSimpleThreadPool::Start() {
59 0 : DCHECK(threads_.empty()) << "Start() called with outstanding threads.";
60 0 : for (int i = 0; i < num_threads_; ++i) {
61 0 : DelegateSimpleThread* thread = new DelegateSimpleThread(this, name_prefix_);
62 0 : thread->Start();
63 0 : threads_.push_back(thread);
64 : }
65 0 : }
66 :
67 0 : void DelegateSimpleThreadPool::JoinAll() {
68 0 : DCHECK(!threads_.empty()) << "JoinAll() called with no outstanding threads.";
69 :
70 : // Tell all our threads to quit their worker loop.
71 0 : AddWork(NULL, num_threads_);
72 :
73 : // Join and destroy all the worker threads.
74 0 : for (int i = 0; i < num_threads_; ++i) {
75 0 : threads_[i]->Join();
76 0 : delete threads_[i];
77 : }
78 0 : threads_.clear();
79 0 : DCHECK(delegates_.empty());
80 0 : }
81 :
82 0 : void DelegateSimpleThreadPool::AddWork(Delegate* delegate, int repeat_count) {
83 0 : AutoLock locked(lock_);
84 0 : for (int i = 0; i < repeat_count; ++i)
85 0 : delegates_.push(delegate);
86 : // If we were empty, signal that we have work now.
87 0 : if (!dry_.IsSignaled())
88 0 : dry_.Signal();
89 0 : }
90 :
91 0 : void DelegateSimpleThreadPool::Run() {
92 : Delegate* work;
93 :
94 0 : while (true) {
95 0 : dry_.Wait();
96 : {
97 0 : AutoLock locked(lock_);
98 0 : if (!dry_.IsSignaled())
99 0 : continue;
100 :
101 0 : DCHECK(!delegates_.empty());
102 0 : work = delegates_.front();
103 0 : delegates_.pop();
104 :
105 : // Signal to any other threads that we're currently out of work.
106 0 : if (delegates_.empty())
107 0 : dry_.Reset();
108 : }
109 :
110 : // A NULL delegate pointer signals us to quit.
111 0 : if (!work)
112 : break;
113 :
114 0 : work->Run();
115 : }
116 0 : }
117 :
118 : } // namespace base
|