michael@0: // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. michael@0: // Use of this source code is governed by a BSD-style license that can be michael@0: // found in the LICENSE file. michael@0: michael@0: #include "base/simple_thread.h" michael@0: michael@0: #include "base/waitable_event.h" michael@0: #include "base/logging.h" michael@0: #include "base/platform_thread.h" michael@0: #include "base/string_util.h" michael@0: michael@0: namespace base { michael@0: michael@0: void SimpleThread::Start() { michael@0: DCHECK(!HasBeenStarted()) << "Tried to Start a thread multiple times."; michael@0: bool success = PlatformThread::Create(options_.stack_size(), this, &thread_); michael@0: CHECK(success); michael@0: event_.Wait(); // Wait for the thread to complete initialization. michael@0: } michael@0: michael@0: void SimpleThread::Join() { michael@0: DCHECK(HasBeenStarted()) << "Tried to Join a never-started thread."; michael@0: DCHECK(!HasBeenJoined()) << "Tried to Join a thread multiple times."; michael@0: PlatformThread::Join(thread_); michael@0: joined_ = true; michael@0: } michael@0: michael@0: void SimpleThread::ThreadMain() { michael@0: tid_ = PlatformThread::CurrentId(); michael@0: // Construct our full name of the form "name_prefix_/TID". michael@0: name_.push_back('/'); michael@0: name_.append(IntToString(tid_)); michael@0: PlatformThread::SetName(name_.c_str()); michael@0: michael@0: // We've initialized our new thread, signal that we're done to Start(). michael@0: event_.Signal(); michael@0: michael@0: Run(); michael@0: } michael@0: michael@0: SimpleThread::~SimpleThread() { michael@0: DCHECK(HasBeenStarted()) << "SimpleThread was never started."; michael@0: DCHECK(HasBeenJoined()) << "SimpleThread destroyed without being Join()ed."; michael@0: } michael@0: michael@0: void DelegateSimpleThread::Run() { michael@0: DCHECK(delegate_) << "Tried to call Run without a delegate (called twice?)"; michael@0: delegate_->Run(); michael@0: delegate_ = NULL; michael@0: } michael@0: michael@0: DelegateSimpleThreadPool::~DelegateSimpleThreadPool() { michael@0: DCHECK(threads_.empty()); michael@0: DCHECK(delegates_.empty()); michael@0: DCHECK(!dry_.IsSignaled()); michael@0: } michael@0: michael@0: void DelegateSimpleThreadPool::Start() { michael@0: DCHECK(threads_.empty()) << "Start() called with outstanding threads."; michael@0: for (int i = 0; i < num_threads_; ++i) { michael@0: DelegateSimpleThread* thread = new DelegateSimpleThread(this, name_prefix_); michael@0: thread->Start(); michael@0: threads_.push_back(thread); michael@0: } michael@0: } michael@0: michael@0: void DelegateSimpleThreadPool::JoinAll() { michael@0: DCHECK(!threads_.empty()) << "JoinAll() called with no outstanding threads."; michael@0: michael@0: // Tell all our threads to quit their worker loop. michael@0: AddWork(NULL, num_threads_); michael@0: michael@0: // Join and destroy all the worker threads. michael@0: for (int i = 0; i < num_threads_; ++i) { michael@0: threads_[i]->Join(); michael@0: delete threads_[i]; michael@0: } michael@0: threads_.clear(); michael@0: DCHECK(delegates_.empty()); michael@0: } michael@0: michael@0: void DelegateSimpleThreadPool::AddWork(Delegate* delegate, int repeat_count) { michael@0: AutoLock locked(lock_); michael@0: for (int i = 0; i < repeat_count; ++i) michael@0: delegates_.push(delegate); michael@0: // If we were empty, signal that we have work now. michael@0: if (!dry_.IsSignaled()) michael@0: dry_.Signal(); michael@0: } michael@0: michael@0: void DelegateSimpleThreadPool::Run() { michael@0: Delegate* work; michael@0: michael@0: while (true) { michael@0: dry_.Wait(); michael@0: { michael@0: AutoLock locked(lock_); michael@0: if (!dry_.IsSignaled()) michael@0: continue; michael@0: michael@0: DCHECK(!delegates_.empty()); michael@0: work = delegates_.front(); michael@0: delegates_.pop(); michael@0: michael@0: // Signal to any other threads that we're currently out of work. michael@0: if (delegates_.empty()) michael@0: dry_.Reset(); michael@0: } michael@0: michael@0: // A NULL delegate pointer signals us to quit. michael@0: if (!work) michael@0: break; michael@0: michael@0: work->Run(); michael@0: } michael@0: } michael@0: michael@0: } // namespace base