This source file includes following definitions.
- identifier_
- identifier_
- ShutdownThreadPool
- FlushThreadPoolHelper
- Init
- MSVC_DISABLE_OPTIMIZE
- DBThreadRun
- FileThreadRun
- FileUserBlockingThreadRun
- ProcessLauncherThreadRun
- CacheThreadRun
- IOThreadRun
- Run
- CleanUp
- Initialize
- PostTaskHelper
- PostDelayedTask
- PostNonNestableDelayedTask
- RunsTasksOnCurrentThread
- PostBlockingPoolTask
- PostBlockingPoolTaskAndReply
- PostBlockingPoolSequencedTask
- GetBlockingPool
- IsThreadInitialized
- CurrentlyOn
- GetThreadName
- GetDCheckCurrentlyOnErrorMessage
- IsMessageLoopValid
- PostTask
- PostDelayedTask
- PostNonNestableTask
- PostNonNestableDelayedTask
- PostTaskAndReply
- GetCurrentThreadIdentifier
- GetMessageLoopProxyForThread
- UnsafeGetMessageLoopForThread
- SetDelegate
#include "content/browser/browser_thread_impl.h"
#include <string>
#include "base/atomicops.h"
#include "base/bind.h"
#include "base/compiler_specific.h"
#include "base/lazy_instance.h"
#include "base/message_loop/message_loop.h"
#include "base/message_loop/message_loop_proxy.h"
#include "base/threading/sequenced_worker_pool.h"
#include "base/threading/thread_restrictions.h"
#include "content/public/browser/browser_thread_delegate.h"
namespace content {
namespace {
static const char* g_browser_thread_names[BrowserThread::ID_COUNT] = {
"",
"Chrome_DBThread",
"Chrome_FileThread",
"Chrome_FileUserBlockingThread",
"Chrome_ProcessLauncherThread",
"Chrome_CacheThread",
"Chrome_IOThread",
};
struct BrowserThreadGlobals {
BrowserThreadGlobals()
: blocking_pool(new base::SequencedWorkerPool(3, "BrowserBlocking")) {
memset(threads, 0, BrowserThread::ID_COUNT * sizeof(threads[0]));
memset(thread_delegates, 0,
BrowserThread::ID_COUNT * sizeof(thread_delegates[0]));
}
base::Lock lock;
BrowserThreadImpl* threads[BrowserThread::ID_COUNT];
BrowserThreadDelegate* thread_delegates[BrowserThread::ID_COUNT];
const scoped_refptr<base::SequencedWorkerPool> blocking_pool;
};
base::LazyInstance<BrowserThreadGlobals>::Leaky
g_globals = LAZY_INSTANCE_INITIALIZER;
}
BrowserThreadImpl::BrowserThreadImpl(ID identifier)
: Thread(g_browser_thread_names[identifier]),
identifier_(identifier) {
Initialize();
}
BrowserThreadImpl::BrowserThreadImpl(ID identifier,
base::MessageLoop* message_loop)
: Thread(message_loop->thread_name().c_str()), identifier_(identifier) {
set_message_loop(message_loop);
Initialize();
}
void BrowserThreadImpl::ShutdownThreadPool() {
const int kMaxNewShutdownBlockingTasks = 1000;
BrowserThreadGlobals& globals = g_globals.Get();
globals.blocking_pool->Shutdown(kMaxNewShutdownBlockingTasks);
}
void BrowserThreadImpl::FlushThreadPoolHelper() {
if (g_globals == NULL)
return;
g_globals.Get().blocking_pool->FlushForTesting();
}
void BrowserThreadImpl::Init() {
BrowserThreadGlobals& globals = g_globals.Get();
using base::subtle::AtomicWord;
AtomicWord* storage =
reinterpret_cast<AtomicWord*>(&globals.thread_delegates[identifier_]);
AtomicWord stored_pointer = base::subtle::NoBarrier_Load(storage);
BrowserThreadDelegate* delegate =
reinterpret_cast<BrowserThreadDelegate*>(stored_pointer);
if (delegate) {
delegate->Init();
message_loop()->PostTask(FROM_HERE,
base::Bind(&BrowserThreadDelegate::InitAsync,
base::Unretained(delegate)));
}
}
MSVC_DISABLE_OPTIMIZE()
MSVC_PUSH_DISABLE_WARNING(4748)
NOINLINE void BrowserThreadImpl::UIThreadRun(base::MessageLoop* message_loop) {
volatile int line_number = __LINE__;
Thread::Run(message_loop);
CHECK_GT(line_number, 0);
}
NOINLINE void BrowserThreadImpl::DBThreadRun(base::MessageLoop* message_loop) {
volatile int line_number = __LINE__;
Thread::Run(message_loop);
CHECK_GT(line_number, 0);
}
NOINLINE void BrowserThreadImpl::FileThreadRun(
base::MessageLoop* message_loop) {
volatile int line_number = __LINE__;
Thread::Run(message_loop);
CHECK_GT(line_number, 0);
}
NOINLINE void BrowserThreadImpl::FileUserBlockingThreadRun(
base::MessageLoop* message_loop) {
volatile int line_number = __LINE__;
Thread::Run(message_loop);
CHECK_GT(line_number, 0);
}
NOINLINE void BrowserThreadImpl::ProcessLauncherThreadRun(
base::MessageLoop* message_loop) {
volatile int line_number = __LINE__;
Thread::Run(message_loop);
CHECK_GT(line_number, 0);
}
NOINLINE void BrowserThreadImpl::CacheThreadRun(
base::MessageLoop* message_loop) {
volatile int line_number = __LINE__;
Thread::Run(message_loop);
CHECK_GT(line_number, 0);
}
NOINLINE void BrowserThreadImpl::IOThreadRun(base::MessageLoop* message_loop) {
volatile int line_number = __LINE__;
Thread::Run(message_loop);
CHECK_GT(line_number, 0);
}
MSVC_POP_WARNING()
MSVC_ENABLE_OPTIMIZE();
void BrowserThreadImpl::Run(base::MessageLoop* message_loop) {
BrowserThread::ID thread_id = ID_COUNT;
if (!GetCurrentThreadIdentifier(&thread_id))
return Thread::Run(message_loop);
switch (thread_id) {
case BrowserThread::UI:
return UIThreadRun(message_loop);
case BrowserThread::DB:
return DBThreadRun(message_loop);
case BrowserThread::FILE:
return FileThreadRun(message_loop);
case BrowserThread::FILE_USER_BLOCKING:
return FileUserBlockingThreadRun(message_loop);
case BrowserThread::PROCESS_LAUNCHER:
return ProcessLauncherThreadRun(message_loop);
case BrowserThread::CACHE:
return CacheThreadRun(message_loop);
case BrowserThread::IO:
return IOThreadRun(message_loop);
case BrowserThread::ID_COUNT:
CHECK(false);
break;
}
Thread::Run(message_loop);
}
void BrowserThreadImpl::CleanUp() {
BrowserThreadGlobals& globals = g_globals.Get();
using base::subtle::AtomicWord;
AtomicWord* storage =
reinterpret_cast<AtomicWord*>(&globals.thread_delegates[identifier_]);
AtomicWord stored_pointer = base::subtle::NoBarrier_Load(storage);
BrowserThreadDelegate* delegate =
reinterpret_cast<BrowserThreadDelegate*>(stored_pointer);
if (delegate)
delegate->CleanUp();
}
void BrowserThreadImpl::Initialize() {
BrowserThreadGlobals& globals = g_globals.Get();
base::AutoLock lock(globals.lock);
DCHECK(identifier_ >= 0 && identifier_ < ID_COUNT);
DCHECK(globals.threads[identifier_] == NULL);
globals.threads[identifier_] = this;
}
BrowserThreadImpl::~BrowserThreadImpl() {
Stop();
BrowserThreadGlobals& globals = g_globals.Get();
base::AutoLock lock(globals.lock);
globals.threads[identifier_] = NULL;
#ifndef NDEBUG
for (int i = identifier_ + 1; i < ID_COUNT; ++i) {
DCHECK(!globals.threads[i]) <<
"Threads must be listed in the reverse order that they die";
}
#endif
}
bool BrowserThreadImpl::PostTaskHelper(
BrowserThread::ID identifier,
const tracked_objects::Location& from_here,
const base::Closure& task,
base::TimeDelta delay,
bool nestable) {
DCHECK(identifier >= 0 && identifier < ID_COUNT);
BrowserThread::ID current_thread = ID_COUNT;
bool target_thread_outlives_current =
GetCurrentThreadIdentifier(¤t_thread) &&
current_thread >= identifier;
BrowserThreadGlobals& globals = g_globals.Get();
if (!target_thread_outlives_current)
globals.lock.Acquire();
base::MessageLoop* message_loop =
globals.threads[identifier] ? globals.threads[identifier]->message_loop()
: NULL;
if (message_loop) {
if (nestable) {
message_loop->PostDelayedTask(from_here, task, delay);
} else {
message_loop->PostNonNestableDelayedTask(from_here, task, delay);
}
}
if (!target_thread_outlives_current)
globals.lock.Release();
return !!message_loop;
}
class BrowserThreadMessageLoopProxy : public base::MessageLoopProxy {
public:
explicit BrowserThreadMessageLoopProxy(BrowserThread::ID identifier)
: id_(identifier) {
}
virtual bool PostDelayedTask(
const tracked_objects::Location& from_here,
const base::Closure& task, base::TimeDelta delay) OVERRIDE {
return BrowserThread::PostDelayedTask(id_, from_here, task, delay);
}
virtual bool PostNonNestableDelayedTask(
const tracked_objects::Location& from_here,
const base::Closure& task,
base::TimeDelta delay) OVERRIDE {
return BrowserThread::PostNonNestableDelayedTask(id_, from_here, task,
delay);
}
virtual bool RunsTasksOnCurrentThread() const OVERRIDE {
return BrowserThread::CurrentlyOn(id_);
}
protected:
virtual ~BrowserThreadMessageLoopProxy() {}
private:
BrowserThread::ID id_;
DISALLOW_COPY_AND_ASSIGN(BrowserThreadMessageLoopProxy);
};
bool BrowserThread::PostBlockingPoolTask(
const tracked_objects::Location& from_here,
const base::Closure& task) {
return g_globals.Get().blocking_pool->PostWorkerTask(from_here, task);
}
bool BrowserThread::PostBlockingPoolTaskAndReply(
const tracked_objects::Location& from_here,
const base::Closure& task,
const base::Closure& reply) {
return g_globals.Get().blocking_pool->PostTaskAndReply(
from_here, task, reply);
}
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);
}
base::SequencedWorkerPool* BrowserThread::GetBlockingPool() {
return g_globals.Get().blocking_pool.get();
}
bool BrowserThread::IsThreadInitialized(ID identifier) {
if (g_globals == NULL)
return false;
BrowserThreadGlobals& globals = g_globals.Get();
base::AutoLock lock(globals.lock);
DCHECK(identifier >= 0 && identifier < ID_COUNT);
return globals.threads[identifier] != NULL;
}
bool BrowserThread::CurrentlyOn(ID identifier) {
base::ThreadRestrictions::ScopedAllowSingleton allow_singleton;
BrowserThreadGlobals& globals = g_globals.Get();
base::AutoLock lock(globals.lock);
DCHECK(identifier >= 0 && identifier < ID_COUNT);
return globals.threads[identifier] &&
globals.threads[identifier]->message_loop() ==
base::MessageLoop::current();
}
static const char* GetThreadName(BrowserThread::ID thread) {
if (BrowserThread::UI < thread && thread < BrowserThread::ID_COUNT)
return g_browser_thread_names[thread];
if (thread == BrowserThread::UI)
return "Chrome_UIThread";
return "Unknown Thread";
}
std::string BrowserThread::GetDCheckCurrentlyOnErrorMessage(ID expected) {
const std::string& message_loop_name =
base::MessageLoop::current()->thread_name();
ID actual_browser_thread;
const char* actual_name = "Unknown Thread";
if (!message_loop_name.empty()) {
actual_name = message_loop_name.c_str();
} else if (GetCurrentThreadIdentifier(&actual_browser_thread)) {
actual_name = GetThreadName(actual_browser_thread);
}
std::string result = "Must be called on ";
result += GetThreadName(expected);
result += "; actually called on ";
result += actual_name;
result += ".";
return result;
}
bool BrowserThread::IsMessageLoopValid(ID identifier) {
if (g_globals == NULL)
return false;
BrowserThreadGlobals& globals = g_globals.Get();
base::AutoLock lock(globals.lock);
DCHECK(identifier >= 0 && identifier < ID_COUNT);
return globals.threads[identifier] &&
globals.threads[identifier]->message_loop();
}
bool BrowserThread::PostTask(ID identifier,
const tracked_objects::Location& from_here,
const base::Closure& task) {
return BrowserThreadImpl::PostTaskHelper(
identifier, from_here, task, base::TimeDelta(), true);
}
bool BrowserThread::PostDelayedTask(ID identifier,
const tracked_objects::Location& from_here,
const base::Closure& task,
base::TimeDelta delay) {
return BrowserThreadImpl::PostTaskHelper(
identifier, from_here, task, delay, true);
}
bool BrowserThread::PostNonNestableTask(
ID identifier,
const tracked_objects::Location& from_here,
const base::Closure& task) {
return BrowserThreadImpl::PostTaskHelper(
identifier, from_here, task, base::TimeDelta(), false);
}
bool BrowserThread::PostNonNestableDelayedTask(
ID identifier,
const tracked_objects::Location& from_here,
const base::Closure& task,
base::TimeDelta delay) {
return BrowserThreadImpl::PostTaskHelper(
identifier, from_here, task, delay, false);
}
bool BrowserThread::PostTaskAndReply(
ID identifier,
const tracked_objects::Location& from_here,
const base::Closure& task,
const base::Closure& reply) {
return GetMessageLoopProxyForThread(identifier)->PostTaskAndReply(from_here,
task,
reply);
}
bool BrowserThread::GetCurrentThreadIdentifier(ID* identifier) {
if (g_globals == NULL)
return false;
base::ThreadRestrictions::ScopedAllowSingleton allow_singleton;
base::MessageLoop* cur_message_loop = base::MessageLoop::current();
BrowserThreadGlobals& globals = g_globals.Get();
for (int i = 0; i < ID_COUNT; ++i) {
if (globals.threads[i] &&
globals.threads[i]->message_loop() == cur_message_loop) {
*identifier = globals.threads[i]->identifier_;
return true;
}
}
return false;
}
scoped_refptr<base::MessageLoopProxy>
BrowserThread::GetMessageLoopProxyForThread(ID identifier) {
return make_scoped_refptr(new BrowserThreadMessageLoopProxy(identifier));
}
base::MessageLoop* BrowserThread::UnsafeGetMessageLoopForThread(ID identifier) {
if (g_globals == NULL)
return NULL;
BrowserThreadGlobals& globals = g_globals.Get();
base::AutoLock lock(globals.lock);
base::Thread* thread = globals.threads[identifier];
DCHECK(thread);
base::MessageLoop* loop = thread->message_loop();
return loop;
}
void BrowserThread::SetDelegate(ID identifier,
BrowserThreadDelegate* delegate) {
using base::subtle::AtomicWord;
BrowserThreadGlobals& globals = g_globals.Get();
AtomicWord* storage = reinterpret_cast<AtomicWord*>(
&globals.thread_delegates[identifier]);
AtomicWord old_pointer = base::subtle::NoBarrier_AtomicExchange(
storage, reinterpret_cast<AtomicWord>(delegate));
DCHECK(!delegate || !old_pointer);
}
}