13f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen// Copyright (c) 2010 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/simple_thread.h"
6c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
7c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/logging.h"
83f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/threading/platform_thread.h"
93345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/string_number_conversions.h"
10c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
11c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottnamespace base {
12c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
1372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenSimpleThread::SimpleThread(const std::string& name_prefix)
1472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    : name_prefix_(name_prefix), name_(name_prefix),
1572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      thread_(), event_(true, false), tid_(0), joined_(false) {
1672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
1772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
1872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenSimpleThread::SimpleThread(const std::string& name_prefix,
1972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                           const Options& options)
2072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    : name_prefix_(name_prefix), name_(name_prefix), options_(options),
2172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      thread_(), event_(true, false), tid_(0), joined_(false) {
2272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
2372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
2472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenSimpleThread::~SimpleThread() {
2572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  DCHECK(HasBeenStarted()) << "SimpleThread was never started.";
2672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  DCHECK(HasBeenJoined()) << "SimpleThread destroyed without being Join()ed.";
2772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
2872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
29c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid SimpleThread::Start() {
30c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(!HasBeenStarted()) << "Tried to Start a thread multiple times.";
31c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  bool success = PlatformThread::Create(options_.stack_size(), this, &thread_);
32c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  CHECK(success);
33c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  event_.Wait();  // Wait for the thread to complete initialization.
34c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
35c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
36c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid SimpleThread::Join() {
37c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(HasBeenStarted()) << "Tried to Join a never-started thread.";
38c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(!HasBeenJoined()) << "Tried to Join a thread multiple times.";
39c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  PlatformThread::Join(thread_);
40c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  joined_ = true;
41c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
42c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
43c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid SimpleThread::ThreadMain() {
44c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  tid_ = PlatformThread::CurrentId();
45c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Construct our full name of the form "name_prefix_/TID".
46c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  name_.push_back('/');
47c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  name_.append(IntToString(tid_));
48c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  PlatformThread::SetName(name_.c_str());
49c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
50c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // We've initialized our new thread, signal that we're done to Start().
51c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  event_.Signal();
52c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
53c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  Run();
54c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
55c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
56731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickDelegateSimpleThread::DelegateSimpleThread(Delegate* delegate,
57731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                           const std::string& name_prefix)
58731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    : SimpleThread(name_prefix),
59731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      delegate_(delegate) {
60731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
61731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
62731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickDelegateSimpleThread::DelegateSimpleThread(Delegate* delegate,
63731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                           const std::string& name_prefix,
64731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                           const Options& options)
65731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    : SimpleThread(name_prefix, options),
66731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      delegate_(delegate) {
67731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
68731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
69731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickDelegateSimpleThread::~DelegateSimpleThread() {
70731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
71731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
72c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid DelegateSimpleThread::Run() {
73c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(delegate_) << "Tried to call Run without a delegate (called twice?)";
74c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  delegate_->Run();
75c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  delegate_ = NULL;
76c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
77c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
78731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickDelegateSimpleThreadPool::DelegateSimpleThreadPool(
79731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    const std::string& name_prefix,
80731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    int num_threads)
81731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    : name_prefix_(name_prefix),
82731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      num_threads_(num_threads),
83731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      dry_(true, false) {
84731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
85731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
86c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottDelegateSimpleThreadPool::~DelegateSimpleThreadPool() {
87c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(threads_.empty());
88c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(delegates_.empty());
89c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(!dry_.IsSignaled());
90c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
91c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
92c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid DelegateSimpleThreadPool::Start() {
93c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(threads_.empty()) << "Start() called with outstanding threads.";
94c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  for (int i = 0; i < num_threads_; ++i) {
95c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    DelegateSimpleThread* thread = new DelegateSimpleThread(this, name_prefix_);
96c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    thread->Start();
97c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    threads_.push_back(thread);
98c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
99c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
100c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
101c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid DelegateSimpleThreadPool::JoinAll() {
102c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(!threads_.empty()) << "JoinAll() called with no outstanding threads.";
103c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
104c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Tell all our threads to quit their worker loop.
105c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  AddWork(NULL, num_threads_);
106c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
107c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Join and destroy all the worker threads.
108c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  for (int i = 0; i < num_threads_; ++i) {
109c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    threads_[i]->Join();
110c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    delete threads_[i];
111c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
112c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  threads_.clear();
113c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(delegates_.empty());
114c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
115c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
116c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid DelegateSimpleThreadPool::AddWork(Delegate* delegate, int repeat_count) {
117c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  AutoLock locked(lock_);
118c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  for (int i = 0; i < repeat_count; ++i)
119c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    delegates_.push(delegate);
120c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // If we were empty, signal that we have work now.
121c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!dry_.IsSignaled())
122c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    dry_.Signal();
123c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
124c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
125c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid DelegateSimpleThreadPool::Run() {
126c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  Delegate* work = NULL;
127c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
128c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  while (true) {
129c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    dry_.Wait();
130c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    {
131c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      AutoLock locked(lock_);
132c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      if (!dry_.IsSignaled())
133c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        continue;
134c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
135c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      DCHECK(!delegates_.empty());
136c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      work = delegates_.front();
137c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      delegates_.pop();
138c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
139c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      // Signal to any other threads that we're currently out of work.
140c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      if (delegates_.empty())
141c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        dry_.Reset();
142c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
143c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
144c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // A NULL delegate pointer signals us to quit.
145c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (!work)
146c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      break;
147c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
148c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    work->Run();
149c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
150c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
151c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
152c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}  // namespace base
153