Respond with QuotaExceededError when IndexedDB has no disk space on open.
[chromium-blink-merge.git] / content / browser / browser_thread_impl.cc
blobfb6feac452fc5c276d3d98624678c37f3e0fe82c
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
3 // found in the LICENSE file.
5 #include "content/browser/browser_thread_impl.h"
7 #include <string>
9 #include "base/atomicops.h"
10 #include "base/bind.h"
11 #include "base/compiler_specific.h"
12 #include "base/lazy_instance.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/message_loop/message_loop_proxy.h"
15 #include "base/threading/sequenced_worker_pool.h"
16 #include "base/threading/thread_restrictions.h"
17 #include "content/public/browser/browser_thread_delegate.h"
19 namespace content {
21 namespace {
23 // Friendly names for the well-known threads.
24 static const char* g_browser_thread_names[BrowserThread::ID_COUNT] = {
25 "", // UI (name assembled in browser_main.cc).
26 "Chrome_DBThread", // DB
27 "Chrome_FileThread", // FILE
28 "Chrome_FileUserBlockingThread", // FILE_USER_BLOCKING
29 "Chrome_ProcessLauncherThread", // PROCESS_LAUNCHER
30 "Chrome_CacheThread", // CACHE
31 "Chrome_IOThread", // IO
34 struct BrowserThreadGlobals {
35 BrowserThreadGlobals()
36 : blocking_pool(new base::SequencedWorkerPool(3, "BrowserBlocking")) {
37 memset(threads, 0, BrowserThread::ID_COUNT * sizeof(threads[0]));
38 memset(thread_delegates, 0,
39 BrowserThread::ID_COUNT * sizeof(thread_delegates[0]));
42 // This lock protects |threads|. Do not read or modify that array
43 // without holding this lock. Do not block while holding this lock.
44 base::Lock lock;
46 // This array is protected by |lock|. The threads are not owned by this
47 // array. Typically, the threads are owned on the UI thread by
48 // BrowserMainLoop. BrowserThreadImpl objects remove themselves from this
49 // array upon destruction.
50 BrowserThreadImpl* threads[BrowserThread::ID_COUNT];
52 // Only atomic operations are used on this array. The delegates are not owned
53 // by this array, rather by whoever calls BrowserThread::SetDelegate.
54 BrowserThreadDelegate* thread_delegates[BrowserThread::ID_COUNT];
56 const scoped_refptr<base::SequencedWorkerPool> blocking_pool;
59 base::LazyInstance<BrowserThreadGlobals>::Leaky
60 g_globals = LAZY_INSTANCE_INITIALIZER;
62 } // namespace
64 BrowserThreadImpl::BrowserThreadImpl(ID identifier)
65 : Thread(g_browser_thread_names[identifier]),
66 identifier_(identifier) {
67 Initialize();
70 BrowserThreadImpl::BrowserThreadImpl(ID identifier,
71 base::MessageLoop* message_loop)
72 : Thread(message_loop->thread_name().c_str()), identifier_(identifier) {
73 set_message_loop(message_loop);
74 Initialize();
77 // static
78 void BrowserThreadImpl::ShutdownThreadPool() {
79 // The goal is to make it impossible for chrome to 'infinite loop' during
80 // shutdown, but to reasonably expect that all BLOCKING_SHUTDOWN tasks queued
81 // during shutdown get run. There's nothing particularly scientific about the
82 // number chosen.
83 const int kMaxNewShutdownBlockingTasks = 1000;
84 BrowserThreadGlobals& globals = g_globals.Get();
85 globals.blocking_pool->Shutdown(kMaxNewShutdownBlockingTasks);
88 // static
89 void BrowserThreadImpl::FlushThreadPoolHelper() {
90 // We don't want to create a pool if none exists.
91 if (g_globals == NULL)
92 return;
93 g_globals.Get().blocking_pool->FlushForTesting();
96 void BrowserThreadImpl::Init() {
97 BrowserThreadGlobals& globals = g_globals.Get();
99 using base::subtle::AtomicWord;
100 AtomicWord* storage =
101 reinterpret_cast<AtomicWord*>(&globals.thread_delegates[identifier_]);
102 AtomicWord stored_pointer = base::subtle::NoBarrier_Load(storage);
103 BrowserThreadDelegate* delegate =
104 reinterpret_cast<BrowserThreadDelegate*>(stored_pointer);
105 if (delegate) {
106 delegate->Init();
107 message_loop()->PostTask(FROM_HERE,
108 base::Bind(&BrowserThreadDelegate::InitAsync,
109 // Delegate is expected to exist for the
110 // duration of the thread's lifetime
111 base::Unretained(delegate)));
115 // We disable optimizations for this block of functions so the compiler doesn't
116 // merge them all together.
117 MSVC_DISABLE_OPTIMIZE()
118 MSVC_PUSH_DISABLE_WARNING(4748)
120 NOINLINE void BrowserThreadImpl::UIThreadRun(base::MessageLoop* message_loop) {
121 volatile int line_number = __LINE__;
122 Thread::Run(message_loop);
123 CHECK_GT(line_number, 0);
126 NOINLINE void BrowserThreadImpl::DBThreadRun(base::MessageLoop* message_loop) {
127 volatile int line_number = __LINE__;
128 Thread::Run(message_loop);
129 CHECK_GT(line_number, 0);
132 NOINLINE void BrowserThreadImpl::FileThreadRun(
133 base::MessageLoop* message_loop) {
134 volatile int line_number = __LINE__;
135 Thread::Run(message_loop);
136 CHECK_GT(line_number, 0);
139 NOINLINE void BrowserThreadImpl::FileUserBlockingThreadRun(
140 base::MessageLoop* message_loop) {
141 volatile int line_number = __LINE__;
142 Thread::Run(message_loop);
143 CHECK_GT(line_number, 0);
146 NOINLINE void BrowserThreadImpl::ProcessLauncherThreadRun(
147 base::MessageLoop* message_loop) {
148 volatile int line_number = __LINE__;
149 Thread::Run(message_loop);
150 CHECK_GT(line_number, 0);
153 NOINLINE void BrowserThreadImpl::CacheThreadRun(
154 base::MessageLoop* message_loop) {
155 volatile int line_number = __LINE__;
156 Thread::Run(message_loop);
157 CHECK_GT(line_number, 0);
160 NOINLINE void BrowserThreadImpl::IOThreadRun(base::MessageLoop* message_loop) {
161 volatile int line_number = __LINE__;
162 Thread::Run(message_loop);
163 CHECK_GT(line_number, 0);
166 MSVC_POP_WARNING()
167 MSVC_ENABLE_OPTIMIZE();
169 void BrowserThreadImpl::Run(base::MessageLoop* message_loop) {
170 BrowserThread::ID thread_id;
171 if (!GetCurrentThreadIdentifier(&thread_id))
172 return Thread::Run(message_loop);
174 switch (thread_id) {
175 case BrowserThread::UI:
176 return UIThreadRun(message_loop);
177 case BrowserThread::DB:
178 return DBThreadRun(message_loop);
179 case BrowserThread::FILE:
180 return FileThreadRun(message_loop);
181 case BrowserThread::FILE_USER_BLOCKING:
182 return FileUserBlockingThreadRun(message_loop);
183 case BrowserThread::PROCESS_LAUNCHER:
184 return ProcessLauncherThreadRun(message_loop);
185 case BrowserThread::CACHE:
186 return CacheThreadRun(message_loop);
187 case BrowserThread::IO:
188 return IOThreadRun(message_loop);
189 case BrowserThread::ID_COUNT:
190 CHECK(false); // This shouldn't actually be reached!
191 break;
193 Thread::Run(message_loop);
196 void BrowserThreadImpl::CleanUp() {
197 BrowserThreadGlobals& globals = g_globals.Get();
199 using base::subtle::AtomicWord;
200 AtomicWord* storage =
201 reinterpret_cast<AtomicWord*>(&globals.thread_delegates[identifier_]);
202 AtomicWord stored_pointer = base::subtle::NoBarrier_Load(storage);
203 BrowserThreadDelegate* delegate =
204 reinterpret_cast<BrowserThreadDelegate*>(stored_pointer);
206 if (delegate)
207 delegate->CleanUp();
210 void BrowserThreadImpl::Initialize() {
211 BrowserThreadGlobals& globals = g_globals.Get();
213 base::AutoLock lock(globals.lock);
214 DCHECK(identifier_ >= 0 && identifier_ < ID_COUNT);
215 DCHECK(globals.threads[identifier_] == NULL);
216 globals.threads[identifier_] = this;
219 BrowserThreadImpl::~BrowserThreadImpl() {
220 // All Thread subclasses must call Stop() in the destructor. This is
221 // doubly important here as various bits of code check they are on
222 // the right BrowserThread.
223 Stop();
225 BrowserThreadGlobals& globals = g_globals.Get();
226 base::AutoLock lock(globals.lock);
227 globals.threads[identifier_] = NULL;
228 #ifndef NDEBUG
229 // Double check that the threads are ordered correctly in the enumeration.
230 for (int i = identifier_ + 1; i < ID_COUNT; ++i) {
231 DCHECK(!globals.threads[i]) <<
232 "Threads must be listed in the reverse order that they die";
234 #endif
237 // static
238 bool BrowserThreadImpl::PostTaskHelper(
239 BrowserThread::ID identifier,
240 const tracked_objects::Location& from_here,
241 const base::Closure& task,
242 base::TimeDelta delay,
243 bool nestable) {
244 DCHECK(identifier >= 0 && identifier < ID_COUNT);
245 // Optimization: to avoid unnecessary locks, we listed the ID enumeration in
246 // order of lifetime. So no need to lock if we know that the target thread
247 // outlives current thread.
248 // Note: since the array is so small, ok to loop instead of creating a map,
249 // which would require a lock because std::map isn't thread safe, defeating
250 // the whole purpose of this optimization.
251 BrowserThread::ID current_thread;
252 bool target_thread_outlives_current =
253 GetCurrentThreadIdentifier(&current_thread) &&
254 current_thread >= identifier;
256 BrowserThreadGlobals& globals = g_globals.Get();
257 if (!target_thread_outlives_current)
258 globals.lock.Acquire();
260 base::MessageLoop* message_loop =
261 globals.threads[identifier] ? globals.threads[identifier]->message_loop()
262 : NULL;
263 if (message_loop) {
264 if (nestable) {
265 message_loop->PostDelayedTask(from_here, task, delay);
266 } else {
267 message_loop->PostNonNestableDelayedTask(from_here, task, delay);
271 if (!target_thread_outlives_current)
272 globals.lock.Release();
274 return !!message_loop;
277 // An implementation of MessageLoopProxy to be used in conjunction
278 // with BrowserThread.
279 class BrowserThreadMessageLoopProxy : public base::MessageLoopProxy {
280 public:
281 explicit BrowserThreadMessageLoopProxy(BrowserThread::ID identifier)
282 : id_(identifier) {
285 // MessageLoopProxy implementation.
286 virtual bool PostDelayedTask(
287 const tracked_objects::Location& from_here,
288 const base::Closure& task, base::TimeDelta delay) OVERRIDE {
289 return BrowserThread::PostDelayedTask(id_, from_here, task, delay);
292 virtual bool PostNonNestableDelayedTask(
293 const tracked_objects::Location& from_here,
294 const base::Closure& task,
295 base::TimeDelta delay) OVERRIDE {
296 return BrowserThread::PostNonNestableDelayedTask(id_, from_here, task,
297 delay);
300 virtual bool RunsTasksOnCurrentThread() const OVERRIDE {
301 return BrowserThread::CurrentlyOn(id_);
304 protected:
305 virtual ~BrowserThreadMessageLoopProxy() {}
307 private:
308 BrowserThread::ID id_;
309 DISALLOW_COPY_AND_ASSIGN(BrowserThreadMessageLoopProxy);
312 // static
313 bool BrowserThread::PostBlockingPoolTask(
314 const tracked_objects::Location& from_here,
315 const base::Closure& task) {
316 return g_globals.Get().blocking_pool->PostWorkerTask(from_here, task);
319 bool BrowserThread::PostBlockingPoolTaskAndReply(
320 const tracked_objects::Location& from_here,
321 const base::Closure& task,
322 const base::Closure& reply) {
323 return g_globals.Get().blocking_pool->PostTaskAndReply(
324 from_here, task, reply);
327 // static
328 bool BrowserThread::PostBlockingPoolSequencedTask(
329 const std::string& sequence_token_name,
330 const tracked_objects::Location& from_here,
331 const base::Closure& task) {
332 return g_globals.Get().blocking_pool->PostNamedSequencedWorkerTask(
333 sequence_token_name, from_here, task);
336 // static
337 base::SequencedWorkerPool* BrowserThread::GetBlockingPool() {
338 return g_globals.Get().blocking_pool.get();
341 // static
342 bool BrowserThread::IsThreadInitialized(ID identifier) {
343 if (g_globals == NULL)
344 return false;
346 BrowserThreadGlobals& globals = g_globals.Get();
347 base::AutoLock lock(globals.lock);
348 DCHECK(identifier >= 0 && identifier < ID_COUNT);
349 return globals.threads[identifier] != NULL;
352 // static
353 bool BrowserThread::CurrentlyOn(ID identifier) {
354 // We shouldn't use MessageLoop::current() since it uses LazyInstance which
355 // may be deleted by ~AtExitManager when a WorkerPool thread calls this
356 // function.
357 // http://crbug.com/63678
358 base::ThreadRestrictions::ScopedAllowSingleton allow_singleton;
359 BrowserThreadGlobals& globals = g_globals.Get();
360 base::AutoLock lock(globals.lock);
361 DCHECK(identifier >= 0 && identifier < ID_COUNT);
362 return globals.threads[identifier] &&
363 globals.threads[identifier]->message_loop() ==
364 base::MessageLoop::current();
367 // static
368 bool BrowserThread::IsMessageLoopValid(ID identifier) {
369 if (g_globals == NULL)
370 return false;
372 BrowserThreadGlobals& globals = g_globals.Get();
373 base::AutoLock lock(globals.lock);
374 DCHECK(identifier >= 0 && identifier < ID_COUNT);
375 return globals.threads[identifier] &&
376 globals.threads[identifier]->message_loop();
379 // static
380 bool BrowserThread::PostTask(ID identifier,
381 const tracked_objects::Location& from_here,
382 const base::Closure& task) {
383 return BrowserThreadImpl::PostTaskHelper(
384 identifier, from_here, task, base::TimeDelta(), true);
387 // static
388 bool BrowserThread::PostDelayedTask(ID identifier,
389 const tracked_objects::Location& from_here,
390 const base::Closure& task,
391 base::TimeDelta delay) {
392 return BrowserThreadImpl::PostTaskHelper(
393 identifier, from_here, task, delay, true);
396 // static
397 bool BrowserThread::PostNonNestableTask(
398 ID identifier,
399 const tracked_objects::Location& from_here,
400 const base::Closure& task) {
401 return BrowserThreadImpl::PostTaskHelper(
402 identifier, from_here, task, base::TimeDelta(), false);
405 // static
406 bool BrowserThread::PostNonNestableDelayedTask(
407 ID identifier,
408 const tracked_objects::Location& from_here,
409 const base::Closure& task,
410 base::TimeDelta delay) {
411 return BrowserThreadImpl::PostTaskHelper(
412 identifier, from_here, task, delay, false);
415 // static
416 bool BrowserThread::PostTaskAndReply(
417 ID identifier,
418 const tracked_objects::Location& from_here,
419 const base::Closure& task,
420 const base::Closure& reply) {
421 return GetMessageLoopProxyForThread(identifier)->PostTaskAndReply(from_here,
422 task,
423 reply);
426 // static
427 bool BrowserThread::GetCurrentThreadIdentifier(ID* identifier) {
428 if (g_globals == NULL)
429 return false;
431 // We shouldn't use MessageLoop::current() since it uses LazyInstance which
432 // may be deleted by ~AtExitManager when a WorkerPool thread calls this
433 // function.
434 // http://crbug.com/63678
435 base::ThreadRestrictions::ScopedAllowSingleton allow_singleton;
436 base::MessageLoop* cur_message_loop = base::MessageLoop::current();
437 BrowserThreadGlobals& globals = g_globals.Get();
438 for (int i = 0; i < ID_COUNT; ++i) {
439 if (globals.threads[i] &&
440 globals.threads[i]->message_loop() == cur_message_loop) {
441 *identifier = globals.threads[i]->identifier_;
442 return true;
446 return false;
449 // static
450 scoped_refptr<base::MessageLoopProxy>
451 BrowserThread::GetMessageLoopProxyForThread(ID identifier) {
452 return make_scoped_refptr(new BrowserThreadMessageLoopProxy(identifier));
455 // static
456 base::MessageLoop* BrowserThread::UnsafeGetMessageLoopForThread(ID identifier) {
457 if (g_globals == NULL)
458 return NULL;
460 BrowserThreadGlobals& globals = g_globals.Get();
461 base::AutoLock lock(globals.lock);
462 base::Thread* thread = globals.threads[identifier];
463 DCHECK(thread);
464 base::MessageLoop* loop = thread->message_loop();
465 return loop;
468 // static
469 void BrowserThread::SetDelegate(ID identifier,
470 BrowserThreadDelegate* delegate) {
471 using base::subtle::AtomicWord;
472 BrowserThreadGlobals& globals = g_globals.Get();
473 AtomicWord* storage = reinterpret_cast<AtomicWord*>(
474 &globals.thread_delegates[identifier]);
475 AtomicWord old_pointer = base::subtle::NoBarrier_AtomicExchange(
476 storage, reinterpret_cast<AtomicWord>(delegate));
478 // This catches registration when previously registered.
479 DCHECK(!delegate || !old_pointer);
482 } // namespace content