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

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: Rely on Thread::using_external_message_loop_ instead of hard-coding BrowserThread::UI Created 4 years, 1 month 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> 7 #include <string.h>
8 8
9 #include <string> 9 #include <string>
10 10
11 #include "base/atomicops.h" 11 #include "base/atomicops.h"
12 #include "base/bind.h" 12 #include "base/bind.h"
13 #include "base/compiler_specific.h" 13 #include "base/compiler_specific.h"
14 #include "base/lazy_instance.h" 14 #include "base/lazy_instance.h"
15 #include "base/logging.h"
15 #include "base/macros.h" 16 #include "base/macros.h"
17 #include "base/message_loop/message_loop.h"
16 #include "base/profiler/scoped_tracker.h" 18 #include "base/profiler/scoped_tracker.h"
17 #include "base/run_loop.h" 19 #include "base/run_loop.h"
18 #include "base/single_thread_task_runner.h" 20 #include "base/task_scheduler/task_scheduler.h"
19 #include "base/threading/platform_thread.h" 21 #include "base/threading/platform_thread.h"
20 #include "base/threading/sequenced_worker_pool.h" 22 #include "base/threading/sequenced_worker_pool.h"
21 #include "build/build_config.h" 23 #include "build/build_config.h"
22 #include "content/public/browser/browser_thread_delegate.h" 24 #include "content/public/browser/browser_thread_delegate.h"
23 #include "content/public/browser/content_browser_client.h" 25 #include "content/public/browser/content_browser_client.h"
24 #include "net/disk_cache/simple/simple_backend_impl.h" 26 #include "net/disk_cache/simple/simple_backend_impl.h"
25 27
26 #if defined(OS_ANDROID) 28 #if defined(OS_ANDROID)
27 #include "base/android/jni_android.h" 29 #include "base/android/jni_android.h"
28 #endif 30 #endif
(...skipping 16 matching lines...) Expand all
45 static const char* GetThreadName(BrowserThread::ID thread) { 47 static const char* GetThreadName(BrowserThread::ID thread) {
46 if (BrowserThread::UI < thread && thread < BrowserThread::ID_COUNT) 48 if (BrowserThread::UI < thread && thread < BrowserThread::ID_COUNT)
47 return g_browser_thread_names[thread]; 49 return g_browser_thread_names[thread];
48 if (thread == BrowserThread::UI) 50 if (thread == BrowserThread::UI)
49 return "Chrome_UIThread"; 51 return "Chrome_UIThread";
50 return "Unknown Thread"; 52 return "Unknown Thread";
51 } 53 }
52 54
53 // An implementation of SingleThreadTaskRunner to be used in conjunction 55 // An implementation of SingleThreadTaskRunner to be used in conjunction
54 // with BrowserThread. 56 // with BrowserThread.
57 // TODO(gab): This can go away in favor of |g_globals->task_runners|.
55 class BrowserThreadTaskRunner : public base::SingleThreadTaskRunner { 58 class BrowserThreadTaskRunner : public base::SingleThreadTaskRunner {
56 public: 59 public:
57 explicit BrowserThreadTaskRunner(BrowserThread::ID identifier) 60 explicit BrowserThreadTaskRunner(BrowserThread::ID identifier)
58 : id_(identifier) {} 61 : id_(identifier) {}
59 62
60 // SingleThreadTaskRunner implementation. 63 // SingleThreadTaskRunner implementation.
61 bool PostDelayedTask(const tracked_objects::Location& from_here, 64 bool PostDelayedTask(const tracked_objects::Location& from_here,
62 const base::Closure& task, 65 const base::Closure& task,
63 base::TimeDelta delay) override { 66 base::TimeDelta delay) override {
64 return BrowserThread::PostDelayedTask(id_, from_here, task, delay); 67 return BrowserThread::PostDelayedTask(id_, from_here, task, delay);
(...skipping 27 matching lines...) Expand all
92 new BrowserThreadTaskRunner(static_cast<BrowserThread::ID>(i)); 95 new BrowserThreadTaskRunner(static_cast<BrowserThread::ID>(i));
93 } 96 }
94 } 97 }
95 98
96 scoped_refptr<base::SingleThreadTaskRunner> proxies[BrowserThread::ID_COUNT]; 99 scoped_refptr<base::SingleThreadTaskRunner> proxies[BrowserThread::ID_COUNT];
97 }; 100 };
98 101
99 base::LazyInstance<BrowserThreadTaskRunners>::Leaky g_task_runners = 102 base::LazyInstance<BrowserThreadTaskRunners>::Leaky g_task_runners =
100 LAZY_INSTANCE_INITIALIZER; 103 LAZY_INSTANCE_INITIALIZER;
101 104
105 // State of a given BrowserThread::ID in chronological order throughout the
106 // browser process' lifetime.
107 enum BrowserThreadState {
108 // BrowserThread::ID isn't associated with anything yet.
109 UNINITIALIZED = 0,
110 // BrowserThread::ID is associated but the underlying thread doesn't run yet.
Avi (use Gerrit) 2016/11/08 16:16:15 "... underlying thread hasn't run yet."
gab 2016/11/08 20:40:44 Done.
111 INITIALIZED,
112 // BrowserThread::ID is associated to a live thread.
113 RUNNING,
114 // BrowserThread::ID is associated to a thread having been or being shutdown.
115 SHUTDOWN
116 };
117
102 struct BrowserThreadGlobals { 118 struct BrowserThreadGlobals {
103 BrowserThreadGlobals() 119 BrowserThreadGlobals()
104 : blocking_pool( 120 : blocking_pool(
105 new base::SequencedWorkerPool(3, 121 new base::SequencedWorkerPool(3,
106 "BrowserBlocking", 122 "BrowserBlocking",
107 base::TaskPriority::USER_VISIBLE)) { 123 base::TaskPriority::USER_VISIBLE)) {
108 memset(threads, 0, BrowserThread::ID_COUNT * sizeof(threads[0])); 124 memset(states, 0, BrowserThread::ID_COUNT * sizeof(states[0]));
109 memset(thread_ids, 0, BrowserThread::ID_COUNT * sizeof(thread_ids[0]));
110 memset(thread_delegates, 0, 125 memset(thread_delegates, 0,
111 BrowserThread::ID_COUNT * sizeof(thread_delegates[0])); 126 BrowserThread::ID_COUNT * sizeof(thread_delegates[0]));
Avi (use Gerrit) 2016/11/08 16:16:15 Does xxx = { 0 } syntax suffice to zero these? I'm
gab 2016/11/08 20:40:44 I just tried = {}; as a member initializer and it
112 } 127 }
113 128
114 // This lock protects |threads| and |thread_ids|. Do not read or modify those 129 // 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. 130 // arrays without holding this lock. Do not block while holding this lock.
116 base::Lock lock; 131 base::Lock lock;
117 132
118 // This array is protected by |lock|. IDs in this array are populated as soon 133 // This array is filled either as the underlying threads start and invoke
119 // as their respective thread is started and are never reset. 134 // Init() or in RedirectThreadIDToTaskRunner() for threads that are being
120 base::PlatformThreadId thread_ids[BrowserThread::ID_COUNT]; 135 // redirected. It is not emptied during shutdown in order to support
136 // RunsTasksOnCurrentThread() until the very end.
137 scoped_refptr<base::SingleThreadTaskRunner>
138 task_runners[BrowserThread::ID_COUNT];
121 139
122 // This array is protected by |lock|. The threads are not owned by this 140 // 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 141 // because |threads| isn't a good signal per redirected IDs remaining null and
124 // BrowserMainLoop. BrowserThreadImpl objects remove themselves from this 142 // |task_runners| isn't either per not being cleaned up on shutdown.
125 // array upon destruction. 143 BrowserThreadState states[BrowserThread::ID_COUNT];
126 BrowserThreadImpl* threads[BrowserThread::ID_COUNT];
127 144
128 // Only atomic operations are used on this array. The delegates are not owned 145 // Only atomic operations are used on this array. The delegates are not owned
129 // by this array, rather by whoever calls BrowserThread::SetDelegate. 146 // by this array, rather by whoever calls BrowserThread::SetDelegate.
130 BrowserThreadDelegate* thread_delegates[BrowserThread::ID_COUNT]; 147 BrowserThreadDelegate* thread_delegates[BrowserThread::ID_COUNT];
131 148
132 const scoped_refptr<base::SequencedWorkerPool> blocking_pool; 149 const scoped_refptr<base::SequencedWorkerPool> blocking_pool;
133 }; 150 };
134 151
135 base::LazyInstance<BrowserThreadGlobals>::Leaky 152 base::LazyInstance<BrowserThreadGlobals>::Leaky
136 g_globals = LAZY_INSTANCE_INITIALIZER; 153 g_globals = LAZY_INSTANCE_INITIALIZER;
137 154
138 } // namespace 155 } // namespace
139 156
140 BrowserThreadImpl::BrowserThreadImpl(ID identifier) 157 BrowserThreadImpl::BrowserThreadImpl(ID identifier)
141 : Thread(GetThreadName(identifier)), identifier_(identifier) { 158 : Thread(GetThreadName(identifier)), identifier_(identifier) {
142 Initialize(); 159 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 } 160 }
151 161
152 BrowserThreadImpl::BrowserThreadImpl(ID identifier, 162 BrowserThreadImpl::BrowserThreadImpl(ID identifier,
153 base::MessageLoop* message_loop) 163 base::MessageLoop* message_loop)
154 : Thread(GetThreadName(identifier)), identifier_(identifier) { 164 : Thread(GetThreadName(identifier)), identifier_(identifier) {
155 SetMessageLoop(message_loop); 165 SetMessageLoop(message_loop);
156 Initialize(); 166 Initialize();
157 167
158 // If constructed with an explicit message loop, this is a fake BrowserThread 168 // If constructed with an explicit message loop, this is a fake BrowserThread
159 // which runs on the current thread. 169 // which runs on the current thread.
160 BrowserThreadGlobals& globals = g_globals.Get(); 170 BrowserThreadGlobals& globals = g_globals.Get();
161 base::AutoLock lock(globals.lock); 171 base::AutoLock lock(globals.lock);
162 globals.thread_ids[identifier] = base::PlatformThread::CurrentId(); 172
173 DCHECK(!globals.task_runners[identifier_]);
174 globals.task_runners[identifier_] = message_loop->task_runner();
175
176 DCHECK_EQ(globals.states[identifier_], BrowserThreadState::INITIALIZED);
177 globals.states[identifier_] = BrowserThreadState::RUNNING;
163 } 178 }
164 179
165 // static 180 // static
166 void BrowserThreadImpl::ShutdownThreadPool() { 181 void BrowserThreadImpl::ShutdownThreadPool() {
167 // The goal is to make it impossible for chrome to 'infinite loop' during 182 // 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 183 // shutdown, but to reasonably expect that all BLOCKING_SHUTDOWN tasks queued
169 // during shutdown get run. There's nothing particularly scientific about the 184 // during shutdown get run. There's nothing particularly scientific about the
170 // number chosen. 185 // number chosen.
171 const int kMaxNewShutdownBlockingTasks = 1000; 186 const int kMaxNewShutdownBlockingTasks = 1000;
172 BrowserThreadGlobals& globals = g_globals.Get(); 187 BrowserThreadGlobals& globals = g_globals.Get();
173 globals.blocking_pool->Shutdown(kMaxNewShutdownBlockingTasks); 188 globals.blocking_pool->Shutdown(kMaxNewShutdownBlockingTasks);
174 } 189 }
175 190
176 // static 191 // static
177 void BrowserThreadImpl::FlushThreadPoolHelperForTesting() { 192 void BrowserThreadImpl::FlushThreadPoolHelperForTesting() {
178 // We don't want to create a pool if none exists. 193 // We don't want to create a pool if none exists.
179 if (g_globals == nullptr) 194 if (g_globals == nullptr)
180 return; 195 return;
181 g_globals.Get().blocking_pool->FlushForTesting(); 196 g_globals.Get().blocking_pool->FlushForTesting();
182 disk_cache::SimpleBackendImpl::FlushWorkerPoolForTesting(); 197 disk_cache::SimpleBackendImpl::FlushWorkerPoolForTesting();
183 } 198 }
184 199
185 void BrowserThreadImpl::Init() { 200 void BrowserThreadImpl::Init() {
186 BrowserThreadGlobals& globals = g_globals.Get(); 201 BrowserThreadGlobals& globals = g_globals.Get();
187 202
203 {
204 base::AutoLock lock(globals.lock);
205
206 // Grab the underlying thread's TaskRunner. This needs to happen right away
207 // as CurrentlyOn() depends on it.
208 globals.task_runners[identifier_] = message_loop()->task_runner();
209
210 DCHECK_EQ(globals.states[identifier_], BrowserThreadState::INITIALIZED);
211 globals.states[identifier_] = BrowserThreadState::RUNNING;
212 }
213
188 if (BrowserThread::CurrentlyOn(BrowserThread::DB) || 214 if (BrowserThread::CurrentlyOn(BrowserThread::DB) ||
189 BrowserThread::CurrentlyOn(BrowserThread::FILE) || 215 BrowserThread::CurrentlyOn(BrowserThread::FILE) ||
190 BrowserThread::CurrentlyOn(BrowserThread::FILE_USER_BLOCKING) || 216 BrowserThread::CurrentlyOn(BrowserThread::FILE_USER_BLOCKING) ||
191 BrowserThread::CurrentlyOn(BrowserThread::PROCESS_LAUNCHER) || 217 BrowserThread::CurrentlyOn(BrowserThread::PROCESS_LAUNCHER) ||
192 BrowserThread::CurrentlyOn(BrowserThread::CACHE)) { 218 BrowserThread::CurrentlyOn(BrowserThread::CACHE)) {
193 base::MessageLoop* message_loop = base::MessageLoop::current(); 219 // Nesting and task observers are not allowed on redirected threads.
194 message_loop->DisallowNesting(); 220 message_loop()->DisallowNesting();
195 message_loop->DisallowTaskObservers(); 221 message_loop()->DisallowTaskObservers();
196 } 222 }
197 223
198 using base::subtle::AtomicWord; 224 using base::subtle::AtomicWord;
199 AtomicWord* storage = 225 AtomicWord* storage =
200 reinterpret_cast<AtomicWord*>(&globals.thread_delegates[identifier_]); 226 reinterpret_cast<AtomicWord*>(&globals.thread_delegates[identifier_]);
201 AtomicWord stored_pointer = base::subtle::NoBarrier_Load(storage); 227 AtomicWord stored_pointer = base::subtle::NoBarrier_Load(storage);
202 BrowserThreadDelegate* delegate = 228 BrowserThreadDelegate* delegate =
203 reinterpret_cast<BrowserThreadDelegate*>(stored_pointer); 229 reinterpret_cast<BrowserThreadDelegate*>(stored_pointer);
204 if (delegate) 230 if (delegate)
205 delegate->Init(); 231 delegate->Init();
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
307 reinterpret_cast<BrowserThreadDelegate*>(stored_pointer); 333 reinterpret_cast<BrowserThreadDelegate*>(stored_pointer);
308 334
309 if (delegate) 335 if (delegate)
310 delegate->CleanUp(); 336 delegate->CleanUp();
311 337
312 // PostTaskHelper() accesses the message loop while holding this lock. 338 // PostTaskHelper() accesses the message loop while holding this lock.
313 // However, the message loop will soon be destructed without any locking. So 339 // However, the message loop will soon be destructed without any locking. So
314 // to prevent a race with accessing the message loop in PostTaskHelper(), 340 // to prevent a race with accessing the message loop in PostTaskHelper(),
315 // remove this thread from the global array now. 341 // remove this thread from the global array now.
316 base::AutoLock lock(globals.lock); 342 base::AutoLock lock(globals.lock);
317 globals.threads[identifier_] = nullptr; 343 DCHECK_EQ(globals.states[identifier_], BrowserThreadState::RUNNING);
344 globals.states[identifier_] = BrowserThreadState::SHUTDOWN;
318 } 345 }
319 346
320 void BrowserThreadImpl::Initialize() { 347 void BrowserThreadImpl::Initialize() {
321 BrowserThreadGlobals& globals = g_globals.Get(); 348 BrowserThreadGlobals& globals = g_globals.Get();
322 349
323 base::AutoLock lock(globals.lock); 350 base::AutoLock lock(globals.lock);
324 DCHECK_GE(identifier_, 0); 351 DCHECK_GE(identifier_, 0);
325 DCHECK_LT(identifier_, ID_COUNT); 352 DCHECK_LT(identifier_, ID_COUNT);
326 DCHECK_EQ(globals.threads[identifier_], nullptr); 353 DCHECK_EQ(globals.states[identifier_], BrowserThreadState::UNINITIALIZED);
327 globals.threads[identifier_] = this; 354 globals.states[identifier_] = BrowserThreadState::INITIALIZED;
328 } 355 }
329 356
330 BrowserThreadImpl::~BrowserThreadImpl() { 357 BrowserThreadImpl::~BrowserThreadImpl() {
331 // All Thread subclasses must call Stop() in the destructor. This is 358 // All Thread subclasses must call Stop() in the destructor. This is
332 // doubly important here as various bits of code check they are on 359 // doubly important here as various bits of code check they are on
333 // the right BrowserThread. 360 // the right BrowserThread.
334 Stop(); 361 Stop();
335 362
336 BrowserThreadGlobals& globals = g_globals.Get(); 363 BrowserThreadGlobals& globals = g_globals.Get();
337 base::AutoLock lock(globals.lock); 364 base::AutoLock lock(globals.lock);
338 globals.threads[identifier_] = nullptr; 365 // This thread should have gone through Cleanup() as part of Stop() and be in
339 #ifndef NDEBUG 366 // the SHUTDOWN state already (unless it uses an externally provided
367 // MessageLoop instead of a real underlying thread and thus doesn't go through
368 // Cleanup()).
369 if (using_external_message_loop_) {
370 DCHECK_EQ(globals.states[identifier_], BrowserThreadState::RUNNING);
371 globals.states[identifier_] = BrowserThreadState::SHUTDOWN;
372 } else {
373 DCHECK_EQ(globals.states[identifier_], BrowserThreadState::SHUTDOWN);
374 }
375 #if DCHECK_IS_ON()
340 // Double check that the threads are ordered correctly in the enumeration. 376 // Double check that the threads are ordered correctly in the enumeration.
341 for (int i = identifier_ + 1; i < ID_COUNT; ++i) { 377 for (int i = identifier_ + 1; i < ID_COUNT; ++i) {
342 DCHECK(!globals.threads[i]) << 378 DCHECK_EQ(globals.states[i], BrowserThreadState::SHUTDOWN)
343 "Threads must be listed in the reverse order that they die"; 379 << "Threads must be listed in the reverse order that they die";
344 } 380 }
345 #endif 381 #endif
346 } 382 }
347 383
348 bool BrowserThreadImpl::Start() { 384 // static
349 return StartWithOptions(base::Thread::Options()); 385 void BrowserThreadImpl::RedirectThreadIDToTaskRunner(
386 BrowserThread::ID identifier,
387 scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
388 BrowserThreadGlobals& globals = g_globals.Get();
389 base::AutoLock lock(globals.lock);
390 if (task_runner) {
391 DCHECK(!globals.task_runners[identifier]);
392 DCHECK_EQ(globals.states[identifier], BrowserThreadState::UNINITIALIZED);
393
394 globals.task_runners[identifier] = std::move(task_runner);
395 globals.states[identifier] = BrowserThreadState::RUNNING;
396 } else {
397 // Cancelling redirection should only be done on previously redirected
398 // threads.
399 DCHECK_EQ(globals.states[identifier], BrowserThreadState::RUNNING);
400 globals.states[identifier] = BrowserThreadState::SHUTDOWN;
401 }
350 } 402 }
351 403
352 bool BrowserThreadImpl::StartWithOptions(const Options& options) {
353 // The global thread table needs to be locked while a new thread is
354 // starting, as the new thread can asynchronously start touching the
355 // table (and other thread's message_loop).
356 BrowserThreadGlobals& globals = g_globals.Get();
357 base::AutoLock lock(globals.lock);
358 DCHECK_EQ(globals.thread_ids[identifier_], base::kInvalidThreadId);
359 bool result = Thread::StartWithOptions(options);
360 globals.thread_ids[identifier_] = GetThreadId();
361 return result;
362 }
363
364 bool BrowserThreadImpl::StartAndWaitForTesting() {
365 if (!Start())
366 return false;
367 WaitUntilThreadStarted();
368 return true;
369 }
370 // static 404 // static
371 bool BrowserThreadImpl::PostTaskHelper( 405 bool BrowserThreadImpl::PostTaskHelper(
372 BrowserThread::ID identifier, 406 BrowserThread::ID identifier,
373 const tracked_objects::Location& from_here, 407 const tracked_objects::Location& from_here,
374 const base::Closure& task, 408 const base::Closure& task,
375 base::TimeDelta delay, 409 base::TimeDelta delay,
376 bool nestable) { 410 bool nestable) {
377 DCHECK_GE(identifier, 0); 411 DCHECK_GE(identifier, 0);
378 DCHECK_LT(identifier, ID_COUNT); 412 DCHECK_LT(identifier, ID_COUNT);
379 // Optimization: to avoid unnecessary locks, we listed the ID enumeration in 413 // 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 414 // order of lifetime. So no need to lock if we know that the target thread
381 // outlives current thread. 415 // outlives current thread.
382 // Note: since the array is so small, ok to loop instead of creating a map, 416 // 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 417 // which would require a lock because std::map isn't thread safe, defeating
384 // the whole purpose of this optimization. 418 // the whole purpose of this optimization.
385 BrowserThread::ID current_thread = ID_COUNT; 419 BrowserThread::ID current_thread = ID_COUNT;
386 bool target_thread_outlives_current = 420 bool target_thread_outlives_current =
387 GetCurrentThreadIdentifier(&current_thread) && 421 GetCurrentThreadIdentifier(&current_thread) &&
388 current_thread >= identifier; 422 current_thread >= identifier;
389 423
390 BrowserThreadGlobals& globals = g_globals.Get(); 424 BrowserThreadGlobals& globals = g_globals.Get();
391 if (!target_thread_outlives_current) 425 if (!target_thread_outlives_current)
392 globals.lock.Acquire(); 426 globals.lock.Acquire();
393 427
394 base::MessageLoop* message_loop = 428 const bool accepting_tasks =
395 globals.threads[identifier] ? globals.threads[identifier]->message_loop() 429 globals.states[identifier] == BrowserThreadState::RUNNING;
396 : nullptr; 430 if (accepting_tasks) {
397 if (message_loop) { 431 base::SingleThreadTaskRunner* task_runner =
432 globals.task_runners[identifier].get();
433 DCHECK(task_runner);
398 if (nestable) { 434 if (nestable) {
399 message_loop->task_runner()->PostDelayedTask(from_here, task, delay); 435 task_runner->PostDelayedTask(from_here, task, delay);
400 } else { 436 } else {
401 message_loop->task_runner()->PostNonNestableDelayedTask(from_here, task, 437 task_runner->PostNonNestableDelayedTask(from_here, task, delay);
402 delay);
403 } 438 }
404 } 439 }
405 440
406 if (!target_thread_outlives_current) 441 if (!target_thread_outlives_current)
407 globals.lock.Release(); 442 globals.lock.Release();
408 443
409 return !!message_loop; 444 return accepting_tasks;
410 } 445 }
411 446
412 // static 447 // static
413 bool BrowserThread::PostBlockingPoolTask( 448 bool BrowserThread::PostBlockingPoolTask(
414 const tracked_objects::Location& from_here, 449 const tracked_objects::Location& from_here,
415 const base::Closure& task) { 450 const base::Closure& task) {
416 return g_globals.Get().blocking_pool->PostWorkerTask(from_here, task); 451 return g_globals.Get().blocking_pool->PostWorkerTask(from_here, task);
417 } 452 }
418 453
419 // static 454 // static
(...skipping 30 matching lines...) Expand all
450 485
451 // static 486 // static
452 bool BrowserThread::IsThreadInitialized(ID identifier) { 487 bool BrowserThread::IsThreadInitialized(ID identifier) {
453 if (g_globals == nullptr) 488 if (g_globals == nullptr)
454 return false; 489 return false;
455 490
456 BrowserThreadGlobals& globals = g_globals.Get(); 491 BrowserThreadGlobals& globals = g_globals.Get();
457 base::AutoLock lock(globals.lock); 492 base::AutoLock lock(globals.lock);
458 DCHECK_GE(identifier, 0); 493 DCHECK_GE(identifier, 0);
459 DCHECK_LT(identifier, ID_COUNT); 494 DCHECK_LT(identifier, ID_COUNT);
460 return globals.threads[identifier] != nullptr; 495 return globals.states[identifier] == BrowserThreadState::INITIALIZED ||
496 globals.states[identifier] == BrowserThreadState::RUNNING;
461 } 497 }
462 498
463 // static 499 // static
464 bool BrowserThread::CurrentlyOn(ID identifier) { 500 bool BrowserThread::CurrentlyOn(ID identifier) {
465 BrowserThreadGlobals& globals = g_globals.Get(); 501 BrowserThreadGlobals& globals = g_globals.Get();
466 base::AutoLock lock(globals.lock); 502 base::AutoLock lock(globals.lock);
467 DCHECK_GE(identifier, 0); 503 DCHECK_GE(identifier, 0);
468 DCHECK_LT(identifier, ID_COUNT); 504 DCHECK_LT(identifier, ID_COUNT);
469 return base::PlatformThread::CurrentId() == globals.thread_ids[identifier]; 505 return globals.task_runners[identifier] &&
506 globals.task_runners[identifier]->RunsTasksOnCurrentThread();
470 } 507 }
471 508
472 // static 509 // static
473 std::string BrowserThread::GetDCheckCurrentlyOnErrorMessage(ID expected) { 510 std::string BrowserThread::GetDCheckCurrentlyOnErrorMessage(ID expected) {
474 std::string actual_name = base::PlatformThread::GetName(); 511 std::string actual_name = base::PlatformThread::GetName();
475 if (actual_name.empty()) 512 if (actual_name.empty())
476 actual_name = "Unknown Thread"; 513 actual_name = "Unknown Thread";
477 514
478 std::string result = "Must be called on "; 515 std::string result = "Must be called on ";
479 result += GetThreadName(expected); 516 result += GetThreadName(expected);
480 result += "; actually called on "; 517 result += "; actually called on ";
481 result += actual_name; 518 result += actual_name;
482 result += "."; 519 result += ".";
483 return result; 520 return result;
484 } 521 }
485 522
486 // static 523 // static
487 bool BrowserThread::IsMessageLoopValid(ID identifier) { 524 bool BrowserThread::IsMessageLoopValid(ID identifier) {
488 if (g_globals == nullptr) 525 if (g_globals == nullptr)
489 return false; 526 return false;
490 527
491 BrowserThreadGlobals& globals = g_globals.Get(); 528 BrowserThreadGlobals& globals = g_globals.Get();
492 base::AutoLock lock(globals.lock); 529 base::AutoLock lock(globals.lock);
493 DCHECK_GE(identifier, 0); 530 DCHECK_GE(identifier, 0);
494 DCHECK_LT(identifier, ID_COUNT); 531 DCHECK_LT(identifier, ID_COUNT);
495 return globals.threads[identifier] && 532 return globals.states[identifier] == BrowserThreadState::RUNNING;
496 globals.threads[identifier]->message_loop();
497 } 533 }
498 534
499 // static 535 // static
500 bool BrowserThread::PostTask(ID identifier, 536 bool BrowserThread::PostTask(ID identifier,
501 const tracked_objects::Location& from_here, 537 const tracked_objects::Location& from_here,
502 const base::Closure& task) { 538 const base::Closure& task) {
503 return BrowserThreadImpl::PostTaskHelper( 539 return BrowserThreadImpl::PostTaskHelper(
504 identifier, from_here, task, base::TimeDelta(), true); 540 identifier, from_here, task, base::TimeDelta(), true);
505 } 541 }
506 542
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
540 const base::Closure& reply) { 576 const base::Closure& reply) {
541 return GetTaskRunnerForThread(identifier) 577 return GetTaskRunnerForThread(identifier)
542 ->PostTaskAndReply(from_here, task, reply); 578 ->PostTaskAndReply(from_here, task, reply);
543 } 579 }
544 580
545 // static 581 // static
546 bool BrowserThread::GetCurrentThreadIdentifier(ID* identifier) { 582 bool BrowserThread::GetCurrentThreadIdentifier(ID* identifier) {
547 if (g_globals == nullptr) 583 if (g_globals == nullptr)
548 return false; 584 return false;
549 585
550 base::MessageLoop* cur_message_loop = base::MessageLoop::current();
551 BrowserThreadGlobals& globals = g_globals.Get(); 586 BrowserThreadGlobals& globals = g_globals.Get();
552 // Profiler to track potential contention on |globals.lock|. This only does 587 // 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 588 // real work on canary and local dev builds, so the cost of having this here
554 // should be minimal. 589 // should be minimal.
555 tracked_objects::ScopedTracker tracking_profile(FROM_HERE); 590 tracked_objects::ScopedTracker tracking_profile(FROM_HERE);
556 base::AutoLock lock(globals.lock); 591 base::AutoLock lock(globals.lock);
557 for (int i = 0; i < ID_COUNT; ++i) { 592 for (int i = 0; i < ID_COUNT; ++i) {
558 if (globals.threads[i] && 593 if (globals.task_runners[i] &&
559 globals.threads[i]->message_loop() == cur_message_loop) { 594 globals.task_runners[i]->RunsTasksOnCurrentThread()) {
560 *identifier = globals.threads[i]->identifier_; 595 *identifier = static_cast<ID>(i);
561 return true; 596 return true;
562 } 597 }
563 } 598 }
564 599
565 return false; 600 return false;
566 } 601 }
567 602
568 // static 603 // static
569 scoped_refptr<base::SingleThreadTaskRunner> 604 scoped_refptr<base::SingleThreadTaskRunner>
570 BrowserThread::GetTaskRunnerForThread(ID identifier) { 605 BrowserThread::GetTaskRunnerForThread(ID identifier) {
571 return g_task_runners.Get().proxies[identifier]; 606 return g_task_runners.Get().proxies[identifier];
572 } 607 }
573 608
574 void BrowserThread::SetDelegate(ID identifier, 609 void BrowserThread::SetDelegate(ID identifier,
575 BrowserThreadDelegate* delegate) { 610 BrowserThreadDelegate* delegate) {
576 using base::subtle::AtomicWord; 611 using base::subtle::AtomicWord;
577 BrowserThreadGlobals& globals = g_globals.Get(); 612 BrowserThreadGlobals& globals = g_globals.Get();
578 AtomicWord* storage = reinterpret_cast<AtomicWord*>( 613 AtomicWord* storage = reinterpret_cast<AtomicWord*>(
579 &globals.thread_delegates[identifier]); 614 &globals.thread_delegates[identifier]);
580 AtomicWord old_pointer = base::subtle::NoBarrier_AtomicExchange( 615 AtomicWord old_pointer = base::subtle::NoBarrier_AtomicExchange(
581 storage, reinterpret_cast<AtomicWord>(delegate)); 616 storage, reinterpret_cast<AtomicWord>(delegate));
582 617
583 // This catches registration when previously registered. 618 // This catches registration when previously registered.
584 DCHECK(!delegate || !old_pointer); 619 DCHECK(!delegate || !old_pointer);
585 } 620 }
586 621
587 } // namespace content 622 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698