Reland "Refactor BrowserThreadImpl, BrowserProcessSubThread, and BrowserMainLoop"
This is a reland of d260e9cf660f062b203692601cf9b6ccb27f3d1e
It was reverted because of crbug.com/824716, these weren't new crashes
but known crashes mislabeled as a fallout of this change.
http://cl/190471699 fixes the crash backend to not rely on
"content::BrowserThreadImpl::IOThreadRun" being in the signature.
Only diff in this CL is to use base::debug::Alias() in methods that we
don't want optimized (i.e. IOThreadRun) out as CHECK_GT was seen as
optimized out in some of the reported crashes (even though the same
pattern as before was used by this CL..?)
Original change's description:
> Refactor BrowserThreadImpl, BrowserProcessSubThread, and BrowserMainLoop
>
> This brings back the invariant that BrowserThread::IO isn't available
> before BrowserMainLoop::CreateThreads(). This was broken to fix issue
> 729596 to bring up the thread earlier for ServiceManager but it is
> important that code that posts to BrowserThread::IO statically have an
> happens-after relationship to BrowserMainLoop::CreateThreads(). Exposing
> it statically earlier put that invariant at risk.
>
> Thankfully fixing issue 815225 resulted in finally reaching the long
> sought goal of only having BrowserThread::UI/IO. Now that the IO thread
> is also kicked off before it's named statically, BrowserThreadImpl no
> longer needs to be a base::Thread, hence this refactoring.
>
> Before this CL:
> * BrowserThreadImpl was a base::Thread
> (could be a fake thread if SetMessageLoop was used)
> * BrowserProcessSubThread was a BrowserThreadImpl
> (performed a bit more initialization)
> * BrowserProcessSubThread was only used in production (in
> BrowserMainLoop)
> * BrowserThreadImpl was used for fake threads (BrowserMainLoop for
> BrowserThread::UI) and for testing (TestBrowserThread(Impl)).
> * BrowserThreadImpl overrode Init/Run/CleanUp() from base::Thread to
> perform some sanity checks as well as drive IOThread's Delegate (ref.
> BrowserThread::SetIOThreadDelegate())
> * BrowserProcessSubThread re-overrode Init/Run/CleanUp() to perform
> per-thread //content initialization (tests missed out on that per
> TestBrowserThread bypassing BrowserProcessSubThread by directly
> subclassing BrowserThreadImpl).
>
> With this CL:
> * BrowserThreadImpl is merely a scoped object that binds a provided
> SingleThreadTaskRunner to a BrowserThread::ID.
> * BrowserProcessSubThread is a base::Thread and performs all of the
> initialization and cleanup specific to //content (this means it now
> also manages BrowserThread::SetIOThreadDelegate())
> * BrowserProcessSubThread can be brought up early before being bound to
> a BrowserThread::ID (BrowserMainLoop handles that through
> BrowserProcessSubThread ::RegisterAsBrowserThread())
>
> Unfortunate exceptions required for this CL:
> * IOThread::Init() (invoked through BrowserThreadDelegate) perfoms
> blocking operations this was previously performed before installed
> the ThreadRestrictions on BrowserThread::IO. But now that //content
> is initialized after bringing up the thread, a
> base::ScopedAllowBlocking is required in scope of IOThread::Init().
> * TestBrowserThread previously bypassing BrowserProcessSubThread by
> directly subclassing BrowserThreadImpl meant it wasn't subject to
> ThreadRestrictions (unfortunate becomes it denies allowance
> verification to product code running in unit tests). Adding it back
> causes DCHECKs, as such
> BrowserProcessSubThread::AllowBlockingForTesting was added to allow
> this CL to pass CQ.
>
> Of note:
> * BrowserProcessSubThread is still written as though it supports many
> BrowserThread::IDs but in practice it's mostly always
> BrowserThread::IO (except in ThreadWatcherTest I think). This change
> was big enough that I didn't bother also breaking that
> generalization.
> * BrowserThreadImpl's constructor was made private to ensure only
> BrowserProcessSubThread and a few select callers get to drive it (to
> avoid previous missed initialization issues)
> * Atomics to manage BrowserThread::SetIOThreadDelegate were removed.
> Restriction was instead added that this only be called before
> initialization and after shutdown (this was already the case).
>
> Follow-ups to this CL:
> * //ios duplicates this logic and will need to undergo the same change
> as a follow-up
> * Fixing ios will allow removal of base::Thread::SetMessageLoop hack :)
> * Removing BrowserThreadGlobals::lock_ to address crbug.com/821034 will
> be much easier
> * BrowserThread post APIs should DCHECK rather than no-op if using a
> BrowserThread::ID before it's registered.
>
> Bug: 815225, 821034, 729596
> Change-Id: If1038f23079df72203b1e95c7d26647f8824a726
> Reviewed-on: https://chromium-review.googlesource.com/969104
> Reviewed-by: John Abd-El-Malek <[email protected]>
> Commit-Queue: Gabriel Charette <[email protected]>
> Cr-Commit-Position: refs/heads/master@{#544440}
[email protected]
Bug: 815225, 821034, 729596, 824716
Change-Id: I9a180975c69a008f8519d1d3d44663aa58a74a92
Reviewed-on: https://chromium-review.googlesource.com/980793
Reviewed-by: John Abd-El-Malek <[email protected]>
Reviewed-by: Gabriel Charette <[email protected]>
Commit-Queue: Gabriel Charette <[email protected]>
Cr-Commit-Position: refs/heads/master@{#546104}
diff --git a/content/browser/browser_process_sub_thread.h b/content/browser/browser_process_sub_thread.h
index 8122cdb..f4b8799 100644
--- a/content/browser/browser_process_sub_thread.h
+++ b/content/browser/browser_process_sub_thread.h
@@ -8,8 +8,9 @@
#include <memory>
#include "base/macros.h"
+#include "base/threading/thread.h"
+#include "base/threading/thread_checker.h"
#include "build/build_config.h"
-#include "content/browser/browser_thread_impl.h"
#include "content/common/content_export.h"
#include "content/public/browser/browser_thread.h"
@@ -28,29 +29,57 @@
namespace content {
// ----------------------------------------------------------------------------
-// BrowserProcessSubThread
-//
-// This simple thread object is used for the specialized threads that the
-// BrowserProcess spins up.
+// A BrowserProcessSubThread is a physical thread backing a BrowserThread.
//
// Applications must initialize the COM library before they can call
// COM library functions other than CoGetMalloc and memory allocation
// functions, so this class initializes COM for those users.
-class CONTENT_EXPORT BrowserProcessSubThread : public BrowserThreadImpl {
+class CONTENT_EXPORT BrowserProcessSubThread : public base::Thread {
public:
+ // Constructs a BrowserProcessSubThread for |identifier|.
explicit BrowserProcessSubThread(BrowserThread::ID identifier);
- BrowserProcessSubThread(BrowserThread::ID identifier,
- base::MessageLoop* message_loop);
~BrowserProcessSubThread() override;
+ // Registers this thread to represent |identifier_| in the browser_thread.h
+ // API. This thread must already be running when this is called. This can only
+ // be called once per BrowserProcessSubThread instance.
+ void RegisterAsBrowserThread();
+
+ // Ideally there wouldn't be a special blanket allowance to block the
+ // BrowserThreads in tests but TestBrowserThreadImpl previously bypassed
+ // BrowserProcessSubThread and hence wasn't subject to ThreadRestrictions...
+ // Flipping that around in favor of explicit scoped allowances would be
+ // preferable but a non-trivial amount of work. Can only be called before
+ // starting this BrowserProcessSubThread.
+ void AllowBlockingForTesting();
+
protected:
void Init() override;
+ void Run(base::RunLoop* run_loop) override;
void CleanUp() override;
private:
- // These methods encapsulate cleanup that needs to happen on the IO thread
- // before we call the embedder's CleanUp function.
- void IOThreadPreCleanUp();
+ // Second Init() phase that must happen on this thread but can only happen
+ // after it's promoted to a BrowserThread in |RegisterAsBrowserThread()|.
+ void CompleteInitializationOnBrowserThread();
+
+ // These methods merely forwards to Thread::Run() but are useful to identify
+ // which BrowserThread this represents in stack traces.
+ void UIThreadRun(base::RunLoop* run_loop);
+ void IOThreadRun(base::RunLoop* run_loop);
+
+ // This method encapsulates cleanup that needs to happen on the IO thread.
+ void IOThreadCleanUp();
+
+ const BrowserThread::ID identifier_;
+
+ // BrowserThreads are not allowed to do file I/O nor wait on synchronization
+ // primivives except when explicitly allowed in tests.
+ bool is_blocking_allowed_for_testing_ = false;
+
+ // The BrowserThread registration for this |identifier_|, initialized in
+ // RegisterAsBrowserThread().
+ std::unique_ptr<BrowserThreadImpl> browser_thread_;
#if defined (OS_WIN)
std::unique_ptr<base::win::ScopedCOMInitializer> com_initializer_;
@@ -59,6 +88,8 @@
// Each specialized thread has its own notification service.
std::unique_ptr<NotificationService> notification_service_;
+ THREAD_CHECKER(browser_thread_checker_);
+
DISALLOW_COPY_AND_ASSIGN(BrowserProcessSubThread);
};