OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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(¤t_thread) && | 421 GetCurrentThreadIdentifier(¤t_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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |