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

Side by Side Diff: content/browser/browser_thread_impl.cc

Issue 2464233002: Experiment with redirecting all BrowserThreads (but UI/IO) to TaskScheduler (Closed)
Patch Set: remove WaitUntilThreadStarted on Android, makes Android test instrumentation hang, is previous issu… Created 4 years 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 | « content/browser/browser_thread_impl.h ('k') | content/public/browser/content_browser_client.h » ('j') | 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 "content/browser/browser_thread_impl.h" 5 #include "content/browser/browser_thread_impl.h"
6 6
7 #include <string.h>
8
9 #include <string> 7 #include <string>
10 8
11 #include "base/atomicops.h" 9 #include "base/atomicops.h"
12 #include "base/bind.h" 10 #include "base/bind.h"
13 #include "base/compiler_specific.h" 11 #include "base/compiler_specific.h"
14 #include "base/lazy_instance.h" 12 #include "base/lazy_instance.h"
13 #include "base/logging.h"
15 #include "base/macros.h" 14 #include "base/macros.h"
15 #include "base/message_loop/message_loop.h"
16 #include "base/profiler/scoped_tracker.h" 16 #include "base/profiler/scoped_tracker.h"
17 #include "base/run_loop.h" 17 #include "base/run_loop.h"
18 #include "base/single_thread_task_runner.h" 18 #include "base/synchronization/waitable_event.h"
19 #include "base/threading/platform_thread.h" 19 #include "base/threading/platform_thread.h"
20 #include "base/threading/sequenced_worker_pool.h" 20 #include "base/threading/sequenced_worker_pool.h"
21 #include "build/build_config.h" 21 #include "build/build_config.h"
22 #include "content/public/browser/browser_thread_delegate.h" 22 #include "content/public/browser/browser_thread_delegate.h"
23 #include "content/public/browser/content_browser_client.h" 23 #include "content/public/browser/content_browser_client.h"
24 #include "net/disk_cache/simple/simple_backend_impl.h" 24 #include "net/disk_cache/simple/simple_backend_impl.h"
25 25
26 #if defined(OS_ANDROID) 26 #if defined(OS_ANDROID)
27 #include "base/android/jni_android.h" 27 #include "base/android/jni_android.h"
28 #endif 28 #endif
(...skipping 16 matching lines...) Expand all
45 static const char* GetThreadName(BrowserThread::ID thread) { 45 static const char* GetThreadName(BrowserThread::ID thread) {
46 if (BrowserThread::UI < thread && thread < BrowserThread::ID_COUNT) 46 if (BrowserThread::UI < thread && thread < BrowserThread::ID_COUNT)
47 return g_browser_thread_names[thread]; 47 return g_browser_thread_names[thread];
48 if (thread == BrowserThread::UI) 48 if (thread == BrowserThread::UI)
49 return "Chrome_UIThread"; 49 return "Chrome_UIThread";
50 return "Unknown Thread"; 50 return "Unknown Thread";
51 } 51 }
52 52
53 // An implementation of SingleThreadTaskRunner to be used in conjunction 53 // An implementation of SingleThreadTaskRunner to be used in conjunction
54 // with BrowserThread. 54 // with BrowserThread.
55 // TODO(gab): Consider replacing this with |g_globals->task_runners| -- only
56 // works if none are requested before starting the threads.
55 class BrowserThreadTaskRunner : public base::SingleThreadTaskRunner { 57 class BrowserThreadTaskRunner : public base::SingleThreadTaskRunner {
56 public: 58 public:
57 explicit BrowserThreadTaskRunner(BrowserThread::ID identifier) 59 explicit BrowserThreadTaskRunner(BrowserThread::ID identifier)
58 : id_(identifier) {} 60 : id_(identifier) {}
59 61
60 // SingleThreadTaskRunner implementation. 62 // SingleThreadTaskRunner implementation.
61 bool PostDelayedTask(const tracked_objects::Location& from_here, 63 bool PostDelayedTask(const tracked_objects::Location& from_here,
62 const base::Closure& task, 64 const base::Closure& task,
63 base::TimeDelta delay) override { 65 base::TimeDelta delay) override {
64 return BrowserThread::PostDelayedTask(id_, from_here, task, delay); 66 return BrowserThread::PostDelayedTask(id_, from_here, task, delay);
(...skipping 27 matching lines...) Expand all
92 new BrowserThreadTaskRunner(static_cast<BrowserThread::ID>(i)); 94 new BrowserThreadTaskRunner(static_cast<BrowserThread::ID>(i));
93 } 95 }
94 } 96 }
95 97
96 scoped_refptr<base::SingleThreadTaskRunner> proxies[BrowserThread::ID_COUNT]; 98 scoped_refptr<base::SingleThreadTaskRunner> proxies[BrowserThread::ID_COUNT];
97 }; 99 };
98 100
99 base::LazyInstance<BrowserThreadTaskRunners>::Leaky g_task_runners = 101 base::LazyInstance<BrowserThreadTaskRunners>::Leaky g_task_runners =
100 LAZY_INSTANCE_INITIALIZER; 102 LAZY_INSTANCE_INITIALIZER;
101 103
104 // State of a given BrowserThread::ID in chronological order throughout the
105 // browser process' lifetime.
106 enum BrowserThreadState {
107 // BrowserThread::ID isn't associated with anything yet.
108 UNINITIALIZED = 0,
109 // BrowserThread::ID is associated with a BrowserThreadImpl instance but the
110 // underlying thread hasn't started yet.
111 INITIALIZED,
112 // BrowserThread::ID is associated to a TaskRunner and is accepting tasks.
113 RUNNING,
114 // BrowserThread::ID no longer accepts tasks.
115 SHUTDOWN
116 };
117
102 using BrowserThreadDelegateAtomicPtr = base::subtle::AtomicWord; 118 using BrowserThreadDelegateAtomicPtr = base::subtle::AtomicWord;
103 119
104 struct BrowserThreadGlobals { 120 struct BrowserThreadGlobals {
105 BrowserThreadGlobals() 121 BrowserThreadGlobals()
106 : blocking_pool( 122 : blocking_pool(
107 new base::SequencedWorkerPool(3, 123 new base::SequencedWorkerPool(3,
108 "BrowserBlocking", 124 "BrowserBlocking",
109 base::TaskPriority::USER_VISIBLE)) { 125 base::TaskPriority::USER_VISIBLE)) {}
110 memset(threads, 0, BrowserThread::ID_COUNT * sizeof(threads[0]));
111 memset(thread_ids, 0, BrowserThread::ID_COUNT * sizeof(thread_ids[0]));
112 }
113 126
114 // This lock protects |threads| and |thread_ids|. Do not read or modify those 127 // This lock protects |task_runners| and |states|. Do not read or modify those
115 // arrays without holding this lock. Do not block while holding this lock. 128 // arrays without holding this lock. Do not block while holding this lock.
116 base::Lock lock; 129 base::Lock lock;
117 130
118 // This array is protected by |lock|. IDs in this array are populated as soon 131 // This array is filled either as the underlying threads start and invoke
119 // as their respective thread is started and are never reset. 132 // Init() or in RedirectThreadIDToTaskRunner() for threads that are being
120 base::PlatformThreadId thread_ids[BrowserThread::ID_COUNT]; 133 // redirected. It is not emptied during shutdown in order to support
134 // RunsTasksOnCurrentThread() until the very end.
135 scoped_refptr<base::SingleThreadTaskRunner>
136 task_runners[BrowserThread::ID_COUNT];
121 137
122 // This array is protected by |lock|. The threads are not owned by this 138 // Holds the state of each BrowserThread::ID.
123 // array. Typically, the threads are owned on the UI thread by 139 BrowserThreadState states[BrowserThread::ID_COUNT] = {};
124 // BrowserMainLoop. BrowserThreadImpl objects remove themselves from this
125 // array upon destruction.
126 BrowserThreadImpl* threads[BrowserThread::ID_COUNT];
127 140
128 // Only atomic operations are used on this pointer. The delegate isn't owned 141 // Only atomic operations are used on this pointer. The delegate isn't owned
129 // by BrowserThreadGlobals, rather by whoever calls 142 // by BrowserThreadGlobals, rather by whoever calls
130 // BrowserThread::SetIOThreadDelegate. 143 // BrowserThread::SetIOThreadDelegate.
131 BrowserThreadDelegateAtomicPtr io_thread_delegate = 0; 144 BrowserThreadDelegateAtomicPtr io_thread_delegate = 0;
132 145
133 const scoped_refptr<base::SequencedWorkerPool> blocking_pool; 146 const scoped_refptr<base::SequencedWorkerPool> blocking_pool;
134 }; 147 };
135 148
136 base::LazyInstance<BrowserThreadGlobals>::Leaky 149 base::LazyInstance<BrowserThreadGlobals>::Leaky
137 g_globals = LAZY_INSTANCE_INITIALIZER; 150 g_globals = LAZY_INSTANCE_INITIALIZER;
138 151
139 } // namespace 152 } // namespace
140 153
141 BrowserThreadImpl::BrowserThreadImpl(ID identifier) 154 BrowserThreadImpl::BrowserThreadImpl(ID identifier)
142 : Thread(GetThreadName(identifier)), identifier_(identifier) { 155 : Thread(GetThreadName(identifier)), identifier_(identifier) {
143 Initialize(); 156 Initialize();
144
145 // Unit tests may create multiple TestBrowserThreadBundles, causing the same
146 // BrowserThread ID to be reinitialized. We explicitly clear the thread ID
147 // here so Start() can sanity check.
148 BrowserThreadGlobals& globals = g_globals.Get();
149 base::AutoLock lock(globals.lock);
150 globals.thread_ids[identifier] = base::kInvalidThreadId;
151 } 157 }
152 158
153 BrowserThreadImpl::BrowserThreadImpl(ID identifier, 159 BrowserThreadImpl::BrowserThreadImpl(ID identifier,
154 base::MessageLoop* message_loop) 160 base::MessageLoop* message_loop)
155 : Thread(GetThreadName(identifier)), identifier_(identifier) { 161 : Thread(GetThreadName(identifier)), identifier_(identifier) {
156 SetMessageLoop(message_loop); 162 SetMessageLoop(message_loop);
157 Initialize(); 163 Initialize();
158 164
159 // If constructed with an explicit message loop, this is a fake BrowserThread 165 // If constructed with an explicit message loop, this is a fake
160 // which runs on the current thread. 166 // BrowserThread which runs on the current thread.
161 BrowserThreadGlobals& globals = g_globals.Get(); 167 BrowserThreadGlobals& globals = g_globals.Get();
162 base::AutoLock lock(globals.lock); 168 base::AutoLock lock(globals.lock);
163 globals.thread_ids[identifier] = base::PlatformThread::CurrentId(); 169
170 DCHECK(!globals.task_runners[identifier_]);
171 globals.task_runners[identifier_] = task_runner();
172
173 DCHECK_EQ(globals.states[identifier_], BrowserThreadState::INITIALIZED);
174 globals.states[identifier_] = BrowserThreadState::RUNNING;
164 } 175 }
165 176
166 // static 177 // static
167 void BrowserThreadImpl::ShutdownThreadPool() { 178 void BrowserThreadImpl::ShutdownThreadPool() {
168 // The goal is to make it impossible for chrome to 'infinite loop' during 179 // The goal is to make it impossible for chrome to 'infinite loop' during
169 // shutdown, but to reasonably expect that all BLOCKING_SHUTDOWN tasks queued 180 // shutdown, but to reasonably expect that all BLOCKING_SHUTDOWN tasks queued
170 // during shutdown get run. There's nothing particularly scientific about the 181 // during shutdown get run. There's nothing particularly scientific about the
171 // number chosen. 182 // number chosen.
172 const int kMaxNewShutdownBlockingTasks = 1000; 183 const int kMaxNewShutdownBlockingTasks = 1000;
173 BrowserThreadGlobals& globals = g_globals.Get(); 184 BrowserThreadGlobals& globals = g_globals.Get();
174 globals.blocking_pool->Shutdown(kMaxNewShutdownBlockingTasks); 185 globals.blocking_pool->Shutdown(kMaxNewShutdownBlockingTasks);
175 } 186 }
176 187
177 // static 188 // static
178 void BrowserThreadImpl::FlushThreadPoolHelperForTesting() { 189 void BrowserThreadImpl::FlushThreadPoolHelperForTesting() {
179 // We don't want to create a pool if none exists. 190 // We don't want to create a pool if none exists.
180 if (g_globals == nullptr) 191 if (g_globals == nullptr)
181 return; 192 return;
182 g_globals.Get().blocking_pool->FlushForTesting(); 193 g_globals.Get().blocking_pool->FlushForTesting();
183 disk_cache::SimpleBackendImpl::FlushWorkerPoolForTesting(); 194 disk_cache::SimpleBackendImpl::FlushWorkerPoolForTesting();
184 } 195 }
185 196
186 void BrowserThreadImpl::Init() { 197 void BrowserThreadImpl::Init() {
187 BrowserThreadGlobals& globals = g_globals.Get(); 198 BrowserThreadGlobals& globals = g_globals.Get();
188 199
200 #if DCHECK_IS_ON()
201 {
202 base::AutoLock lock(globals.lock);
203 // |globals| should already have been initialized for |identifier_| in
204 // BrowserThreadImpl::StartWithOptions(). If this isn't the case it's likely
205 // because this BrowserThreadImpl's owner incorrectly used Thread::Start.*()
206 // instead of BrowserThreadImpl::Start.*().
207 DCHECK_EQ(globals.states[identifier_], BrowserThreadState::RUNNING);
208 DCHECK(globals.task_runners[identifier_]);
209 DCHECK(globals.task_runners[identifier_]->RunsTasksOnCurrentThread());
210 }
211 #endif // DCHECK_IS_ON()
212
189 if (identifier_ == BrowserThread::DB || 213 if (identifier_ == BrowserThread::DB ||
190 identifier_ == BrowserThread::FILE || 214 identifier_ == BrowserThread::FILE ||
191 identifier_ == BrowserThread::FILE_USER_BLOCKING || 215 identifier_ == BrowserThread::FILE_USER_BLOCKING ||
192 identifier_ == BrowserThread::PROCESS_LAUNCHER || 216 identifier_ == BrowserThread::PROCESS_LAUNCHER ||
193 identifier_ == BrowserThread::CACHE) { 217 identifier_ == BrowserThread::CACHE) {
194 base::MessageLoop* message_loop = base::MessageLoop::current(); 218 // Nesting and task observers are not allowed on redirected threads.
195 message_loop->DisallowNesting(); 219 message_loop()->DisallowNesting();
196 message_loop->DisallowTaskObservers(); 220 message_loop()->DisallowTaskObservers();
197 } 221 }
198 222
199 if (identifier_ == BrowserThread::IO) { 223 if (identifier_ == BrowserThread::IO) {
200 BrowserThreadDelegateAtomicPtr delegate = 224 BrowserThreadDelegateAtomicPtr delegate =
201 base::subtle::NoBarrier_Load(&globals.io_thread_delegate); 225 base::subtle::NoBarrier_Load(&globals.io_thread_delegate);
202 if (delegate) 226 if (delegate)
203 reinterpret_cast<BrowserThreadDelegate*>(delegate)->Init(); 227 reinterpret_cast<BrowserThreadDelegate*>(delegate)->Init();
204 } 228 }
205 } 229 }
206 230
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
298 void BrowserThreadImpl::CleanUp() { 322 void BrowserThreadImpl::CleanUp() {
299 BrowserThreadGlobals& globals = g_globals.Get(); 323 BrowserThreadGlobals& globals = g_globals.Get();
300 324
301 if (identifier_ == BrowserThread::IO) { 325 if (identifier_ == BrowserThread::IO) {
302 BrowserThreadDelegateAtomicPtr delegate = 326 BrowserThreadDelegateAtomicPtr delegate =
303 base::subtle::NoBarrier_Load(&globals.io_thread_delegate); 327 base::subtle::NoBarrier_Load(&globals.io_thread_delegate);
304 if (delegate) 328 if (delegate)
305 reinterpret_cast<BrowserThreadDelegate*>(delegate)->CleanUp(); 329 reinterpret_cast<BrowserThreadDelegate*>(delegate)->CleanUp();
306 } 330 }
307 331
308 // PostTaskHelper() accesses the message loop while holding this lock. 332 // Change the state to SHUTDOWN so that PostTaskHelper stops accepting tasks
309 // However, the message loop will soon be destructed without any locking. So 333 // for this thread. Do not clear globals.task_runners[identifier_] so that
310 // to prevent a race with accessing the message loop in PostTaskHelper(), 334 // BrowserThread::CurrentlyOn() works from the MessageLoop's
311 // remove this thread from the global array now. 335 // DestructionObservers.
312 base::AutoLock lock(globals.lock); 336 base::AutoLock lock(globals.lock);
313 globals.threads[identifier_] = nullptr; 337 DCHECK_EQ(globals.states[identifier_], BrowserThreadState::RUNNING);
338 globals.states[identifier_] = BrowserThreadState::SHUTDOWN;
314 } 339 }
315 340
316 void BrowserThreadImpl::Initialize() { 341 void BrowserThreadImpl::Initialize() {
317 BrowserThreadGlobals& globals = g_globals.Get(); 342 BrowserThreadGlobals& globals = g_globals.Get();
318 343
319 base::AutoLock lock(globals.lock); 344 base::AutoLock lock(globals.lock);
320 DCHECK_GE(identifier_, 0); 345 DCHECK_GE(identifier_, 0);
321 DCHECK_LT(identifier_, ID_COUNT); 346 DCHECK_LT(identifier_, ID_COUNT);
322 DCHECK_EQ(globals.threads[identifier_], nullptr); 347 DCHECK_EQ(globals.states[identifier_], BrowserThreadState::UNINITIALIZED);
323 globals.threads[identifier_] = this; 348 globals.states[identifier_] = BrowserThreadState::INITIALIZED;
349 }
350
351 // static
352 void BrowserThreadImpl::ResetGlobalsForTesting(BrowserThread::ID identifier) {
353 BrowserThreadGlobals& globals = g_globals.Get();
354
355 base::AutoLock lock(globals.lock);
356 DCHECK_EQ(globals.states[identifier], BrowserThreadState::SHUTDOWN);
357 globals.states[identifier] = BrowserThreadState::UNINITIALIZED;
358 globals.task_runners[identifier] = nullptr;
359 SetIOThreadDelegate(nullptr);
324 } 360 }
325 361
326 BrowserThreadImpl::~BrowserThreadImpl() { 362 BrowserThreadImpl::~BrowserThreadImpl() {
327 // All Thread subclasses must call Stop() in the destructor. This is 363 // All Thread subclasses must call Stop() in the destructor. This is
328 // doubly important here as various bits of code check they are on 364 // doubly important here as various bits of code check they are on
329 // the right BrowserThread. 365 // the right BrowserThread.
330 Stop(); 366 Stop();
331 367
332 BrowserThreadGlobals& globals = g_globals.Get(); 368 BrowserThreadGlobals& globals = g_globals.Get();
333 base::AutoLock lock(globals.lock); 369 base::AutoLock lock(globals.lock);
334 globals.threads[identifier_] = nullptr; 370 // This thread should have gone through Cleanup() as part of Stop() and be in
335 #ifndef NDEBUG 371 // the SHUTDOWN state already (unless it uses an externally provided
372 // MessageLoop instead of a real underlying thread and thus doesn't go through
373 // Cleanup()).
374 if (using_external_message_loop()) {
375 DCHECK_EQ(globals.states[identifier_], BrowserThreadState::RUNNING);
376 globals.states[identifier_] = BrowserThreadState::SHUTDOWN;
377 } else {
378 DCHECK_EQ(globals.states[identifier_], BrowserThreadState::SHUTDOWN);
379 }
380 #if DCHECK_IS_ON()
336 // Double check that the threads are ordered correctly in the enumeration. 381 // Double check that the threads are ordered correctly in the enumeration.
337 for (int i = identifier_ + 1; i < ID_COUNT; ++i) { 382 for (int i = identifier_ + 1; i < ID_COUNT; ++i) {
338 DCHECK(!globals.threads[i]) << 383 DCHECK(globals.states[i] == BrowserThreadState::SHUTDOWN ||
339 "Threads must be listed in the reverse order that they die"; 384 globals.states[i] == BrowserThreadState::UNINITIALIZED)
385 << "Threads must be listed in the reverse order that they die";
340 } 386 }
341 #endif 387 #endif
342 } 388 }
343 389
344 bool BrowserThreadImpl::Start() { 390 bool BrowserThreadImpl::Start() {
345 return StartWithOptions(base::Thread::Options()); 391 return StartWithOptions(base::Thread::Options());
346 } 392 }
347 393
348 bool BrowserThreadImpl::StartWithOptions(const Options& options) { 394 bool BrowserThreadImpl::StartWithOptions(const Options& options) {
349 // The global thread table needs to be locked while a new thread is
350 // starting, as the new thread can asynchronously start touching the
351 // table (and other thread's message_loop).
352 BrowserThreadGlobals& globals = g_globals.Get(); 395 BrowserThreadGlobals& globals = g_globals.Get();
396
397 // Holding the lock is necessary when kicking off the thread to ensure
398 // |states| and |task_runners| are updated before it gets to query them.
353 base::AutoLock lock(globals.lock); 399 base::AutoLock lock(globals.lock);
354 DCHECK_EQ(globals.thread_ids[identifier_], base::kInvalidThreadId); 400
355 bool result = Thread::StartWithOptions(options); 401 bool result = Thread::StartWithOptions(options);
356 globals.thread_ids[identifier_] = GetThreadId(); 402
403 // Although the thread is starting asynchronously, the MessageLoop is already
404 // ready to accept tasks and as such this BrowserThreadImpl is considered as
405 // "running".
406 DCHECK(!globals.task_runners[identifier_]);
407 globals.task_runners[identifier_] = task_runner();
408 DCHECK(globals.task_runners[identifier_]);
409
410 DCHECK_EQ(globals.states[identifier_], BrowserThreadState::INITIALIZED);
411 globals.states[identifier_] = BrowserThreadState::RUNNING;
412
357 return result; 413 return result;
358 } 414 }
359 415
360 bool BrowserThreadImpl::StartAndWaitForTesting() { 416 bool BrowserThreadImpl::StartAndWaitForTesting() {
361 if (!Start()) 417 if (!Start())
362 return false; 418 return false;
363 WaitUntilThreadStarted(); 419 WaitUntilThreadStarted();
364 return true; 420 return true;
365 } 421 }
422
423 // static
424 void BrowserThreadImpl::RedirectThreadIDToTaskRunner(
425 BrowserThread::ID identifier,
426 scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
427 DCHECK(task_runner);
428
429 BrowserThreadGlobals& globals = g_globals.Get();
430 base::AutoLock lock(globals.lock);
431
432 DCHECK(!globals.task_runners[identifier]);
433 DCHECK_EQ(globals.states[identifier], BrowserThreadState::UNINITIALIZED);
434
435 globals.task_runners[identifier] = std::move(task_runner);
436 globals.states[identifier] = BrowserThreadState::RUNNING;
437 }
438
439 // static
440 void BrowserThreadImpl::StopRedirectionOfThreadID(
441 BrowserThread::ID identifier) {
442 BrowserThreadGlobals& globals = g_globals.Get();
443 base::AutoLock auto_lock(globals.lock);
444
445 DCHECK(globals.task_runners[identifier]);
446
447 // Change the state to SHUTDOWN to stop accepting new tasks. Note: this is
448 // different from non-redirected threads which continue accepting tasks while
449 // being joined and only quit when idle. However, any tasks for which this
450 // difference matters was already racy as any thread posting a task after the
451 // Signal task below can't be synchronized with the joining thread. Therefore,
452 // that task could already come in before or after the join had completed in
453 // the non-redirection world. Entering SHUTDOWN early merely skews this race
454 // towards making it less likely such a task is accepted by the joined thread
455 // which is fine.
456 DCHECK_EQ(globals.states[identifier], BrowserThreadState::RUNNING);
457 globals.states[identifier] = BrowserThreadState::SHUTDOWN;
458
459 // Wait for all pending tasks to complete.
460 base::WaitableEvent flushed(base::WaitableEvent::ResetPolicy::MANUAL,
461 base::WaitableEvent::InitialState::NOT_SIGNALED);
462 globals.task_runners[identifier]->PostTask(
463 FROM_HERE,
464 base::Bind(&base::WaitableEvent::Signal, base::Unretained(&flushed)));
465 {
466 base::AutoUnlock auto_lock(globals.lock);
467 flushed.Wait();
468 }
469
470 // Only reset the task runner after running pending tasks so that
471 // BrowserThread::CurrentlyOn() works in their scope.
472 globals.task_runners[identifier] = nullptr;
473
474 // Note: it's still possible for tasks to be posted to that task runner after
475 // this point (e.g. through a previously obtained ThreadTaskRunnerHandle or by
476 // one of the last tasks re-posting to its ThreadTaskRunnerHandle) but the
477 // BrowserThread API itself won't accept tasks. Such tasks are ultimately
478 // guaranteed to run before TaskScheduler::Shutdown() returns but may break
479 // the assumption in PostTaskHelper that BrowserThread::ID A > B will always
480 // succeed to post to B. This is pretty much the only observable difference
481 // between a redirected thread and a real one and is one we're willing to live
482 // with for this experiment. TODO(gab): fix this before enabling the
483 // experiment by default on trunk, http://crbug.com/653916.
484 }
485
366 // static 486 // static
367 bool BrowserThreadImpl::PostTaskHelper( 487 bool BrowserThreadImpl::PostTaskHelper(
368 BrowserThread::ID identifier, 488 BrowserThread::ID identifier,
369 const tracked_objects::Location& from_here, 489 const tracked_objects::Location& from_here,
370 const base::Closure& task, 490 const base::Closure& task,
371 base::TimeDelta delay, 491 base::TimeDelta delay,
372 bool nestable) { 492 bool nestable) {
373 DCHECK_GE(identifier, 0); 493 DCHECK_GE(identifier, 0);
374 DCHECK_LT(identifier, ID_COUNT); 494 DCHECK_LT(identifier, ID_COUNT);
375 // Optimization: to avoid unnecessary locks, we listed the ID enumeration in 495 // Optimization: to avoid unnecessary locks, we listed the ID enumeration in
376 // order of lifetime. So no need to lock if we know that the target thread 496 // order of lifetime. So no need to lock if we know that the target thread
377 // outlives current thread. 497 // outlives current thread as that implies the current thread only ever sees
498 // the target thread in its RUNNING state.
378 // Note: since the array is so small, ok to loop instead of creating a map, 499 // Note: since the array is so small, ok to loop instead of creating a map,
379 // which would require a lock because std::map isn't thread safe, defeating 500 // which would require a lock because std::map isn't thread safe, defeating
380 // the whole purpose of this optimization. 501 // the whole purpose of this optimization.
381 BrowserThread::ID current_thread = ID_COUNT; 502 BrowserThread::ID current_thread = ID_COUNT;
382 bool target_thread_outlives_current = 503 bool target_thread_outlives_current =
383 GetCurrentThreadIdentifier(&current_thread) && 504 GetCurrentThreadIdentifier(&current_thread) &&
384 current_thread >= identifier; 505 current_thread >= identifier;
385 506
386 BrowserThreadGlobals& globals = g_globals.Get(); 507 BrowserThreadGlobals& globals = g_globals.Get();
387 if (!target_thread_outlives_current) 508 if (!target_thread_outlives_current)
388 globals.lock.Acquire(); 509 globals.lock.Acquire();
389 510
390 base::MessageLoop* message_loop = 511 const bool accepting_tasks =
391 globals.threads[identifier] ? globals.threads[identifier]->message_loop() 512 globals.states[identifier] == BrowserThreadState::RUNNING;
392 : nullptr; 513 if (accepting_tasks) {
393 if (message_loop) { 514 base::SingleThreadTaskRunner* task_runner =
515 globals.task_runners[identifier].get();
516 DCHECK(task_runner);
394 if (nestable) { 517 if (nestable) {
395 message_loop->task_runner()->PostDelayedTask(from_here, task, delay); 518 task_runner->PostDelayedTask(from_here, task, delay);
396 } else { 519 } else {
397 message_loop->task_runner()->PostNonNestableDelayedTask(from_here, task, 520 task_runner->PostNonNestableDelayedTask(from_here, task, delay);
398 delay);
399 } 521 }
400 } 522 }
401 523
402 if (!target_thread_outlives_current) 524 if (!target_thread_outlives_current)
403 globals.lock.Release(); 525 globals.lock.Release();
404 526
405 return !!message_loop; 527 return accepting_tasks;
406 } 528 }
407 529
408 // static 530 // static
409 bool BrowserThread::PostBlockingPoolTask( 531 bool BrowserThread::PostBlockingPoolTask(
410 const tracked_objects::Location& from_here, 532 const tracked_objects::Location& from_here,
411 const base::Closure& task) { 533 const base::Closure& task) {
412 return g_globals.Get().blocking_pool->PostWorkerTask(from_here, task); 534 return g_globals.Get().blocking_pool->PostWorkerTask(from_here, task);
413 } 535 }
414 536
415 // static 537 // static
(...skipping 30 matching lines...) Expand all
446 568
447 // static 569 // static
448 bool BrowserThread::IsThreadInitialized(ID identifier) { 570 bool BrowserThread::IsThreadInitialized(ID identifier) {
449 if (g_globals == nullptr) 571 if (g_globals == nullptr)
450 return false; 572 return false;
451 573
452 BrowserThreadGlobals& globals = g_globals.Get(); 574 BrowserThreadGlobals& globals = g_globals.Get();
453 base::AutoLock lock(globals.lock); 575 base::AutoLock lock(globals.lock);
454 DCHECK_GE(identifier, 0); 576 DCHECK_GE(identifier, 0);
455 DCHECK_LT(identifier, ID_COUNT); 577 DCHECK_LT(identifier, ID_COUNT);
456 return globals.threads[identifier] != nullptr; 578 return globals.states[identifier] == BrowserThreadState::INITIALIZED ||
579 globals.states[identifier] == BrowserThreadState::RUNNING;
457 } 580 }
458 581
459 // static 582 // static
460 bool BrowserThread::CurrentlyOn(ID identifier) { 583 bool BrowserThread::CurrentlyOn(ID identifier) {
461 BrowserThreadGlobals& globals = g_globals.Get(); 584 BrowserThreadGlobals& globals = g_globals.Get();
462 base::AutoLock lock(globals.lock); 585 base::AutoLock lock(globals.lock);
463 DCHECK_GE(identifier, 0); 586 DCHECK_GE(identifier, 0);
464 DCHECK_LT(identifier, ID_COUNT); 587 DCHECK_LT(identifier, ID_COUNT);
465 return base::PlatformThread::CurrentId() == globals.thread_ids[identifier]; 588 return globals.task_runners[identifier] &&
589 globals.task_runners[identifier]->RunsTasksOnCurrentThread();
466 } 590 }
467 591
468 // static 592 // static
469 std::string BrowserThread::GetDCheckCurrentlyOnErrorMessage(ID expected) { 593 std::string BrowserThread::GetDCheckCurrentlyOnErrorMessage(ID expected) {
470 std::string actual_name = base::PlatformThread::GetName(); 594 std::string actual_name = base::PlatformThread::GetName();
471 if (actual_name.empty()) 595 if (actual_name.empty())
472 actual_name = "Unknown Thread"; 596 actual_name = "Unknown Thread";
473 597
474 std::string result = "Must be called on "; 598 std::string result = "Must be called on ";
475 result += GetThreadName(expected); 599 result += GetThreadName(expected);
476 result += "; actually called on "; 600 result += "; actually called on ";
477 result += actual_name; 601 result += actual_name;
478 result += "."; 602 result += ".";
479 return result; 603 return result;
480 } 604 }
481 605
482 // static 606 // static
483 bool BrowserThread::IsMessageLoopValid(ID identifier) { 607 bool BrowserThread::IsMessageLoopValid(ID identifier) {
484 if (g_globals == nullptr) 608 if (g_globals == nullptr)
485 return false; 609 return false;
486 610
487 BrowserThreadGlobals& globals = g_globals.Get(); 611 BrowserThreadGlobals& globals = g_globals.Get();
488 base::AutoLock lock(globals.lock); 612 base::AutoLock lock(globals.lock);
489 DCHECK_GE(identifier, 0); 613 DCHECK_GE(identifier, 0);
490 DCHECK_LT(identifier, ID_COUNT); 614 DCHECK_LT(identifier, ID_COUNT);
491 return globals.threads[identifier] && 615 return globals.states[identifier] == BrowserThreadState::RUNNING;
492 globals.threads[identifier]->message_loop();
493 } 616 }
494 617
495 // static 618 // static
496 bool BrowserThread::PostTask(ID identifier, 619 bool BrowserThread::PostTask(ID identifier,
497 const tracked_objects::Location& from_here, 620 const tracked_objects::Location& from_here,
498 const base::Closure& task) { 621 const base::Closure& task) {
499 return BrowserThreadImpl::PostTaskHelper( 622 return BrowserThreadImpl::PostTaskHelper(
500 identifier, from_here, task, base::TimeDelta(), true); 623 identifier, from_here, task, base::TimeDelta(), true);
501 } 624 }
502 625
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
536 const base::Closure& reply) { 659 const base::Closure& reply) {
537 return GetTaskRunnerForThread(identifier) 660 return GetTaskRunnerForThread(identifier)
538 ->PostTaskAndReply(from_here, task, reply); 661 ->PostTaskAndReply(from_here, task, reply);
539 } 662 }
540 663
541 // static 664 // static
542 bool BrowserThread::GetCurrentThreadIdentifier(ID* identifier) { 665 bool BrowserThread::GetCurrentThreadIdentifier(ID* identifier) {
543 if (g_globals == nullptr) 666 if (g_globals == nullptr)
544 return false; 667 return false;
545 668
546 base::MessageLoop* cur_message_loop = base::MessageLoop::current();
547 BrowserThreadGlobals& globals = g_globals.Get(); 669 BrowserThreadGlobals& globals = g_globals.Get();
548 // Profiler to track potential contention on |globals.lock|. This only does 670 // Profiler to track potential contention on |globals.lock|. This only does
549 // real work on canary and local dev builds, so the cost of having this here 671 // real work on canary and local dev builds, so the cost of having this here
550 // should be minimal. 672 // should be minimal.
551 tracked_objects::ScopedTracker tracking_profile(FROM_HERE); 673 tracked_objects::ScopedTracker tracking_profile(FROM_HERE);
552 base::AutoLock lock(globals.lock); 674 base::AutoLock lock(globals.lock);
553 for (int i = 0; i < ID_COUNT; ++i) { 675 for (int i = 0; i < ID_COUNT; ++i) {
554 if (globals.threads[i] && 676 if (globals.task_runners[i] &&
555 globals.threads[i]->message_loop() == cur_message_loop) { 677 globals.task_runners[i]->RunsTasksOnCurrentThread()) {
556 *identifier = globals.threads[i]->identifier_; 678 *identifier = static_cast<ID>(i);
557 return true; 679 return true;
558 } 680 }
559 } 681 }
560 682
561 return false; 683 return false;
562 } 684 }
563 685
564 // static 686 // static
565 scoped_refptr<base::SingleThreadTaskRunner> 687 scoped_refptr<base::SingleThreadTaskRunner>
566 BrowserThread::GetTaskRunnerForThread(ID identifier) { 688 BrowserThread::GetTaskRunnerForThread(ID identifier) {
567 return g_task_runners.Get().proxies[identifier]; 689 return g_task_runners.Get().proxies[identifier];
568 } 690 }
569 691
570 // static 692 // static
571 void BrowserThread::SetIOThreadDelegate(BrowserThreadDelegate* delegate) { 693 void BrowserThread::SetIOThreadDelegate(BrowserThreadDelegate* delegate) {
572 BrowserThreadGlobals& globals = g_globals.Get(); 694 BrowserThreadGlobals& globals = g_globals.Get();
573 BrowserThreadDelegateAtomicPtr old_delegate = 695 BrowserThreadDelegateAtomicPtr old_delegate =
574 base::subtle::NoBarrier_AtomicExchange( 696 base::subtle::NoBarrier_AtomicExchange(
575 &globals.io_thread_delegate, 697 &globals.io_thread_delegate,
576 reinterpret_cast<BrowserThreadDelegateAtomicPtr>(delegate)); 698 reinterpret_cast<BrowserThreadDelegateAtomicPtr>(delegate));
577 699
578 // This catches registration when previously registered. 700 // This catches registration when previously registered.
579 DCHECK(!delegate || !old_delegate); 701 DCHECK(!delegate || !old_delegate);
580 } 702 }
581 703
582 } // namespace content 704 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/browser_thread_impl.h ('k') | content/public/browser/content_browser_client.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698