summaryrefslogtreecommitdiffstats
path: root/content/browser
diff options
context:
space:
mode:
Diffstat (limited to 'content/browser')
-rw-r--r--content/browser/browser_main_loop.cc8
-rw-r--r--content/browser/browser_thread_impl.cc146
-rw-r--r--content/browser/browser_thread_impl.h2
3 files changed, 110 insertions, 46 deletions
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc
index 4c307b1..8203333 100644
--- a/content/browser/browser_main_loop.cc
+++ b/content/browser/browser_main_loop.cc
@@ -513,6 +513,14 @@ void BrowserMainLoop::ShutdownThreadsAndCleanUp() {
}
}
+ // Close the blocking I/O pool after the other threads. Other threads such
+ // as the I/O thread may need to schedule work like closing files or flushing
+ // data during shutdown, so the blocking pool needs to be available. There
+ // may also be slow operations pending that will blcok shutdown, so closing
+ // it here (which will block until required operations are complete) gives
+ // more head start for those operations to finish.
+ BrowserThreadImpl::ShutdownThreadPool();
+
if (parts_.get())
parts_->PostDestroyThreads();
}
diff --git a/content/browser/browser_thread_impl.cc b/content/browser/browser_thread_impl.cc
index f7cca04..bd6aff9 100644
--- a/content/browser/browser_thread_impl.cc
+++ b/content/browser/browser_thread_impl.cc
@@ -9,6 +9,7 @@
#include "base/lazy_instance.h"
#include "base/message_loop.h"
#include "base/message_loop_proxy.h"
+#include "base/threading/sequenced_worker_pool.h"
#include "base/threading/thread_restrictions.h"
namespace content {
@@ -27,24 +28,37 @@ static const char* g_browser_thread_names[BrowserThread::ID_COUNT] = {
"Chrome_IOThread", // IO
};
-// This lock protects |g_browser_threads|. Do not read or modify that
-// array without holding this lock. Do not block while holding this
-// lock.
-base::LazyInstance<base::Lock,
- base::LeakyLazyInstanceTraits<base::Lock> >
- g_lock = LAZY_INSTANCE_INITIALIZER;
-
-// This array is protected by |g_lock|. The threads are not owned by this
-// array. Typically, the threads are owned on the UI thread by
-// content::BrowserMainLoop. BrowserThreadImpl objects remove
-// themselves from this array upon destruction.
-static BrowserThreadImpl* g_browser_threads[BrowserThread::ID_COUNT];
-
-// Only atomic operations are used on this array. The delegates are
-// not owned by this array, rather by whoever calls
-// BrowserThread::SetDelegate.
-static BrowserThreadDelegate* g_browser_thread_delegates[
- BrowserThread::ID_COUNT];
+struct BrowserThreadGlobals {
+ BrowserThreadGlobals()
+ : blocking_pool(new base::SequencedWorkerPool(3, "BrowserBlocking")) {
+ memset(threads, 0,
+ BrowserThread::ID_COUNT * sizeof(BrowserThreadImpl*));
+ memset(thread_delegates, 0,
+ BrowserThread::ID_COUNT * sizeof(BrowserThreadDelegate*));
+ }
+
+ // This lock protects |threads|. Do not read or modify that array
+ // without holding this lock. Do not block while holding this lock.
+ base::Lock lock;
+
+ // This array is protected by |lock|. The threads are not owned by this
+ // array. Typically, the threads are owned on the UI thread by
+ // content::BrowserMainLoop. BrowserThreadImpl objects remove themselves from
+ // this array upon destruction.
+ BrowserThreadImpl* threads[BrowserThread::ID_COUNT];
+
+ // Only atomic operations are used on this array. The delegates are not owned
+ // by this array, rather by whoever calls BrowserThread::SetDelegate.
+ BrowserThreadDelegate* thread_delegates[BrowserThread::ID_COUNT];
+
+ // This pointer is deliberately leaked on shutdown. This allows the pool to
+ // implement "continue on shutdown" semantics.
+ base::SequencedWorkerPool* blocking_pool;
+};
+
+base::LazyInstance<BrowserThreadGlobals,
+ base::LeakyLazyInstanceTraits<BrowserThreadGlobals> >
+ g_globals = LAZY_INSTANCE_INITIALIZER;
} // namespace
@@ -62,10 +76,18 @@ BrowserThreadImpl::BrowserThreadImpl(ID identifier,
Initialize();
}
+// static
+void BrowserThreadImpl::ShutdownThreadPool() {
+ BrowserThreadGlobals& globals = g_globals.Get();
+ globals.blocking_pool->Shutdown();
+}
+
void BrowserThreadImpl::Init() {
+ BrowserThreadGlobals& globals = g_globals.Get();
+
using base::subtle::AtomicWord;
AtomicWord* storage =
- reinterpret_cast<AtomicWord*>(&g_browser_thread_delegates[identifier_]);
+ reinterpret_cast<AtomicWord*>(&globals.thread_delegates[identifier_]);
AtomicWord stored_pointer = base::subtle::NoBarrier_Load(storage);
BrowserThreadDelegate* delegate =
reinterpret_cast<BrowserThreadDelegate*>(stored_pointer);
@@ -74,9 +96,11 @@ void BrowserThreadImpl::Init() {
}
void BrowserThreadImpl::CleanUp() {
+ BrowserThreadGlobals& globals = g_globals.Get();
+
using base::subtle::AtomicWord;
AtomicWord* storage =
- reinterpret_cast<AtomicWord*>(&g_browser_thread_delegates[identifier_]);
+ reinterpret_cast<AtomicWord*>(&globals.thread_delegates[identifier_]);
AtomicWord stored_pointer = base::subtle::NoBarrier_Load(storage);
BrowserThreadDelegate* delegate =
reinterpret_cast<BrowserThreadDelegate*>(stored_pointer);
@@ -86,10 +110,12 @@ void BrowserThreadImpl::CleanUp() {
}
void BrowserThreadImpl::Initialize() {
- base::AutoLock lock(g_lock.Get());
+ BrowserThreadGlobals& globals = g_globals.Get();
+
+ base::AutoLock lock(globals.lock);
DCHECK(identifier_ >= 0 && identifier_ < ID_COUNT);
- DCHECK(g_browser_threads[identifier_] == NULL);
- g_browser_threads[identifier_] = this;
+ DCHECK(globals.threads[identifier_] == NULL);
+ globals.threads[identifier_] = this;
}
BrowserThreadImpl::~BrowserThreadImpl() {
@@ -98,12 +124,13 @@ BrowserThreadImpl::~BrowserThreadImpl() {
// the right BrowserThread.
Stop();
- base::AutoLock lock(g_lock.Get());
- g_browser_threads[identifier_] = NULL;
+ BrowserThreadGlobals& globals = g_globals.Get();
+ base::AutoLock lock(globals.lock);
+ globals.threads[identifier_] = NULL;
#ifndef NDEBUG
// Double check that the threads are ordered correctly in the enumeration.
for (int i = identifier_ + 1; i < ID_COUNT; ++i) {
- DCHECK(!g_browser_threads[i]) <<
+ DCHECK(!globals.threads[i]) <<
"Threads must be listed in the reverse order that they die";
}
#endif
@@ -128,11 +155,12 @@ bool BrowserThreadImpl::PostTaskHelper(
GetCurrentThreadIdentifier(&current_thread) &&
current_thread <= identifier;
+ BrowserThreadGlobals& globals = g_globals.Get();
if (!guaranteed_to_outlive_target_thread)
- g_lock.Get().Acquire();
+ globals.lock.Acquire();
- MessageLoop* message_loop = g_browser_threads[identifier] ?
- g_browser_threads[identifier]->message_loop() : NULL;
+ MessageLoop* message_loop = globals.threads[identifier] ?
+ globals.threads[identifier]->message_loop() : NULL;
if (message_loop) {
if (nestable) {
message_loop->PostDelayedTask(from_here, task, delay_ms);
@@ -142,7 +170,7 @@ bool BrowserThreadImpl::PostTaskHelper(
}
if (!guaranteed_to_outlive_target_thread)
- g_lock.Get().Release();
+ globals.lock.Release();
return !!message_loop;
}
@@ -189,10 +217,32 @@ class BrowserThreadMessageLoopProxy : public base::MessageLoopProxy {
};
// static
+bool BrowserThread::PostBlockingPoolTask(
+ const tracked_objects::Location& from_here,
+ const base::Closure& task) {
+ return g_globals.Get().blocking_pool->PostWorkerTask(from_here, task);
+}
+
+// static
+bool BrowserThread::PostBlockingPoolSequencedTask(
+ const std::string& sequence_token_name,
+ const tracked_objects::Location& from_here,
+ const base::Closure& task) {
+ return g_globals.Get().blocking_pool->PostNamedSequencedWorkerTask(
+ sequence_token_name, from_here, task);
+}
+
+// static
+base::SequencedWorkerPool* BrowserThread::GetBlockingPool() {
+ return g_globals.Get().blocking_pool;
+}
+
+// static
bool BrowserThread::IsWellKnownThread(ID identifier) {
- base::AutoLock lock(g_lock.Get());
+ BrowserThreadGlobals& globals = g_globals.Get();
+ base::AutoLock lock(globals.lock);
return (identifier >= 0 && identifier < ID_COUNT &&
- g_browser_threads[identifier]);
+ globals.threads[identifier]);
}
// static
@@ -202,19 +252,21 @@ bool BrowserThread::CurrentlyOn(ID identifier) {
// function.
// http://crbug.com/63678
base::ThreadRestrictions::ScopedAllowSingleton allow_singleton;
- base::AutoLock lock(g_lock.Get());
+ BrowserThreadGlobals& globals = g_globals.Get();
+ base::AutoLock lock(globals.lock);
DCHECK(identifier >= 0 && identifier < ID_COUNT);
- return g_browser_threads[identifier] &&
- g_browser_threads[identifier]->message_loop() ==
+ return globals.threads[identifier] &&
+ globals.threads[identifier]->message_loop() ==
MessageLoop::current();
}
// static
bool BrowserThread::IsMessageLoopValid(ID identifier) {
- base::AutoLock lock(g_lock.Get());
+ BrowserThreadGlobals& globals = g_globals.Get();
+ base::AutoLock lock(globals.lock);
DCHECK(identifier >= 0 && identifier < ID_COUNT);
- return g_browser_threads[identifier] &&
- g_browser_threads[identifier]->message_loop();
+ return globals.threads[identifier] &&
+ globals.threads[identifier]->message_loop();
}
// static
@@ -272,10 +324,11 @@ bool BrowserThread::GetCurrentThreadIdentifier(ID* identifier) {
// http://crbug.com/63678
base::ThreadRestrictions::ScopedAllowSingleton allow_singleton;
MessageLoop* cur_message_loop = MessageLoop::current();
+ BrowserThreadGlobals& globals = g_globals.Get();
for (int i = 0; i < ID_COUNT; ++i) {
- if (g_browser_threads[i] &&
- g_browser_threads[i]->message_loop() == cur_message_loop) {
- *identifier = g_browser_threads[i]->identifier_;
+ if (globals.threads[i] &&
+ globals.threads[i]->message_loop() == cur_message_loop) {
+ *identifier = globals.threads[i]->identifier_;
return true;
}
}
@@ -285,8 +338,7 @@ bool BrowserThread::GetCurrentThreadIdentifier(ID* identifier) {
// static
scoped_refptr<base::MessageLoopProxy>
-BrowserThread::GetMessageLoopProxyForThread(
- ID identifier) {
+BrowserThread::GetMessageLoopProxyForThread(ID identifier) {
scoped_refptr<base::MessageLoopProxy> proxy(
new BrowserThreadMessageLoopProxy(identifier));
return proxy;
@@ -294,8 +346,9 @@ BrowserThread::GetMessageLoopProxyForThread(
// static
MessageLoop* BrowserThread::UnsafeGetMessageLoopForThread(ID identifier) {
- base::AutoLock lock(g_lock.Get());
- base::Thread* thread = g_browser_threads[identifier];
+ BrowserThreadGlobals& globals = g_globals.Get();
+ base::AutoLock lock(globals.lock);
+ base::Thread* thread = globals.threads[identifier];
DCHECK(thread);
MessageLoop* loop = thread->message_loop();
return loop;
@@ -305,8 +358,9 @@ MessageLoop* BrowserThread::UnsafeGetMessageLoopForThread(ID identifier) {
void BrowserThread::SetDelegate(ID identifier,
BrowserThreadDelegate* delegate) {
using base::subtle::AtomicWord;
+ BrowserThreadGlobals& globals = g_globals.Get();
AtomicWord* storage = reinterpret_cast<AtomicWord*>(
- &g_browser_thread_delegates[identifier]);
+ &globals.thread_delegates[identifier]);
AtomicWord old_pointer = base::subtle::NoBarrier_AtomicExchange(
storage, reinterpret_cast<AtomicWord>(delegate));
diff --git a/content/browser/browser_thread_impl.h b/content/browser/browser_thread_impl.h
index feea986..4488f85 100644
--- a/content/browser/browser_thread_impl.h
+++ b/content/browser/browser_thread_impl.h
@@ -25,6 +25,8 @@ class CONTENT_EXPORT BrowserThreadImpl
BrowserThreadImpl(BrowserThread::ID identifier, MessageLoop* message_loop);
virtual ~BrowserThreadImpl();
+ static void ShutdownThreadPool();
+
protected:
virtual void Init() OVERRIDE;
virtual void CleanUp() OVERRIDE;