blob: 0fe023adca9a32e0aa79e4d1b9fe26b433fcac60 [file] [log] [blame]
license.botbf09a502008-08-24 00:55:551// 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.
initial.commitd7cae122008-07-26 21:49:384
[email protected]eff4aecb2008-08-12 18:37:355#include "base/thread.h"
6
initial.commitd7cae122008-07-26 21:49:387#include "base/message_loop.h"
initial.commitd7cae122008-07-26 21:49:388#include "base/string_util.h"
[email protected]ffd83082008-08-11 14:35:159#include "base/waitable_event.h"
[email protected]eff4aecb2008-08-12 18:37:3510
initial.commitd7cae122008-07-26 21:49:3811// This task is used to trigger the message loop to exit.
12class ThreadQuitTask : public Task {
13 public:
14 virtual void Run() {
15 MessageLoop::current()->Quit();
16 Thread::SetThreadWasQuitProperly(true);
17 }
18};
19
initial.commitd7cae122008-07-26 21:49:3820Thread::Thread(const char *name)
[email protected]e9ba26d2008-08-21 09:46:3221 : message_loop_(NULL),
22 startup_event_(NULL),
23 name_(name),
24 thread_created_(false) {
initial.commitd7cae122008-07-26 21:49:3825}
26
27Thread::~Thread() {
28 Stop();
29}
30
31// We use this thread-local variable to record whether or not a thread exited
32// because its Stop method was called. This allows us to catch cases where
33// MessageLoop::Quit() is called directly, which is unexpected when using a
34// Thread to setup and run a MessageLoop.
35// Note that if we start doing complex stuff in other static initializers
36// this could cause problems.
[email protected]6a6e6572008-08-20 22:54:5237// TODO(evanm): this shouldn't rely on static initialization.
38TLSSlot Thread::tls_index_;
initial.commitd7cae122008-07-26 21:49:3839
40void Thread::SetThreadWasQuitProperly(bool flag) {
41#ifndef NDEBUG
[email protected]6a6e6572008-08-20 22:54:5242 tls_index_.Set(reinterpret_cast<void*>(flag));
initial.commitd7cae122008-07-26 21:49:3843#endif
44}
45
46bool Thread::GetThreadWasQuitProperly() {
47 bool quit_properly = true;
48#ifndef NDEBUG
[email protected]6a6e6572008-08-20 22:54:5249 quit_properly = (tls_index_.Get() != 0);
initial.commitd7cae122008-07-26 21:49:3850#endif
51 return quit_properly;
52}
53
initial.commitd7cae122008-07-26 21:49:3854bool Thread::Start() {
55 return StartWithStackSize(0);
56}
57
58bool Thread::StartWithStackSize(size_t stack_size) {
[email protected]e9ba26d2008-08-21 09:46:3259 DCHECK(!message_loop_);
initial.commitd7cae122008-07-26 21:49:3860
[email protected]e9ba26d2008-08-21 09:46:3261 SetThreadWasQuitProperly(false);
62
63 base::WaitableEvent event(false, false);
64 startup_event_ = &event;
65
66 if (!PlatformThread::Create(stack_size, this, &thread_)) {
initial.commitd7cae122008-07-26 21:49:3867 DLOG(ERROR) << "failed to create thread";
68 return false;
69 }
70
71 // Wait for the thread to start and initialize message_loop_
[email protected]e9ba26d2008-08-21 09:46:3272 startup_event_->Wait();
73 startup_event_ = NULL;
74
75 DCHECK(message_loop_);
initial.commitd7cae122008-07-26 21:49:3876 return true;
77}
78
79void Thread::Stop() {
[email protected]e9ba26d2008-08-21 09:46:3280 if (!thread_created_)
initial.commitd7cae122008-07-26 21:49:3881 return;
82
[email protected]e9ba26d2008-08-21 09:46:3283 DCHECK_NE(thread_id_, PlatformThread::CurrentId()) <<
84 "Can't call Stop() on the currently executing thread";
initial.commitd7cae122008-07-26 21:49:3885
[email protected]e9ba26d2008-08-21 09:46:3286 // If StopSoon was called, then we won't have a message loop anymore, but
87 // more importantly, we won't need to tell the thread to stop.
88 if (message_loop_)
[email protected]eff4aecb2008-08-12 18:37:3589 message_loop_->PostTask(FROM_HERE, new ThreadQuitTask());
90
91 // Wait for the thread to exit. It should already have terminated but make
92 // sure this assumption is valid.
[email protected]e9ba26d2008-08-21 09:46:3293 PlatformThread::Join(thread_);
[email protected]eff4aecb2008-08-12 18:37:3594
[email protected]e9ba26d2008-08-21 09:46:3295 // The thread can't receive messages anymore.
96 message_loop_ = NULL;
97
98 // The thread no longer needs to be joined.
99 thread_created_ = false;
[email protected]eff4aecb2008-08-12 18:37:35100}
101
102void Thread::StopSoon() {
[email protected]e9ba26d2008-08-21 09:46:32103 if (!message_loop_)
[email protected]eff4aecb2008-08-12 18:37:35104 return;
105
[email protected]e9ba26d2008-08-21 09:46:32106 DCHECK_NE(thread_id_, PlatformThread::CurrentId()) <<
107 "Can't call StopSoon() on the currently executing thread";
[email protected]eff4aecb2008-08-12 18:37:35108
initial.commitd7cae122008-07-26 21:49:38109 // We had better have a message loop at this point! If we do not, then it
110 // most likely means that the thread terminated unexpectedly, probably due
111 // to someone calling Quit() on our message loop directly.
112 DCHECK(message_loop_);
113
114 message_loop_->PostTask(FROM_HERE, new ThreadQuitTask());
115
[email protected]eff4aecb2008-08-12 18:37:35116 // The thread can't receive messages anymore.
[email protected]e9ba26d2008-08-21 09:46:32117 message_loop_ = NULL;
initial.commitd7cae122008-07-26 21:49:38118}
119
[email protected]e9ba26d2008-08-21 09:46:32120void Thread::ThreadMain() {
initial.commitd7cae122008-07-26 21:49:38121 // The message loop for this thread.
122 MessageLoop message_loop;
123
[email protected]eff4aecb2008-08-12 18:37:35124 // Complete the initialization of our Thread object.
[email protected]e9ba26d2008-08-21 09:46:32125 thread_id_ = PlatformThread::CurrentId();
[email protected]7d0f94452008-08-25 13:54:18126 PlatformThread::SetName(name_.c_str());
[email protected]e9ba26d2008-08-21 09:46:32127 message_loop.set_thread_name(name_);
128 message_loop_ = &message_loop;
129 thread_created_ = true;
130
131 startup_event_->Signal();
132 // startup_event_ can't be touched anymore since the starting thread is now
133 // unlocked.
initial.commitd7cae122008-07-26 21:49:38134
135 // Let the thread do extra initialization.
[email protected]e9ba26d2008-08-21 09:46:32136 Init();
initial.commitd7cae122008-07-26 21:49:38137
138 message_loop.Run();
139
140 // Let the thread do extra cleanup.
[email protected]e9ba26d2008-08-21 09:46:32141 CleanUp();
initial.commitd7cae122008-07-26 21:49:38142
143 // Assert that MessageLoop::Quit was called by ThreadQuitTask.
[email protected]e9ba26d2008-08-21 09:46:32144 DCHECK(GetThreadWasQuitProperly());
initial.commitd7cae122008-07-26 21:49:38145
[email protected]eff4aecb2008-08-12 18:37:35146 // We can't receive messages anymore.
[email protected]e9ba26d2008-08-21 09:46:32147 message_loop_ = NULL;
initial.commitd7cae122008-07-26 21:49:38148}
license.botbf09a502008-08-24 00:55:55149