diff options
Diffstat (limited to 'chromium/content/browser/browser_thread_impl.cc')
-rw-r--r-- | chromium/content/browser/browser_thread_impl.cc | 534 |
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(¤t_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 |