Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(91)

Side by Side Diff: base/threading/thread.cc

Issue 1256903005: base/threading: fix a potential race issue on start_event_ (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: [rebase] Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/threading/thread.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/threading/thread.h" 5 #include "base/threading/thread.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/lazy_instance.h" 8 #include "base/lazy_instance.h"
9 #include "base/location.h" 9 #include "base/location.h"
10 #include "base/synchronization/waitable_event.h" 10 #include "base/synchronization/waitable_event.h"
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
59 #if defined(OS_WIN) 59 #if defined(OS_WIN)
60 com_status_(NONE), 60 com_status_(NONE),
61 #endif 61 #endif
62 stopping_(false), 62 stopping_(false),
63 running_(false), 63 running_(false),
64 thread_(0), 64 thread_(0),
65 id_(kInvalidThreadId), 65 id_(kInvalidThreadId),
66 id_event_(true, false), 66 id_event_(true, false),
67 message_loop_(nullptr), 67 message_loop_(nullptr),
68 message_loop_timer_slack_(TIMER_SLACK_NONE), 68 message_loop_timer_slack_(TIMER_SLACK_NONE),
69 name_(name) { 69 name_(name),
70 start_event_(false, false) {
70 } 71 }
71 72
72 Thread::~Thread() { 73 Thread::~Thread() {
73 Stop(); 74 Stop();
74 } 75 }
75 76
76 bool Thread::Start() { 77 bool Thread::Start() {
77 Options options; 78 Options options;
78 #if defined(OS_WIN) 79 #if defined(OS_WIN)
79 if (com_status_ == STA) 80 if (com_status_ == STA)
(...skipping 16 matching lines...) Expand all
96 SetThreadWasQuitProperly(false); 97 SetThreadWasQuitProperly(false);
97 98
98 MessageLoop::Type type = options.message_loop_type; 99 MessageLoop::Type type = options.message_loop_type;
99 if (!options.message_pump_factory.is_null()) 100 if (!options.message_pump_factory.is_null())
100 type = MessageLoop::TYPE_CUSTOM; 101 type = MessageLoop::TYPE_CUSTOM;
101 102
102 message_loop_timer_slack_ = options.timer_slack; 103 message_loop_timer_slack_ = options.timer_slack;
103 scoped_ptr<MessageLoop> message_loop = MessageLoop::CreateUnbound( 104 scoped_ptr<MessageLoop> message_loop = MessageLoop::CreateUnbound(
104 type, options.message_pump_factory); 105 type, options.message_pump_factory);
105 message_loop_ = message_loop.get(); 106 message_loop_ = message_loop.get();
106 start_event_.reset(new WaitableEvent(false, false)); 107 start_event_.Reset();
107 108
108 // Hold the thread_lock_ while starting a new thread, so that we can make sure 109 // Hold the thread_lock_ while starting a new thread, so that we can make sure
109 // that thread_ is populated before the newly created thread accesses it. 110 // that thread_ is populated before the newly created thread accesses it.
110 { 111 {
111 AutoLock lock(thread_lock_); 112 AutoLock lock(thread_lock_);
112 if (!PlatformThread::CreateWithPriority(options.stack_size, this, &thread_, 113 if (!PlatformThread::CreateWithPriority(options.stack_size, this, &thread_,
113 options.priority)) { 114 options.priority)) {
114 DLOG(ERROR) << "failed to create thread"; 115 DLOG(ERROR) << "failed to create thread";
115 message_loop_ = nullptr; 116 message_loop_ = nullptr;
116 start_event_.reset();
117 return false; 117 return false;
118 } 118 }
119 } 119 }
120 120
121 // The ownership of message_loop is managemed by the newly created thread 121 // The ownership of message_loop is managemed by the newly created thread
122 // within the ThreadMain. 122 // within the ThreadMain.
123 ignore_result(message_loop.release()); 123 ignore_result(message_loop.release());
124 124
125 DCHECK(message_loop_); 125 DCHECK(message_loop_);
126 return true; 126 return true;
127 } 127 }
128 128
129 bool Thread::StartAndWaitForTesting() { 129 bool Thread::StartAndWaitForTesting() {
130 bool result = Start(); 130 bool result = Start();
131 if (!result) 131 if (!result)
132 return false; 132 return false;
133 WaitUntilThreadStarted(); 133 WaitUntilThreadStarted();
134 return true; 134 return true;
135 } 135 }
136 136
137 bool Thread::WaitUntilThreadStarted() { 137 bool Thread::WaitUntilThreadStarted() const {
138 if (!start_event_) 138 if (!message_loop_)
139 return false; 139 return false;
140 base::ThreadRestrictions::ScopedAllowWait allow_wait; 140 base::ThreadRestrictions::ScopedAllowWait allow_wait;
141 start_event_->Wait(); 141 start_event_.Wait();
142 return true; 142 return true;
143 } 143 }
144 144
145 void Thread::Stop() { 145 void Thread::Stop() {
146 if (!start_event_) 146 AutoLock lock(thread_lock_);
147 if (thread_.is_null())
147 return; 148 return;
148 149
149 StopSoon(); 150 StopSoon();
150 151
151 // Wait for the thread to exit. 152 // Wait for the thread to exit.
152 // 153 //
153 // TODO(darin): Unfortunately, we need to keep message_loop_ around until 154 // TODO(darin): Unfortunately, we need to keep message_loop_ around until
154 // the thread exits. Some consumers are abusing the API. Make them stop. 155 // the thread exits. Some consumers are abusing the API. Make them stop.
155 // 156 //
156 PlatformThread::Join(thread_); 157 PlatformThread::Join(thread_);
158 thread_ = base::PlatformThreadHandle();
157 159
158 // The thread should NULL message_loop_ on exit. 160 // The thread should nullify message_loop_ on exit.
159 DCHECK(!message_loop_); 161 DCHECK(!message_loop_);
160 162
161 // The thread no longer needs to be joined.
162 start_event_.reset();
163
164 stopping_ = false; 163 stopping_ = false;
165 } 164 }
166 165
167 void Thread::StopSoon() { 166 void Thread::StopSoon() {
168 // We should only be called on the same thread that started us. 167 // We should only be called on the same thread that started us.
169 168
170 DCHECK_NE(GetThreadId(), PlatformThread::CurrentId()); 169 DCHECK_NE(GetThreadId(), PlatformThread::CurrentId());
171 170
172 if (stopping_ || !message_loop_) 171 if (stopping_ || !message_loop_)
173 return; 172 return;
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
240 #endif 239 #endif
241 240
242 // Let the thread do extra initialization. 241 // Let the thread do extra initialization.
243 Init(); 242 Init();
244 243
245 { 244 {
246 AutoLock lock(running_lock_); 245 AutoLock lock(running_lock_);
247 running_ = true; 246 running_ = true;
248 } 247 }
249 248
250 start_event_->Signal(); 249 start_event_.Signal();
251 250
252 Run(message_loop_); 251 Run(message_loop_);
253 252
254 { 253 {
255 AutoLock lock(running_lock_); 254 AutoLock lock(running_lock_);
256 running_ = false; 255 running_ = false;
257 } 256 }
258 257
259 // Let the thread do extra cleanup. 258 // Let the thread do extra cleanup.
260 CleanUp(); 259 CleanUp();
261 260
262 #if defined(OS_WIN) 261 #if defined(OS_WIN)
263 com_initializer.reset(); 262 com_initializer.reset();
264 #endif 263 #endif
265 264
266 // Assert that MessageLoop::Quit was called by ThreadQuitHelper. 265 // Assert that MessageLoop::Quit was called by ThreadQuitHelper.
267 DCHECK(GetThreadWasQuitProperly()); 266 DCHECK(GetThreadWasQuitProperly());
268 267
269 // We can't receive messages anymore. 268 // We can't receive messages anymore.
270 // (The message loop is destructed at the end of this block) 269 // (The message loop is destructed at the end of this block)
271 message_loop_ = NULL; 270 message_loop_ = nullptr;
272 } 271 }
273 272
274 } // namespace base 273 } // namespace base
OLDNEW
« no previous file with comments | « base/threading/thread.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698