summaryrefslogtreecommitdiff
path: root/chromium/content/browser/browser_thread_impl.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/content/browser/browser_thread_impl.cc')
-rw-r--r--chromium/content/browser/browser_thread_impl.cc534
1 files changed, 121 insertions, 413 deletions
diff --git a/chromium/content/browser/browser_thread_impl.cc b/chromium/content/browser/browser_thread_impl.cc
index 566b0f7dafe..4443c7bbc4c 100644
--- a/chromium/content/browser/browser_thread_impl.cc
+++ b/chromium/content/browser/browser_thread_impl.cc
@@ -9,41 +9,21 @@
#include "base/atomicops.h"
#include "base/bind.h"
+#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
-#include "base/synchronization/waitable_event.h"
+#include "base/sequence_checker.h"
#include "base/threading/platform_thread.h"
+#include "base/time/time.h"
#include "build/build_config.h"
-#include "content/public/browser/browser_thread_delegate.h"
#include "content/public/browser/content_browser_client.h"
-#if defined(OS_ANDROID)
-#include "base/android/jni_android.h"
-#endif
-
namespace content {
namespace {
-// Friendly names for the well-known threads.
-static const char* const g_browser_thread_names[BrowserThread::ID_COUNT] = {
- "", // UI (name assembled in browser_main.cc).
- "Chrome_ProcessLauncherThread", // PROCESS_LAUNCHER
- "Chrome_IOThread", // IO
-};
-
-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";
-}
-
// An implementation of SingleThreadTaskRunner to be used in conjunction
// with BrowserThread.
// TODO(gab): Consider replacing this with |g_globals->task_runners| -- only
@@ -101,389 +81,149 @@ base::LazyInstance<BrowserThreadTaskRunners>::Leaky g_task_runners =
enum BrowserThreadState {
// BrowserThread::ID isn't associated with anything yet.
UNINITIALIZED = 0,
- // BrowserThread::ID is associated with a BrowserThreadImpl instance but the
- // underlying thread hasn't started yet.
- INITIALIZED,
// BrowserThread::ID is associated to a TaskRunner and is accepting tasks.
RUNNING,
- // BrowserThread::ID no longer accepts tasks.
+ // BrowserThread::ID no longer accepts tasks (it's still associated to a
+ // TaskRunner but that TaskRunner doesn't have to accept tasks).
SHUTDOWN
};
-using BrowserThreadDelegateAtomicPtr = base::subtle::AtomicWord;
-
struct BrowserThreadGlobals {
- // This lock protects |task_runners| and |states|. Do not read or modify those
- // arrays without holding this lock. Do not block while holding this lock.
- base::Lock lock;
-
- // This array is filled either as the underlying threads start and invoke
- // Init() or in RedirectThreadIDToTaskRunner() for threads that are being
- // redirected. It is not emptied during shutdown in order to support
- // RunsTasksInCurrentSequence() until the very end.
- scoped_refptr<base::SingleThreadTaskRunner>
- task_runners[BrowserThread::ID_COUNT];
-
- // Holds the state of each BrowserThread::ID.
- BrowserThreadState states[BrowserThread::ID_COUNT] = {};
+ BrowserThreadGlobals() {
+ // A few unit tests which do not use a TestBrowserThreadBundle still invoke
+ // code that reaches into CurrentlyOn()/IsThreadInitialized(). This can
+ // result in instantiating BrowserThreadGlobals off the main thread.
+ // |main_thread_checker_| being bound incorrectly would then result in a
+ // flake in the next test that instantiates a TestBrowserThreadBundle in the
+ // same process. Detaching here postpones binding |main_thread_checker_| to
+ // the first invocation of BrowserThreadImpl::BrowserThreadImpl() and works
+ // around this issue.
+ DETACH_FROM_THREAD(main_thread_checker_);
+ }
- // Only atomic operations are used on this pointer. The delegate isn't owned
- // by BrowserThreadGlobals, rather by whoever calls
- // BrowserThread::SetIOThreadDelegate.
- BrowserThreadDelegateAtomicPtr io_thread_delegate = 0;
+ // BrowserThreadGlobals must be initialized on main thread before it's used by
+ // any other threads.
+ THREAD_CHECKER(main_thread_checker_);
- // This locks protects |is_io_thread_initialized|. Do not read or modify this
- // variable without holding this lock.
- base::Lock io_thread_lock;
+ // |task_runners[id]| is safe to access on |main_thread_checker_| as
+ // well as on any thread once it's read-only after initialization
+ // (i.e. while |states[id] >= RUNNING|).
+ scoped_refptr<base::SingleThreadTaskRunner>
+ task_runners[BrowserThread::ID_COUNT];
- // A flag indicates whether the BrowserThreadDelegate of the BrowserThread::IO
- // thread has been initialized.
- bool is_io_thread_initialized = false;
+ // Tracks the runtime state of BrowserThreadImpls. Atomic because a few
+ // methods below read this value outside |main_thread_checker_| to
+ // confirm it's >= RUNNING and doing so requires an atomic read as it could be
+ // in the middle of transitioning to SHUTDOWN (which the check is fine with
+ // but reading a non-atomic value as it's written to by another thread can
+ // result in undefined behaviour on some platforms).
+ // Only NoBarrier atomic operations should be used on |states| as it shouldn't
+ // be used to establish happens-after relationships but rather checking the
+ // runtime state of various threads (once again: it's only atomic to support
+ // reading while transitioning from RUNNING=>SHUTDOWN).
+ base::subtle::Atomic32 states[BrowserThread::ID_COUNT] = {};
};
base::LazyInstance<BrowserThreadGlobals>::Leaky
g_globals = LAZY_INSTANCE_INITIALIZER;
-void InitIOThreadDelegateOnIOThread() {
- BrowserThreadDelegateAtomicPtr delegate =
- base::subtle::NoBarrier_Load(&g_globals.Get().io_thread_delegate);
- if (delegate)
- reinterpret_cast<BrowserThreadDelegate*>(delegate)->Init();
-}
-
-bool IsIOThreadInitialized() {
- BrowserThreadGlobals& globals = g_globals.Get();
- base::AutoLock lock(globals.io_thread_lock);
- return globals.is_io_thread_initialized;
-}
-
-void SetIsIOThreadInitialized(bool is_io_thread_initialized) {
- BrowserThreadGlobals& globals = g_globals.Get();
- base::AutoLock lock(globals.io_thread_lock);
- globals.is_io_thread_initialized = is_io_thread_initialized;
-}
-
-} // namespace
-
-BrowserThreadImpl::BrowserThreadImpl(ID identifier)
- : Thread(GetThreadName(identifier)), identifier_(identifier) {
- Initialize();
-}
-
-BrowserThreadImpl::BrowserThreadImpl(ID identifier,
- base::MessageLoop* message_loop)
- : Thread(GetThreadName(identifier)), identifier_(identifier) {
- SetMessageLoop(message_loop);
- Initialize();
+bool PostTaskHelper(BrowserThread::ID identifier,
+ const base::Location& from_here,
+ base::OnceClosure task,
+ base::TimeDelta delay,
+ bool nestable) {
+ DCHECK_GE(identifier, 0);
+ DCHECK_LT(identifier, BrowserThread::ID_COUNT);
- // If constructed with an explicit message loop, this is a fake
- // BrowserThread which runs on the current thread.
BrowserThreadGlobals& globals = g_globals.Get();
- base::AutoLock lock(globals.lock);
-
- DCHECK(!globals.task_runners[identifier_]);
- globals.task_runners[identifier_] = task_runner();
- DCHECK_EQ(globals.states[identifier_], BrowserThreadState::INITIALIZED);
- globals.states[identifier_] = BrowserThreadState::RUNNING;
-}
-
-void BrowserThreadImpl::Init() {
-#if DCHECK_IS_ON()
- {
- BrowserThreadGlobals& globals = g_globals.Get();
- base::AutoLock lock(globals.lock);
- // |globals| should already have been initialized for |identifier_| in
- // BrowserThreadImpl::StartWithOptions(). If this isn't the case it's likely
- // because this BrowserThreadImpl's owner incorrectly used Thread::Start.*()
- // instead of BrowserThreadImpl::Start.*().
- DCHECK_EQ(globals.states[identifier_], BrowserThreadState::RUNNING);
- DCHECK(globals.task_runners[identifier_]);
- DCHECK(globals.task_runners[identifier_]->RunsTasksInCurrentSequence());
- }
-#endif // DCHECK_IS_ON()
-
- if (identifier_ == BrowserThread::PROCESS_LAUNCHER) {
- // Nesting and task observers are not allowed on redirected threads.
- base::RunLoop::DisallowNestingOnCurrentThread();
- message_loop()->DisallowTaskObservers();
- }
-}
-
-// We disable optimizations for this block of functions so the compiler doesn't
-// merge them all together.
-MSVC_DISABLE_OPTIMIZE()
-MSVC_PUSH_DISABLE_WARNING(4748)
-
-NOINLINE void BrowserThreadImpl::UIThreadRun(base::RunLoop* run_loop) {
- volatile int line_number = __LINE__;
- Thread::Run(run_loop);
- CHECK_GT(line_number, 0);
-}
-
-NOINLINE void BrowserThreadImpl::ProcessLauncherThreadRun(
- base::RunLoop* run_loop) {
- volatile int line_number = __LINE__;
- Thread::Run(run_loop);
- CHECK_GT(line_number, 0);
-}
-
-NOINLINE void BrowserThreadImpl::IOThreadRun(base::RunLoop* run_loop) {
- volatile int line_number = __LINE__;
- Thread::Run(run_loop);
- CHECK_GT(line_number, 0);
-}
-
-MSVC_POP_WARNING()
-MSVC_ENABLE_OPTIMIZE();
-
-void BrowserThreadImpl::Run(base::RunLoop* run_loop) {
-#if defined(OS_ANDROID)
- // Not to reset thread name to "Thread-???" by VM, attach VM with thread name.
- // Though it may create unnecessary VM thread objects, keeping thread name
- // gives more benefit in debugging in the platform.
- if (!thread_name().empty()) {
- base::android::AttachCurrentThreadWithName(thread_name());
- }
-#endif
-
- BrowserThread::ID thread_id = ID_COUNT;
- CHECK(GetCurrentThreadIdentifier(&thread_id));
- CHECK_EQ(identifier_, thread_id);
-
- switch (identifier_) {
- case BrowserThread::UI:
- return UIThreadRun(run_loop);
- case BrowserThread::PROCESS_LAUNCHER:
- return ProcessLauncherThreadRun(run_loop);
- case BrowserThread::IO:
- return IOThreadRun(run_loop);
- case BrowserThread::ID_COUNT:
- CHECK(false); // This shouldn't actually be reached!
- break;
- }
-
- // |identifier_| must be set to a valid enum value in the constructor, so it
- // should be impossible to reach here.
- CHECK(false);
-}
-
-void BrowserThreadImpl::CleanUp() {
- BrowserThreadGlobals& globals = g_globals.Get();
+ // Tasks should always be posted while the BrowserThread is in a RUNNING or
+ // SHUTDOWN state (will return false if SHUTDOWN).
+ //
+ // Posting tasks before BrowserThreads are initialized is incorrect as it
+ // would silently no-op. If you need to support posting early, gate it on
+ // BrowserThread::IsThreadInitialized(). If you hit this check in unittests,
+ // you most likely posted a task outside the scope of a
+ // TestBrowserThreadBundle (which also completely resets the state after
+ // shutdown in ~TestBrowserThreadBundle(), ref. ResetGlobalsForTesting(),
+ // making sure TestBrowserThreadBundle is the first member of your test
+ // fixture and thus outlives everything is usually the right solution).
+ DCHECK_GE(base::subtle::NoBarrier_Load(&globals.states[identifier]),
+ BrowserThreadState::RUNNING);
+ DCHECK(globals.task_runners[identifier]);
- if (identifier_ == BrowserThread::IO && IsIOThreadInitialized()) {
- BrowserThreadDelegateAtomicPtr delegate =
- base::subtle::NoBarrier_Load(&globals.io_thread_delegate);
- if (delegate)
- reinterpret_cast<BrowserThreadDelegate*>(delegate)->CleanUp();
- SetIsIOThreadInitialized(false);
+ if (nestable) {
+ return globals.task_runners[identifier]->PostDelayedTask(
+ from_here, std::move(task), delay);
+ } else {
+ return globals.task_runners[identifier]->PostNonNestableDelayedTask(
+ from_here, std::move(task), delay);
}
-
- // Change the state to SHUTDOWN so that PostTaskHelper stops accepting tasks
- // for this thread. Do not clear globals.task_runners[identifier_] so that
- // BrowserThread::CurrentlyOn() works from the MessageLoop's
- // DestructionObservers.
- base::AutoLock lock(globals.lock);
- DCHECK_EQ(globals.states[identifier_], BrowserThreadState::RUNNING);
- globals.states[identifier_] = BrowserThreadState::SHUTDOWN;
}
-void BrowserThreadImpl::Initialize() {
- BrowserThreadGlobals& globals = g_globals.Get();
+} // namespace
- base::AutoLock lock(globals.lock);
+BrowserThreadImpl::BrowserThreadImpl(
+ ID identifier,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner)
+ : identifier_(identifier) {
DCHECK_GE(identifier_, 0);
DCHECK_LT(identifier_, ID_COUNT);
- DCHECK_EQ(globals.states[identifier_], BrowserThreadState::UNINITIALIZED);
- globals.states[identifier_] = BrowserThreadState::INITIALIZED;
-}
+ DCHECK(task_runner);
-// static
-void BrowserThreadImpl::ResetGlobalsForTesting(BrowserThread::ID identifier) {
BrowserThreadGlobals& globals = g_globals.Get();
- base::AutoLock lock(globals.lock);
- DCHECK_EQ(globals.states[identifier], BrowserThreadState::SHUTDOWN);
- globals.states[identifier] = BrowserThreadState::UNINITIALIZED;
- globals.task_runners[identifier] = nullptr;
- if (identifier == BrowserThread::IO)
- SetIOThreadDelegate(nullptr);
-}
+ DCHECK_CALLED_ON_VALID_THREAD(globals.main_thread_checker_);
-void BrowserThreadImpl::InitIOThreadDelegate() {
- DCHECK(!IsIOThreadInitialized());
+ DCHECK_EQ(base::subtle::NoBarrier_Load(&globals.states[identifier_]),
+ BrowserThreadState::UNINITIALIZED);
+ base::subtle::NoBarrier_Store(&globals.states[identifier_],
+ BrowserThreadState::RUNNING);
- SetIsIOThreadInitialized(true);
- BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
- base::BindOnce(&InitIOThreadDelegateOnIOThread));
+ DCHECK(!globals.task_runners[identifier_]);
+ globals.task_runners[identifier_] = std::move(task_runner);
}
BrowserThreadImpl::~BrowserThreadImpl() {
- // All Thread subclasses must call Stop() in the destructor. This is
- // doubly important here as various bits of code check they are on
- // the right BrowserThread.
- Stop();
-
- BrowserThreadGlobals& globals = g_globals.Get();
- base::AutoLock lock(globals.lock);
- // This thread should have gone through Cleanup() as part of Stop() and be in
- // the SHUTDOWN state already (unless it uses an externally provided
- // MessageLoop instead of a real underlying thread and thus doesn't go through
- // Cleanup()).
- if (using_external_message_loop()) {
- DCHECK_EQ(globals.states[identifier_], BrowserThreadState::RUNNING);
- globals.states[identifier_] = BrowserThreadState::SHUTDOWN;
- } else {
- DCHECK_EQ(globals.states[identifier_], BrowserThreadState::SHUTDOWN);
- }
-#if DCHECK_IS_ON()
- // Double check that the threads are ordered correctly in the enumeration.
- for (int i = identifier_ + 1; i < ID_COUNT; ++i) {
- DCHECK(globals.states[i] == BrowserThreadState::SHUTDOWN ||
- globals.states[i] == BrowserThreadState::UNINITIALIZED)
- << "Threads must be listed in the reverse order that they die";
- }
-#endif
-}
-
-bool BrowserThreadImpl::Start() {
- return StartWithOptions(base::Thread::Options());
-}
-
-bool BrowserThreadImpl::StartWithOptions(const Options& options) {
BrowserThreadGlobals& globals = g_globals.Get();
+ DCHECK_CALLED_ON_VALID_THREAD(globals.main_thread_checker_);
- // Holding the lock is necessary when kicking off the thread to ensure
- // |states| and |task_runners| are updated before it gets to query them.
- base::AutoLock lock(globals.lock);
+ DCHECK_EQ(base::subtle::NoBarrier_Load(&globals.states[identifier_]),
+ BrowserThreadState::RUNNING);
+ base::subtle::NoBarrier_Store(&globals.states[identifier_],
+ BrowserThreadState::SHUTDOWN);
- bool result = Thread::StartWithOptions(options);
-
- // Although the thread is starting asynchronously, the MessageLoop is already
- // ready to accept tasks and as such this BrowserThreadImpl is considered as
- // "running".
- DCHECK(!globals.task_runners[identifier_]);
- globals.task_runners[identifier_] = task_runner();
+ // The mapping is kept alive after shutdown to avoid requiring a lock only for
+ // shutdown (the SingleThreadTaskRunner itself may stop accepting tasks at any
+ // point -- usually soon before/after destroying the BrowserThreadImpl).
DCHECK(globals.task_runners[identifier_]);
-
- DCHECK_EQ(globals.states[identifier_], BrowserThreadState::INITIALIZED);
- globals.states[identifier_] = BrowserThreadState::RUNNING;
-
- return result;
-}
-
-bool BrowserThreadImpl::StartAndWaitForTesting() {
- if (!Start())
- return false;
- WaitUntilThreadStarted();
- return true;
-}
-
-// static
-void BrowserThreadImpl::RedirectThreadIDToTaskRunner(
- BrowserThread::ID identifier,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
- DCHECK(task_runner);
-
- BrowserThreadGlobals& globals = g_globals.Get();
- base::AutoLock lock(globals.lock);
-
- DCHECK(!globals.task_runners[identifier]);
- DCHECK_EQ(globals.states[identifier], BrowserThreadState::UNINITIALIZED);
-
- globals.task_runners[identifier] = std::move(task_runner);
- globals.states[identifier] = BrowserThreadState::RUNNING;
}
// static
-void BrowserThreadImpl::StopRedirectionOfThreadID(
- BrowserThread::ID identifier) {
+void BrowserThreadImpl::ResetGlobalsForTesting(BrowserThread::ID identifier) {
BrowserThreadGlobals& globals = g_globals.Get();
- base::AutoLock auto_lock(globals.lock);
-
- DCHECK(globals.task_runners[identifier]);
+ DCHECK_CALLED_ON_VALID_THREAD(globals.main_thread_checker_);
- // Change the state to SHUTDOWN to stop accepting new tasks. Note: this is
- // different from non-redirected threads which continue accepting tasks while
- // being joined and only quit when idle. However, any tasks for which this
- // difference matters was already racy as any thread posting a task after the
- // Signal task below can't be synchronized with the joining thread. Therefore,
- // that task could already come in before or after the join had completed in
- // the non-redirection world. Entering SHUTDOWN early merely skews this race
- // towards making it less likely such a task is accepted by the joined thread
- // which is fine.
- DCHECK_EQ(globals.states[identifier], BrowserThreadState::RUNNING);
- globals.states[identifier] = BrowserThreadState::SHUTDOWN;
-
- // Wait for all pending tasks to complete.
- base::WaitableEvent flushed(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
- globals.task_runners[identifier]->PostTask(
- FROM_HERE,
- base::BindOnce(&base::WaitableEvent::Signal, base::Unretained(&flushed)));
- {
- base::AutoUnlock auto_unlock(globals.lock);
- flushed.Wait();
- }
+ DCHECK_EQ(base::subtle::NoBarrier_Load(&globals.states[identifier]),
+ BrowserThreadState::SHUTDOWN);
+ base::subtle::NoBarrier_Store(&globals.states[identifier],
+ BrowserThreadState::UNINITIALIZED);
- // Only reset the task runner after running pending tasks so that
- // BrowserThread::CurrentlyOn() works in their scope.
globals.task_runners[identifier] = nullptr;
-
- // Note: it's still possible for tasks to be posted to that task runner after
- // this point (e.g. through a previously obtained ThreadTaskRunnerHandle or by
- // one of the last tasks re-posting to its ThreadTaskRunnerHandle) but the
- // BrowserThread API itself won't accept tasks. Such tasks are ultimately
- // guaranteed to run before TaskScheduler::Shutdown() returns but may break
- // the assumption in PostTaskHelper that BrowserThread::ID A > B will always
- // succeed to post to B. This is pretty much the only observable difference
- // between a redirected thread and a real one and is one we're willing to live
- // with for this experiment. TODO(gab): fix this before enabling the
- // experiment by default on trunk, http://crbug.com/653916.
}
// static
-bool BrowserThreadImpl::PostTaskHelper(BrowserThread::ID identifier,
- const base::Location& from_here,
- base::OnceClosure task,
- base::TimeDelta delay,
- bool nestable) {
- DCHECK_GE(identifier, 0);
- DCHECK_LT(identifier, ID_COUNT);
- // Optimization: to avoid unnecessary locks, we listed the ID enumeration in
- // order of lifetime. So no need to lock if we know that the target thread
- // outlives current thread as that implies the current thread only ever sees
- // the target thread in its RUNNING state.
- // Note: since the array is so small, ok to loop instead of creating a map,
- // which would require a lock because std::map isn't thread safe, defeating
- // the whole purpose of this optimization.
- BrowserThread::ID current_thread = ID_COUNT;
- bool target_thread_outlives_current =
- GetCurrentThreadIdentifier(&current_thread) &&
- current_thread >= identifier;
+const char* BrowserThreadImpl::GetThreadName(BrowserThread::ID thread) {
+ static const char* const kBrowserThreadNames[BrowserThread::ID_COUNT] = {
+ "", // UI (name assembled in browser_main_loop.cc).
+ "Chrome_IOThread", // IO
+ };
- BrowserThreadGlobals& globals = g_globals.Get();
- if (!target_thread_outlives_current)
- globals.lock.Acquire();
-
- const bool accepting_tasks =
- globals.states[identifier] == BrowserThreadState::RUNNING;
- if (accepting_tasks) {
- base::SingleThreadTaskRunner* task_runner =
- globals.task_runners[identifier].get();
- DCHECK(task_runner);
- if (nestable) {
- task_runner->PostDelayedTask(from_here, std::move(task), delay);
- } else {
- task_runner->PostNonNestableDelayedTask(from_here, std::move(task),
- delay);
- }
- }
-
- if (!target_thread_outlives_current)
- globals.lock.Release();
-
- return accepting_tasks;
+ if (BrowserThread::UI < thread && thread < BrowserThread::ID_COUNT)
+ return kBrowserThreadNames[thread];
+ if (thread == BrowserThread::UI)
+ return "Chrome_UIThread";
+ return "Unknown Thread";
}
// static
@@ -497,28 +237,25 @@ void BrowserThread::PostAfterStartupTask(
// static
bool BrowserThread::IsThreadInitialized(ID identifier) {
- if (!g_globals.IsCreated())
- return false;
-
- BrowserThreadGlobals& globals = g_globals.Get();
- base::AutoLock lock(globals.lock);
DCHECK_GE(identifier, 0);
DCHECK_LT(identifier, ID_COUNT);
- bool running =
- globals.states[identifier] == BrowserThreadState::INITIALIZED ||
- globals.states[identifier] == BrowserThreadState::RUNNING;
- if (identifier != BrowserThread::IO)
- return running;
- return running && IsIOThreadInitialized();
+ BrowserThreadGlobals& globals = g_globals.Get();
+ return base::subtle::NoBarrier_Load(&globals.states[identifier]) ==
+ BrowserThreadState::RUNNING;
}
// static
bool BrowserThread::CurrentlyOn(ID identifier) {
- BrowserThreadGlobals& globals = g_globals.Get();
- base::AutoLock lock(globals.lock);
DCHECK_GE(identifier, 0);
DCHECK_LT(identifier, ID_COUNT);
+
+ BrowserThreadGlobals& globals = g_globals.Get();
+
+ // Thread-safe since |globals.task_runners| is read-only after being
+ // initialized from main thread (which happens before //content and embedders
+ // are kicked off and enabled to call the BrowserThread API from other
+ // threads).
return globals.task_runners[identifier] &&
globals.task_runners[identifier]->RunsTasksInCurrentSequence();
}
@@ -530,31 +267,18 @@ std::string BrowserThread::GetDCheckCurrentlyOnErrorMessage(ID expected) {
actual_name = "Unknown Thread";
std::string result = "Must be called on ";
- result += GetThreadName(expected);
+ result += BrowserThreadImpl::GetThreadName(expected);
result += "; actually called on ";
result += actual_name;
result += ".";
return result;
}
-// static
-bool BrowserThread::IsMessageLoopValid(ID identifier) {
- if (!g_globals.IsCreated())
- return false;
-
- BrowserThreadGlobals& globals = g_globals.Get();
- base::AutoLock lock(globals.lock);
- DCHECK_GE(identifier, 0);
- DCHECK_LT(identifier, ID_COUNT);
- return globals.states[identifier] == BrowserThreadState::RUNNING;
-}
-
-// static
bool BrowserThread::PostTask(ID identifier,
const base::Location& from_here,
base::OnceClosure task) {
- return BrowserThreadImpl::PostTaskHelper(
- identifier, from_here, std::move(task), base::TimeDelta(), true);
+ return PostTaskHelper(identifier, from_here, std::move(task),
+ base::TimeDelta(), true);
}
// static
@@ -562,16 +286,15 @@ bool BrowserThread::PostDelayedTask(ID identifier,
const base::Location& from_here,
base::OnceClosure task,
base::TimeDelta delay) {
- return BrowserThreadImpl::PostTaskHelper(identifier, from_here,
- std::move(task), delay, true);
+ return PostTaskHelper(identifier, from_here, std::move(task), delay, true);
}
// static
bool BrowserThread::PostNonNestableTask(ID identifier,
const base::Location& from_here,
base::OnceClosure task) {
- return BrowserThreadImpl::PostTaskHelper(
- identifier, from_here, std::move(task), base::TimeDelta(), false);
+ return PostTaskHelper(identifier, from_here, std::move(task),
+ base::TimeDelta(), false);
}
// static
@@ -579,8 +302,7 @@ bool BrowserThread::PostNonNestableDelayedTask(ID identifier,
const base::Location& from_here,
base::OnceClosure task,
base::TimeDelta delay) {
- return BrowserThreadImpl::PostTaskHelper(identifier, from_here,
- std::move(task), delay, false);
+ return PostTaskHelper(identifier, from_here, std::move(task), delay, false);
}
// static
@@ -594,14 +316,12 @@ bool BrowserThread::PostTaskAndReply(ID identifier,
// static
bool BrowserThread::GetCurrentThreadIdentifier(ID* identifier) {
- if (!g_globals.IsCreated())
- return false;
-
BrowserThreadGlobals& globals = g_globals.Get();
- // Profiler to track potential contention on |globals.lock|. This only does
- // real work on canary and local dev builds, so the cost of having this here
- // should be minimal.
- base::AutoLock lock(globals.lock);
+
+ // Thread-safe since |globals.task_runners| is read-only after being
+ // initialized from main thread (which happens before //content and embedders
+ // are kicked off and enabled to call the BrowserThread API from other
+ // threads).
for (int i = 0; i < ID_COUNT; ++i) {
if (globals.task_runners[i] &&
globals.task_runners[i]->RunsTasksInCurrentSequence()) {
@@ -619,16 +339,4 @@ BrowserThread::GetTaskRunnerForThread(ID identifier) {
return g_task_runners.Get().proxies[identifier];
}
-// static
-void BrowserThread::SetIOThreadDelegate(BrowserThreadDelegate* delegate) {
- BrowserThreadGlobals& globals = g_globals.Get();
- BrowserThreadDelegateAtomicPtr old_delegate =
- base::subtle::NoBarrier_AtomicExchange(
- &globals.io_thread_delegate,
- reinterpret_cast<BrowserThreadDelegateAtomicPtr>(delegate));
-
- // This catches registration when previously registered.
- DCHECK(!delegate || !old_delegate);
-}
-
} // namespace content