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

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: rm TODO 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
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/task_scheduler/task_scheduler.h"
fdoray 2016/12/01 15:15:21 Not needed.
gab 2016/12/07 19:15:27 Done.
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 but the underlying thread hasn't run yet.
fdoray 2016/12/01 15:15:22 The INITIALIZED state is useless. See comment in B
gab 2016/12/07 19:15:27 It is useful, replied there.
110 INITIALIZED,
111 // BrowserThread::ID is associated to a live thread.
fdoray 2016/12/01 15:15:22 ... is associated to TaskRunner and is accepting t
gab 2016/12/07 19:15:27 Done.
112 RUNNING,
113 // BrowserThread::ID is associated to a thread having been or being shutdown.
fdoray 2016/12/01 15:15:21 ... no longer accepts tasks. If it was backed by a
gab 2016/12/07 19:15:27 Done (without second sentence).
114 SHUTDOWN
115 };
116
102 struct BrowserThreadGlobals { 117 struct BrowserThreadGlobals {
103 BrowserThreadGlobals() 118 BrowserThreadGlobals()
104 : blocking_pool( 119 : blocking_pool(
105 new base::SequencedWorkerPool(3, 120 new base::SequencedWorkerPool(3,
106 "BrowserBlocking", 121 "BrowserBlocking",
107 base::TaskPriority::USER_VISIBLE)) { 122 base::TaskPriority::USER_VISIBLE)) {}
108 memset(threads, 0, BrowserThread::ID_COUNT * sizeof(threads[0]));
109 memset(thread_ids, 0, BrowserThread::ID_COUNT * sizeof(thread_ids[0]));
110 memset(thread_delegates, 0,
111 BrowserThread::ID_COUNT * sizeof(thread_delegates[0]));
112 }
113 123
114 // This lock protects |threads| and |thread_ids|. Do not read or modify those 124 // 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. 125 // arrays without holding this lock. Do not block while holding this lock.
116 base::Lock lock; 126 base::Lock lock;
117 127
118 // This array is protected by |lock|. IDs in this array are populated as soon 128 // This array is filled either as the underlying threads start and invoke
119 // as their respective thread is started and are never reset. 129 // Init() or in RedirectThreadIDToTaskRunner() for threads that are being
120 base::PlatformThreadId thread_ids[BrowserThread::ID_COUNT]; 130 // redirected. It is not emptied during shutdown in order to support
131 // RunsTasksOnCurrentThread() until the very end.
132 scoped_refptr<base::SingleThreadTaskRunner>
133 task_runners[BrowserThread::ID_COUNT];
121 134
122 // This array is protected by |lock|. The threads are not owned by this 135 // Holds the state of each BrowserThread::ID. This needs to be a separate bit
123 // array. Typically, the threads are owned on the UI thread by 136 // because |threads| isn't a good signal per redirected IDs remaining null and
fdoray 2016/12/01 15:15:22 |threads| doesn't exist
gab 2016/12/07 19:15:27 Done.
124 // BrowserMainLoop. BrowserThreadImpl objects remove themselves from this 137 // |task_runners| isn't either per not being cleaned up on shutdown.
125 // array upon destruction. 138 BrowserThreadState states[BrowserThread::ID_COUNT] = {};
126 BrowserThreadImpl* threads[BrowserThread::ID_COUNT];
127 139
128 // Only atomic operations are used on this array. The delegates are not owned 140 // Only atomic operations are used on this array. The delegates are not owned
129 // by this array, rather by whoever calls BrowserThread::SetDelegate. 141 // by this array, rather by whoever calls BrowserThread::SetDelegate.
130 BrowserThreadDelegate* thread_delegates[BrowserThread::ID_COUNT]; 142 BrowserThreadDelegate* thread_delegates[BrowserThread::ID_COUNT] = {};
131 143
132 const scoped_refptr<base::SequencedWorkerPool> blocking_pool; 144 const scoped_refptr<base::SequencedWorkerPool> blocking_pool;
133 }; 145 };
134 146
135 base::LazyInstance<BrowserThreadGlobals>::Leaky 147 base::LazyInstance<BrowserThreadGlobals>::Leaky
136 g_globals = LAZY_INSTANCE_INITIALIZER; 148 g_globals = LAZY_INSTANCE_INITIALIZER;
137 149
138 } // namespace 150 } // namespace
139 151
140 BrowserThreadImpl::BrowserThreadImpl(ID identifier) 152 BrowserThreadImpl::BrowserThreadImpl(ID identifier)
141 : Thread(GetThreadName(identifier)), identifier_(identifier) { 153 : Thread(GetThreadName(identifier)), identifier_(identifier) {
142 Initialize(); 154 Initialize();
143
144 // Unit tests may create multiple TestBrowserThreadBundles, causing the same
145 // BrowserThread ID to be reinitialized. We explicitly clear the thread ID
146 // here so Start() can sanity check.
147 BrowserThreadGlobals& globals = g_globals.Get();
148 base::AutoLock lock(globals.lock);
149 globals.thread_ids[identifier] = base::kInvalidThreadId;
150 } 155 }
151 156
152 BrowserThreadImpl::BrowserThreadImpl(ID identifier, 157 BrowserThreadImpl::BrowserThreadImpl(ID identifier,
153 base::MessageLoop* message_loop) 158 base::MessageLoop* message_loop)
154 : Thread(GetThreadName(identifier)), identifier_(identifier) { 159 : Thread(GetThreadName(identifier)), identifier_(identifier) {
155 SetMessageLoop(message_loop); 160 SetMessageLoop(message_loop);
156 Initialize(); 161 Initialize();
157 162
158 // If constructed with an explicit message loop, this is a fake BrowserThread 163 // If constructed with an explicit message loop, this is a fake
159 // which runs on the current thread. 164 // BrowserThread which runs on the current thread.
160 BrowserThreadGlobals& globals = g_globals.Get(); 165 BrowserThreadGlobals& globals = g_globals.Get();
161 base::AutoLock lock(globals.lock); 166 base::AutoLock lock(globals.lock);
162 globals.thread_ids[identifier] = base::PlatformThread::CurrentId(); 167
168 DCHECK(!globals.task_runners[identifier_]);
169 globals.task_runners[identifier_] = task_runner();
170
171 DCHECK_EQ(globals.states[identifier_], BrowserThreadState::INITIALIZED);
172 globals.states[identifier_] = BrowserThreadState::RUNNING;
163 } 173 }
164 174
165 // static 175 // static
166 void BrowserThreadImpl::ShutdownThreadPool() { 176 void BrowserThreadImpl::ShutdownThreadPool() {
167 // The goal is to make it impossible for chrome to 'infinite loop' during 177 // The goal is to make it impossible for chrome to 'infinite loop' during
168 // shutdown, but to reasonably expect that all BLOCKING_SHUTDOWN tasks queued 178 // shutdown, but to reasonably expect that all BLOCKING_SHUTDOWN tasks queued
169 // during shutdown get run. There's nothing particularly scientific about the 179 // during shutdown get run. There's nothing particularly scientific about the
170 // number chosen. 180 // number chosen.
171 const int kMaxNewShutdownBlockingTasks = 1000; 181 const int kMaxNewShutdownBlockingTasks = 1000;
172 BrowserThreadGlobals& globals = g_globals.Get(); 182 BrowserThreadGlobals& globals = g_globals.Get();
173 globals.blocking_pool->Shutdown(kMaxNewShutdownBlockingTasks); 183 globals.blocking_pool->Shutdown(kMaxNewShutdownBlockingTasks);
174 } 184 }
175 185
176 // static 186 // static
177 void BrowserThreadImpl::FlushThreadPoolHelperForTesting() { 187 void BrowserThreadImpl::FlushThreadPoolHelperForTesting() {
178 // We don't want to create a pool if none exists. 188 // We don't want to create a pool if none exists.
179 if (g_globals == nullptr) 189 if (g_globals == nullptr)
180 return; 190 return;
181 g_globals.Get().blocking_pool->FlushForTesting(); 191 g_globals.Get().blocking_pool->FlushForTesting();
182 disk_cache::SimpleBackendImpl::FlushWorkerPoolForTesting(); 192 disk_cache::SimpleBackendImpl::FlushWorkerPoolForTesting();
183 } 193 }
184 194
185 void BrowserThreadImpl::Init() { 195 void BrowserThreadImpl::Init() {
186 BrowserThreadGlobals& globals = g_globals.Get(); 196 BrowserThreadGlobals& globals = g_globals.Get();
187 197
198 // |globals| should already have been initialized for |identifier_| in
199 // BrowserThreadImpl::StartWithOptions(). If this isn't the case it's likely
200 // because this BrowserThreadImpl's owner incorrectly used Thread::Start.*()
201 // instead of BrowserThreadImpl::Start.*().
202 DCHECK(globals.task_runners[identifier_]);
203 DCHECK(globals.task_runners[identifier_]->RunsTasksOnCurrentThread());
204 DCHECK_EQ(globals.states[identifier_], BrowserThreadState::RUNNING);
205
188 if (BrowserThread::CurrentlyOn(BrowserThread::DB) || 206 if (BrowserThread::CurrentlyOn(BrowserThread::DB) ||
189 BrowserThread::CurrentlyOn(BrowserThread::FILE) || 207 BrowserThread::CurrentlyOn(BrowserThread::FILE) ||
190 BrowserThread::CurrentlyOn(BrowserThread::FILE_USER_BLOCKING) || 208 BrowserThread::CurrentlyOn(BrowserThread::FILE_USER_BLOCKING) ||
191 BrowserThread::CurrentlyOn(BrowserThread::PROCESS_LAUNCHER) || 209 BrowserThread::CurrentlyOn(BrowserThread::PROCESS_LAUNCHER) ||
192 BrowserThread::CurrentlyOn(BrowserThread::CACHE)) { 210 BrowserThread::CurrentlyOn(BrowserThread::CACHE)) {
193 base::MessageLoop* message_loop = base::MessageLoop::current(); 211 // Nesting and task observers are not allowed on redirected threads.
194 message_loop->DisallowNesting(); 212 message_loop()->DisallowNesting();
195 message_loop->DisallowTaskObservers(); 213 message_loop()->DisallowTaskObservers();
196 } 214 }
197 215
198 using base::subtle::AtomicWord; 216 using base::subtle::AtomicWord;
199 AtomicWord* storage = 217 AtomicWord* storage =
200 reinterpret_cast<AtomicWord*>(&globals.thread_delegates[identifier_]); 218 reinterpret_cast<AtomicWord*>(&globals.thread_delegates[identifier_]);
201 AtomicWord stored_pointer = base::subtle::NoBarrier_Load(storage); 219 AtomicWord stored_pointer = base::subtle::NoBarrier_Load(storage);
202 BrowserThreadDelegate* delegate = 220 BrowserThreadDelegate* delegate =
203 reinterpret_cast<BrowserThreadDelegate*>(stored_pointer); 221 reinterpret_cast<BrowserThreadDelegate*>(stored_pointer);
204 if (delegate) 222 if (delegate)
205 delegate->Init(); 223 delegate->Init();
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
302 using base::subtle::AtomicWord; 320 using base::subtle::AtomicWord;
303 AtomicWord* storage = 321 AtomicWord* storage =
304 reinterpret_cast<AtomicWord*>(&globals.thread_delegates[identifier_]); 322 reinterpret_cast<AtomicWord*>(&globals.thread_delegates[identifier_]);
305 AtomicWord stored_pointer = base::subtle::NoBarrier_Load(storage); 323 AtomicWord stored_pointer = base::subtle::NoBarrier_Load(storage);
306 BrowserThreadDelegate* delegate = 324 BrowserThreadDelegate* delegate =
307 reinterpret_cast<BrowserThreadDelegate*>(stored_pointer); 325 reinterpret_cast<BrowserThreadDelegate*>(stored_pointer);
308 326
309 if (delegate) 327 if (delegate)
310 delegate->CleanUp(); 328 delegate->CleanUp();
311 329
312 // PostTaskHelper() accesses the message loop while holding this lock. 330 // PostTaskHelper() accesses the message loop while holding this lock.
fdoray 2016/12/01 15:15:22 PostTaskHelper() no longer accesses a MessageLoop.
gab 2016/12/07 19:15:27 Done (slightly reworded).
313 // However, the message loop will soon be destructed without any locking. So 331 // However, the message loop will soon be destructed without any locking. So
314 // to prevent a race with accessing the message loop in PostTaskHelper(), 332 // to prevent a race with accessing the message loop in PostTaskHelper(),
315 // remove this thread from the global array now. 333 // remove this thread from the global array now.
316 base::AutoLock lock(globals.lock); 334 base::AutoLock lock(globals.lock);
317 globals.threads[identifier_] = nullptr; 335 DCHECK_EQ(globals.states[identifier_], BrowserThreadState::RUNNING);
336 globals.states[identifier_] = BrowserThreadState::SHUTDOWN;
318 } 337 }
319 338
320 void BrowserThreadImpl::Initialize() { 339 void BrowserThreadImpl::Initialize() {
321 BrowserThreadGlobals& globals = g_globals.Get(); 340 BrowserThreadGlobals& globals = g_globals.Get();
322 341
323 base::AutoLock lock(globals.lock); 342 base::AutoLock lock(globals.lock);
324 DCHECK_GE(identifier_, 0); 343 DCHECK_GE(identifier_, 0);
325 DCHECK_LT(identifier_, ID_COUNT); 344 DCHECK_LT(identifier_, ID_COUNT);
326 DCHECK_EQ(globals.threads[identifier_], nullptr); 345 DCHECK_EQ(globals.states[identifier_], BrowserThreadState::UNINITIALIZED);
327 globals.threads[identifier_] = this; 346 globals.states[identifier_] = BrowserThreadState::INITIALIZED;
fdoray 2016/12/01 15:15:21 You can get rid of the INITIALIZED state. Initiali
gab 2016/12/07 19:15:27 No, INITIALIZED is required to support BrowserThre
347 }
348
349 // static
350 void BrowserThreadImpl::ResetGlobalsForTesting(BrowserThread::ID identifier) {
351 BrowserThreadGlobals& globals = g_globals.Get();
352
353 base::AutoLock lock(globals.lock);
354 DCHECK_EQ(globals.states[identifier], BrowserThreadState::SHUTDOWN);
355 globals.states[identifier] = BrowserThreadState::UNINITIALIZED;
356 globals.task_runners[identifier] = nullptr;
357 SetDelegate(identifier, nullptr);
328 } 358 }
329 359
330 BrowserThreadImpl::~BrowserThreadImpl() { 360 BrowserThreadImpl::~BrowserThreadImpl() {
331 // All Thread subclasses must call Stop() in the destructor. This is 361 // All Thread subclasses must call Stop() in the destructor. This is
332 // doubly important here as various bits of code check they are on 362 // doubly important here as various bits of code check they are on
333 // the right BrowserThread. 363 // the right BrowserThread.
334 Stop(); 364 Stop();
335 365
336 BrowserThreadGlobals& globals = g_globals.Get(); 366 BrowserThreadGlobals& globals = g_globals.Get();
337 base::AutoLock lock(globals.lock); 367 base::AutoLock lock(globals.lock);
338 globals.threads[identifier_] = nullptr; 368 // This thread should have gone through Cleanup() as part of Stop() and be in
339 #ifndef NDEBUG 369 // the SHUTDOWN state already (unless it uses an externally provided
370 // MessageLoop instead of a real underlying thread and thus doesn't go through
371 // Cleanup()).
372 if (using_external_message_loop()) {
373 DCHECK_EQ(globals.states[identifier_], BrowserThreadState::RUNNING);
374 globals.states[identifier_] = BrowserThreadState::SHUTDOWN;
375 } else {
376 DCHECK_EQ(globals.states[identifier_], BrowserThreadState::SHUTDOWN);
377 }
378 #if DCHECK_IS_ON()
340 // Double check that the threads are ordered correctly in the enumeration. 379 // Double check that the threads are ordered correctly in the enumeration.
341 for (int i = identifier_ + 1; i < ID_COUNT; ++i) { 380 for (int i = identifier_ + 1; i < ID_COUNT; ++i) {
342 DCHECK(!globals.threads[i]) << 381 DCHECK(globals.states[i] == BrowserThreadState::SHUTDOWN ||
343 "Threads must be listed in the reverse order that they die"; 382 globals.states[i] == BrowserThreadState::UNINITIALIZED)
383 << "Threads must be listed in the reverse order that they die";
344 } 384 }
345 #endif 385 #endif
346 } 386 }
347 387
348 bool BrowserThreadImpl::Start() { 388 bool BrowserThreadImpl::Start() {
349 return StartWithOptions(base::Thread::Options()); 389 return StartWithOptions(base::Thread::Options());
350 } 390 }
351 391
352 bool BrowserThreadImpl::StartWithOptions(const Options& options) { 392 bool BrowserThreadImpl::StartWithOptions(const Options& options) {
353 // The global thread table needs to be locked while a new thread is 393 // The lock doesn't need to be held to start the thread. The thread will
354 // starting, as the new thread can asynchronously start touching the 394 // start asynchronously and eventually invoke BrowserThreadImpl::Init()
355 // table (and other thread's message_loop). 395 // to complete initialization.
396 bool result = Thread::StartWithOptions(options);
397
356 BrowserThreadGlobals& globals = g_globals.Get(); 398 BrowserThreadGlobals& globals = g_globals.Get();
357 base::AutoLock lock(globals.lock); 399 base::AutoLock lock(globals.lock);
358 DCHECK_EQ(globals.thread_ids[identifier_], base::kInvalidThreadId); 400
359 bool result = Thread::StartWithOptions(options); 401 // Although the the thread is starting asynchronously. The MessageLoop is
360 globals.thread_ids[identifier_] = GetThreadId(); 402 // already ready to accept tasks and as such this BrowserThreadImpl is
403 // considered as "running".
404 DCHECK(!globals.task_runners[identifier_]);
405 globals.task_runners[identifier_] = task_runner();
406 DCHECK(globals.task_runners[identifier_]);
407
408 DCHECK_EQ(globals.states[identifier_], BrowserThreadState::INITIALIZED);
409 globals.states[identifier_] = BrowserThreadState::RUNNING;
410
361 return result; 411 return result;
362 } 412 }
363 413
364 bool BrowserThreadImpl::StartAndWaitForTesting() { 414 bool BrowserThreadImpl::StartAndWaitForTesting() {
365 if (!Start()) 415 if (!Start())
366 return false; 416 return false;
367 WaitUntilThreadStarted(); 417 WaitUntilThreadStarted();
368 return true; 418 return true;
369 } 419 }
420
421 // static
422 void BrowserThreadImpl::RedirectThreadIDToTaskRunner(
423 BrowserThread::ID identifier,
424 scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
425 BrowserThreadGlobals& globals = g_globals.Get();
426 base::AutoLock lock(globals.lock);
427 if (task_runner) {
428 DCHECK(!globals.task_runners[identifier]);
429 DCHECK_EQ(globals.states[identifier], BrowserThreadState::UNINITIALIZED);
430
431 globals.task_runners[identifier] = std::move(task_runner);
432 globals.states[identifier] = BrowserThreadState::RUNNING;
433 } else {
434 // Cancelling redirection should only be done on previously redirected
435 // threads.
fdoray 2016/12/01 15:15:22 Add: // Change the state to SHUTDOWN so that Post
gab 2016/12/07 19:15:27 Detailed comments added to BrowserThreadImpl::Stop
436 DCHECK_EQ(globals.states[identifier], BrowserThreadState::RUNNING);
437 globals.states[identifier] = BrowserThreadState::SHUTDOWN;
438 }
439 }
440
370 // static 441 // static
371 bool BrowserThreadImpl::PostTaskHelper( 442 bool BrowserThreadImpl::PostTaskHelper(
372 BrowserThread::ID identifier, 443 BrowserThread::ID identifier,
373 const tracked_objects::Location& from_here, 444 const tracked_objects::Location& from_here,
374 const base::Closure& task, 445 const base::Closure& task,
375 base::TimeDelta delay, 446 base::TimeDelta delay,
376 bool nestable) { 447 bool nestable) {
377 DCHECK_GE(identifier, 0); 448 DCHECK_GE(identifier, 0);
378 DCHECK_LT(identifier, ID_COUNT); 449 DCHECK_LT(identifier, ID_COUNT);
379 // Optimization: to avoid unnecessary locks, we listed the ID enumeration in 450 // Optimization: to avoid unnecessary locks, we listed the ID enumeration in
380 // order of lifetime. So no need to lock if we know that the target thread 451 // order of lifetime. So no need to lock if we know that the target thread
381 // outlives current thread. 452 // outlives current thread.
382 // Note: since the array is so small, ok to loop instead of creating a map, 453 // Note: since the array is so small, ok to loop instead of creating a map,
383 // which would require a lock because std::map isn't thread safe, defeating 454 // which would require a lock because std::map isn't thread safe, defeating
384 // the whole purpose of this optimization. 455 // the whole purpose of this optimization.
385 BrowserThread::ID current_thread = ID_COUNT; 456 BrowserThread::ID current_thread = ID_COUNT;
386 bool target_thread_outlives_current = 457 bool target_thread_outlives_current =
387 GetCurrentThreadIdentifier(&current_thread) && 458 GetCurrentThreadIdentifier(&current_thread) &&
388 current_thread >= identifier; 459 current_thread >= identifier;
389 460
390 BrowserThreadGlobals& globals = g_globals.Get(); 461 BrowserThreadGlobals& globals = g_globals.Get();
391 if (!target_thread_outlives_current) 462 if (!target_thread_outlives_current)
392 globals.lock.Acquire(); 463 globals.lock.Acquire();
393 464
394 base::MessageLoop* message_loop = 465 const bool accepting_tasks =
395 globals.threads[identifier] ? globals.threads[identifier]->message_loop() 466 globals.states[identifier] == BrowserThreadState::RUNNING;
396 : nullptr; 467 if (accepting_tasks) {
397 if (message_loop) { 468 base::SingleThreadTaskRunner* task_runner =
469 globals.task_runners[identifier].get();
470 DCHECK(task_runner);
398 if (nestable) { 471 if (nestable) {
399 message_loop->task_runner()->PostDelayedTask(from_here, task, delay); 472 task_runner->PostDelayedTask(from_here, task, delay);
400 } else { 473 } else {
401 message_loop->task_runner()->PostNonNestableDelayedTask(from_here, task, 474 task_runner->PostNonNestableDelayedTask(from_here, task, delay);
402 delay);
403 } 475 }
404 } 476 }
405 477
406 if (!target_thread_outlives_current) 478 if (!target_thread_outlives_current)
407 globals.lock.Release(); 479 globals.lock.Release();
408 480
409 return !!message_loop; 481 return accepting_tasks;
410 } 482 }
411 483
412 // static 484 // static
413 bool BrowserThread::PostBlockingPoolTask( 485 bool BrowserThread::PostBlockingPoolTask(
414 const tracked_objects::Location& from_here, 486 const tracked_objects::Location& from_here,
415 const base::Closure& task) { 487 const base::Closure& task) {
416 return g_globals.Get().blocking_pool->PostWorkerTask(from_here, task); 488 return g_globals.Get().blocking_pool->PostWorkerTask(from_here, task);
417 } 489 }
418 490
419 // static 491 // static
(...skipping 30 matching lines...) Expand all
450 522
451 // static 523 // static
452 bool BrowserThread::IsThreadInitialized(ID identifier) { 524 bool BrowserThread::IsThreadInitialized(ID identifier) {
453 if (g_globals == nullptr) 525 if (g_globals == nullptr)
454 return false; 526 return false;
455 527
456 BrowserThreadGlobals& globals = g_globals.Get(); 528 BrowserThreadGlobals& globals = g_globals.Get();
457 base::AutoLock lock(globals.lock); 529 base::AutoLock lock(globals.lock);
458 DCHECK_GE(identifier, 0); 530 DCHECK_GE(identifier, 0);
459 DCHECK_LT(identifier, ID_COUNT); 531 DCHECK_LT(identifier, ID_COUNT);
460 return globals.threads[identifier] != nullptr; 532 return globals.states[identifier] == BrowserThreadState::INITIALIZED ||
533 globals.states[identifier] == BrowserThreadState::RUNNING;
461 } 534 }
462 535
463 // static 536 // static
464 bool BrowserThread::CurrentlyOn(ID identifier) { 537 bool BrowserThread::CurrentlyOn(ID identifier) {
465 BrowserThreadGlobals& globals = g_globals.Get(); 538 BrowserThreadGlobals& globals = g_globals.Get();
466 base::AutoLock lock(globals.lock); 539 base::AutoLock lock(globals.lock);
467 DCHECK_GE(identifier, 0); 540 DCHECK_GE(identifier, 0);
468 DCHECK_LT(identifier, ID_COUNT); 541 DCHECK_LT(identifier, ID_COUNT);
469 return base::PlatformThread::CurrentId() == globals.thread_ids[identifier]; 542 return globals.task_runners[identifier] &&
543 globals.task_runners[identifier]->RunsTasksOnCurrentThread();
470 } 544 }
471 545
472 // static 546 // static
473 std::string BrowserThread::GetDCheckCurrentlyOnErrorMessage(ID expected) { 547 std::string BrowserThread::GetDCheckCurrentlyOnErrorMessage(ID expected) {
474 std::string actual_name = base::PlatformThread::GetName(); 548 std::string actual_name = base::PlatformThread::GetName();
475 if (actual_name.empty()) 549 if (actual_name.empty())
476 actual_name = "Unknown Thread"; 550 actual_name = "Unknown Thread";
477 551
478 std::string result = "Must be called on "; 552 std::string result = "Must be called on ";
479 result += GetThreadName(expected); 553 result += GetThreadName(expected);
480 result += "; actually called on "; 554 result += "; actually called on ";
481 result += actual_name; 555 result += actual_name;
482 result += "."; 556 result += ".";
483 return result; 557 return result;
484 } 558 }
485 559
486 // static 560 // static
487 bool BrowserThread::IsMessageLoopValid(ID identifier) { 561 bool BrowserThread::IsMessageLoopValid(ID identifier) {
488 if (g_globals == nullptr) 562 if (g_globals == nullptr)
489 return false; 563 return false;
490 564
491 BrowserThreadGlobals& globals = g_globals.Get(); 565 BrowserThreadGlobals& globals = g_globals.Get();
492 base::AutoLock lock(globals.lock); 566 base::AutoLock lock(globals.lock);
493 DCHECK_GE(identifier, 0); 567 DCHECK_GE(identifier, 0);
494 DCHECK_LT(identifier, ID_COUNT); 568 DCHECK_LT(identifier, ID_COUNT);
495 return globals.threads[identifier] && 569 return globals.states[identifier] == BrowserThreadState::RUNNING;
496 globals.threads[identifier]->message_loop();
497 } 570 }
498 571
499 // static 572 // static
500 bool BrowserThread::PostTask(ID identifier, 573 bool BrowserThread::PostTask(ID identifier,
501 const tracked_objects::Location& from_here, 574 const tracked_objects::Location& from_here,
502 const base::Closure& task) { 575 const base::Closure& task) {
503 return BrowserThreadImpl::PostTaskHelper( 576 return BrowserThreadImpl::PostTaskHelper(
504 identifier, from_here, task, base::TimeDelta(), true); 577 identifier, from_here, task, base::TimeDelta(), true);
505 } 578 }
506 579
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
540 const base::Closure& reply) { 613 const base::Closure& reply) {
541 return GetTaskRunnerForThread(identifier) 614 return GetTaskRunnerForThread(identifier)
542 ->PostTaskAndReply(from_here, task, reply); 615 ->PostTaskAndReply(from_here, task, reply);
543 } 616 }
544 617
545 // static 618 // static
546 bool BrowserThread::GetCurrentThreadIdentifier(ID* identifier) { 619 bool BrowserThread::GetCurrentThreadIdentifier(ID* identifier) {
547 if (g_globals == nullptr) 620 if (g_globals == nullptr)
548 return false; 621 return false;
549 622
550 base::MessageLoop* cur_message_loop = base::MessageLoop::current();
551 BrowserThreadGlobals& globals = g_globals.Get(); 623 BrowserThreadGlobals& globals = g_globals.Get();
552 // Profiler to track potential contention on |globals.lock|. This only does 624 // Profiler to track potential contention on |globals.lock|. This only does
553 // real work on canary and local dev builds, so the cost of having this here 625 // real work on canary and local dev builds, so the cost of having this here
554 // should be minimal. 626 // should be minimal.
555 tracked_objects::ScopedTracker tracking_profile(FROM_HERE); 627 tracked_objects::ScopedTracker tracking_profile(FROM_HERE);
556 base::AutoLock lock(globals.lock); 628 base::AutoLock lock(globals.lock);
557 for (int i = 0; i < ID_COUNT; ++i) { 629 for (int i = 0; i < ID_COUNT; ++i) {
558 if (globals.threads[i] && 630 if (globals.task_runners[i] &&
559 globals.threads[i]->message_loop() == cur_message_loop) { 631 globals.task_runners[i]->RunsTasksOnCurrentThread()) {
560 *identifier = globals.threads[i]->identifier_; 632 *identifier = static_cast<ID>(i);
561 return true; 633 return true;
562 } 634 }
563 } 635 }
564 636
565 return false; 637 return false;
566 } 638 }
567 639
568 // static 640 // static
569 scoped_refptr<base::SingleThreadTaskRunner> 641 scoped_refptr<base::SingleThreadTaskRunner>
570 BrowserThread::GetTaskRunnerForThread(ID identifier) { 642 BrowserThread::GetTaskRunnerForThread(ID identifier) {
571 return g_task_runners.Get().proxies[identifier]; 643 return g_task_runners.Get().proxies[identifier];
572 } 644 }
573 645
646 // static
574 void BrowserThread::SetDelegate(ID identifier, 647 void BrowserThread::SetDelegate(ID identifier,
fdoray 2016/12/01 15:15:22 I would change this to SetIOThreadDelegate() and c
gab 2016/12/07 19:15:27 Good call, will do in precursor CL.
gab 2016/12/08 18:49:41 Done in http://crrev.com/437271 :)
575 BrowserThreadDelegate* delegate) { 648 BrowserThreadDelegate* delegate) {
576 using base::subtle::AtomicWord; 649 using base::subtle::AtomicWord;
577 BrowserThreadGlobals& globals = g_globals.Get(); 650 BrowserThreadGlobals& globals = g_globals.Get();
578 AtomicWord* storage = reinterpret_cast<AtomicWord*>( 651 AtomicWord* storage = reinterpret_cast<AtomicWord*>(
579 &globals.thread_delegates[identifier]); 652 &globals.thread_delegates[identifier]);
580 AtomicWord old_pointer = base::subtle::NoBarrier_AtomicExchange( 653 AtomicWord old_pointer = base::subtle::NoBarrier_AtomicExchange(
581 storage, reinterpret_cast<AtomicWord>(delegate)); 654 storage, reinterpret_cast<AtomicWord>(delegate));
582 655
583 // This catches registration when previously registered. 656 // This catches registration when previously registered.
584 DCHECK(!delegate || !old_pointer); 657 DCHECK(!delegate || !old_pointer);
585 } 658 }
586 659
587 } // namespace content 660 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698