Commit 752eeba7 authored by Rohit Rao's avatar Rohit Rao Committed by Commit Bot

Refactor WebThreadImpl, WebSubThread, and WebMainLoop.

WebThreadImpl is now merely a scoped object that binds a provided
SingleThreadTaskRunner to a WebThread::ID. It no longer subclasses
base::Thread. That functionality has been moved to WebSubThread, which is
effectively only used for the IO thread now.

This is the //web implementation of
https://chromium-review.googlesource.com/c/chromium/src/+/980793. See the
description of that CL for more details.

BUG=826465

Change-Id: I636051b154c4156bc32517d649081131f9bdd14d
Reviewed-on: https://chromium-review.googlesource.com/c/1383140
Commit-Queue: Rohit Rao <rohitrao@chromium.org>
Reviewed-by: default avatarGabriel Charette <gab@chromium.org>
Reviewed-by: default avatarSylvain Defresne <sdefresne@chromium.org>
Cr-Commit-Position: refs/heads/master@{#618761}
parent ab50c918
...@@ -234,6 +234,10 @@ namespace vr { ...@@ -234,6 +234,10 @@ namespace vr {
class VrShell; class VrShell;
} }
namespace web {
class WebSubThread;
}
namespace webrtc { namespace webrtc {
class DesktopConfigurationMonitor; class DesktopConfigurationMonitor;
} }
...@@ -317,6 +321,7 @@ class BASE_EXPORT ScopedAllowBlocking { ...@@ -317,6 +321,7 @@ class BASE_EXPORT ScopedAllowBlocking {
friend class mojo::CoreLibraryInitializer; friend class mojo::CoreLibraryInitializer;
friend class resource_coordinator::TabManagerDelegate; // crbug.com/778703 friend class resource_coordinator::TabManagerDelegate; // crbug.com/778703
friend class ui::MaterialDesignController; friend class ui::MaterialDesignController;
friend class web::WebSubThread;
friend class StackSamplingProfiler; friend class StackSamplingProfiler;
ScopedAllowBlocking() EMPTY_BODY_IF_DCHECK_IS_OFF; ScopedAllowBlocking() EMPTY_BODY_IF_DCHECK_IS_OFF;
......
...@@ -7,4 +7,8 @@ include_rules = [ ...@@ -7,4 +7,8 @@ include_rules = [
"+components/version_info", "+components/version_info",
"+ios/web/public", "+ios/web/public",
"+net", "+net",
# Temporarily allow WebThreadImpl until TaskExecutor functionality is moved
# into a new file in ios/web/public.
"+ios/web/web_thread_impl.h"
] ]
...@@ -4,16 +4,16 @@ ...@@ -4,16 +4,16 @@
#include "ios/components/io_thread/ios_io_thread.h" #include "ios/components/io_thread/ios_io_thread.h"
#include "base/message_loop/message_loop.h" #include <memory>
#include "base/run_loop.h"
#include "components/prefs/pref_registry_simple.h" #include "base/test/scoped_task_environment.h"
#include "components/prefs/pref_service.h" #include "components/prefs/testing_pref_service.h"
#include "components/prefs/pref_service_factory.h"
#include "components/prefs/testing_pref_store.h"
#include "components/proxy_config/pref_proxy_config_tracker_impl.h" #include "components/proxy_config/pref_proxy_config_tracker_impl.h"
#include "ios/web/public/test/test_web_thread_bundle.h" #import "ios/web/public/test/fakes/test_web_client.h"
#include "net/test/url_request/url_request_failed_job.h" #include "ios/web/public/test/scoped_testing_web_client.h"
#include "net/url_request/url_request_filter.h" #include "ios/web/public/test/test_web_thread.h"
#include "ios/web/web_thread_impl.h"
#include "net/base/network_delegate.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "testing/gtest_mac.h" #include "testing/gtest_mac.h"
#include "testing/platform_test.h" #include "testing/platform_test.h"
...@@ -42,32 +42,43 @@ class TestIOThread : public io_thread::IOSIOThread { ...@@ -42,32 +42,43 @@ class TestIOThread : public io_thread::IOSIOThread {
class IOSIOThreadTest : public PlatformTest { class IOSIOThreadTest : public PlatformTest {
public: public:
IOSIOThreadTest() : thread_bundle_(web::TestWebThreadBundle::IO_MAINLOOP) { IOSIOThreadTest() : web_client_(std::make_unique<web::TestWebClient>()) {
net::URLRequestFailedJob::AddUrlHandler(); web::WebThreadImpl::CreateTaskExecutor();
ui_thread_ = std::make_unique<web::TestWebThread>(
web::WebThread::UI, scoped_task_environment_.GetMainThreadTaskRunner());
} }
~IOSIOThreadTest() override { ~IOSIOThreadTest() override {
net::URLRequestFilter::GetInstance()->ClearHandlers(); web::WebThreadImpl::ResetTaskExecutorForTesting();
} }
private: protected:
web::TestWebThreadBundle thread_bundle_; base::test::ScopedTaskEnvironment scoped_task_environment_;
web::ScopedTestingWebClient web_client_;
std::unique_ptr<web::TestWebThread> ui_thread_;
}; };
// Tests the creation of an IOSIOThread and verifies that it returns a system // Tests the creation of an IOSIOThread and verifies that it returns a system
// url request context. // url request context.
TEST_F(IOSIOThreadTest, AssertSystemUrlRequestContext) { TEST_F(IOSIOThreadTest, AssertSystemUrlRequestContext) {
PrefServiceFactory pref_service_factory; std::unique_ptr<TestingPrefServiceSimple> pref_service(
pref_service_factory.set_user_prefs(base::MakeRefCounted<TestingPrefStore>()); std::make_unique<TestingPrefServiceSimple>());
PrefProxyConfigTrackerImpl::RegisterPrefs(pref_service->registry());
scoped_refptr<PrefRegistrySimple> pref_registry = new PrefRegistrySimple; // Create the IO thread but do not register it yet.
PrefProxyConfigTrackerImpl::RegisterPrefs(pref_registry.get()); std::unique_ptr<web::TestWebThread> io_thread(
std::make_unique<web::TestWebThread>(web::WebThread::IO));
io_thread->StartIOThreadUnregistered();
std::unique_ptr<PrefService> pref_service( // Create the TestIOThread before the IO thread is registered.
pref_service_factory.Create(pref_registry.get())); std::unique_ptr<TestIOThread> ios_io_thread(
std::unique_ptr<TestIOThread> test_io_thread(
new TestIOThread(pref_service.get(), nullptr)); new TestIOThread(pref_service.get(), nullptr));
io_thread->RegisterAsWebThread();
ASSERT_TRUE(ios_io_thread->system_url_request_context_getter());
ASSERT_TRUE(test_io_thread->system_url_request_context_getter()); // Explicitly destroy the IO thread so that it is unregistered before the
// TestIOThread is destroyed.
io_thread.reset();
} }
...@@ -83,7 +83,7 @@ class WebMainLoop { ...@@ -83,7 +83,7 @@ class WebMainLoop {
// This must get destroyed after other threads that are created in parts_. // This must get destroyed after other threads that are created in parts_.
std::unique_ptr<WebThreadImpl> main_thread_; std::unique_ptr<WebThreadImpl> main_thread_;
// Members initialized in |RunMainMessageLoopParts()| ------------------------ // Members initialized in |CreateThreads()| ------------------------
std::unique_ptr<WebSubThread> io_thread_; std::unique_ptr<WebSubThread> io_thread_;
// Members initialized in |WebThreadsStarted()| -------------------------- // Members initialized in |WebThreadsStarted()| --------------------------
......
...@@ -130,7 +130,9 @@ int WebMainLoop::CreateThreads( ...@@ -130,7 +130,9 @@ int WebMainLoop::CreateThreads(
base::Thread::Options io_message_loop_options; base::Thread::Options io_message_loop_options;
io_message_loop_options.message_loop_type = base::MessageLoop::TYPE_IO; io_message_loop_options.message_loop_type = base::MessageLoop::TYPE_IO;
io_thread_ = std::make_unique<WebSubThread>(WebThread::IO); io_thread_ = std::make_unique<WebSubThread>(WebThread::IO);
io_thread_->StartWithOptions(io_message_loop_options); if (!io_thread_->StartWithOptions(io_message_loop_options))
LOG(FATAL) << "Failed to start WebThread::IO";
io_thread_->RegisterAsWebThread();
// Only start IO thread above as this is the only WebThread besides UI (which // Only start IO thread above as this is the only WebThread besides UI (which
// is the main thread). // is the main thread).
...@@ -196,8 +198,10 @@ void WebMainLoop::InitializeMainThread() { ...@@ -196,8 +198,10 @@ void WebMainLoop::InitializeMainThread() {
base::PlatformThread::SetName("CrWebMain"); base::PlatformThread::SetName("CrWebMain");
// Register the main thread by instantiating it, but don't call any methods. // Register the main thread by instantiating it, but don't call any methods.
DCHECK(base::ThreadTaskRunnerHandle::IsSet());
main_thread_.reset(new WebThreadImpl( main_thread_.reset(new WebThreadImpl(
WebThread::UI, ios_global_state::GetMainThreadMessageLoop())); WebThread::UI,
ios_global_state::GetMainThreadMessageLoop()->task_runner()));
} }
int WebMainLoop::WebThreadsStarted() { int WebMainLoop::WebThreadsStarted() {
......
...@@ -12,18 +12,29 @@ ...@@ -12,18 +12,29 @@
namespace base { namespace base {
class MessageLoop; class MessageLoop;
class Thread;
} }
namespace web { namespace web {
class TestWebThreadImpl; class WebSubThread;
class WebThreadImpl;
// DEPRECATED: use TestWebThreadBundle instead. // DEPRECATED: use TestWebThreadBundle instead.
// A WebThread for unit tests; this lets unit tests outside of web create // A WebThread for unit tests; this lets unit tests outside of web create
// WebThread instances. // WebThread instances.
class TestWebThread { class TestWebThread {
public: public:
// Constructs a TestWebThread with a |real_thread_| and starts it (with a
// MessageLoopForIO if |identifier == WebThread::IO|).
explicit TestWebThread(WebThread::ID identifier); explicit TestWebThread(WebThread::ID identifier);
// Constructs a TestWebThread "running" on |thread_runner| (no
// |real_thread_|).
TestWebThread(WebThread::ID identifier,
scoped_refptr<base::SingleThreadTaskRunner> thread_runner);
// Constructs a TestWebThread based on |message_loop| (no |real_thread_|).
TestWebThread(WebThread::ID identifier, base::MessageLoop* message_loop); TestWebThread(WebThread::ID identifier, base::MessageLoop* message_loop);
~TestWebThread(); ~TestWebThread();
...@@ -33,22 +44,31 @@ class TestWebThread { ...@@ -33,22 +44,31 @@ class TestWebThread {
// WebThread, do no provide the full Thread interface. // WebThread, do no provide the full Thread interface.
// Starts the thread with a generic message loop. // Starts the thread with a generic message loop.
bool Start(); void Start();
// Starts the thread with an IOThread message loop. // Starts the thread with an IOThread message loop.
bool StartIOThread(); void StartIOThread();
// Together these are the same as StartIOThread(). They can be called in
// phases to test binding WebThread::IO after its underlying thread was
// started.
void StartIOThreadUnregistered();
void RegisterAsWebThread();
// Stops the thread. // Stops the thread.
void Stop(); void Stop();
// Returns true if the thread is running.
bool IsRunning();
private: private:
std::unique_ptr<TestWebThreadImpl> impl_;
const WebThread::ID identifier_; const WebThread::ID identifier_;
// A real thread which represents |identifier_| when constructor #1 is used
// (null otherwise).
std::unique_ptr<WebSubThread> real_thread_;
// Binds |identifier_| to |message_loop| when constructor #2 is used (null
// otherwise).
std::unique_ptr<WebThreadImpl> fake_thread_;
DISALLOW_COPY_AND_ASSIGN(TestWebThread); DISALLOW_COPY_AND_ASSIGN(TestWebThread);
}; };
......
...@@ -95,9 +95,9 @@ class WebThread { ...@@ -95,9 +95,9 @@ class WebThread {
// Only one delegate may be registered at a time. Delegates may be // Only one delegate may be registered at a time. Delegates may be
// unregistered by providing a nullptr pointer. // unregistered by providing a nullptr pointer.
// //
// If the caller unregisters a delegate before CleanUp has been // The delegate can only be registered through this call before
// called, it must perform its own locking to ensure the delegate is // WebThreadImpl(WebThread::IO) is created and unregistered after
// not deleted while unregistering. // it was destroyed and its underlying thread shutdown.
static void SetIOThreadDelegate(WebThreadDelegate* delegate); static void SetIOThreadDelegate(WebThreadDelegate* delegate);
// Returns an appropriate error message for when DCHECK_CURRENTLY_ON() fails. // Returns an appropriate error message for when DCHECK_CURRENTLY_ON() fails.
......
...@@ -13,14 +13,17 @@ namespace web { ...@@ -13,14 +13,17 @@ namespace web {
// If registered as such, it will schedule to run Init() before the // If registered as such, it will schedule to run Init() before the
// message loop begins, and receive a CleanUp() call right after the message // message loop begins, and receive a CleanUp() call right after the message
// loop ends (and before the WebThread has done its own clean-up). // loop ends (and before the WebThread has done its own clean-up).
// A delegate for //web embedders to perform extra initialization/cleanup on
// WebThread::IO.
class WebThreadDelegate { class WebThreadDelegate {
public: public:
virtual ~WebThreadDelegate() {} virtual ~WebThreadDelegate() {}
// Called prior to starting the message loop // Called prior to completing initialization of WebThread::IO.
virtual void Init() = 0; virtual void Init() = 0;
// Called just after the message loop ends. // Called during teardown of WebThread::IO.
virtual void CleanUp() = 0; virtual void CleanUp() = 0;
}; };
......
...@@ -6,41 +6,36 @@ ...@@ -6,41 +6,36 @@
#include "base/macros.h" #include "base/macros.h"
#include "base/message_loop/message_loop.h" #include "base/message_loop/message_loop.h"
#include "ios/web/web_sub_thread.h"
#include "ios/web/web_thread_impl.h" #include "ios/web/web_thread_impl.h"
namespace web { namespace web {
class TestWebThreadImpl : public WebThreadImpl {
public:
TestWebThreadImpl(WebThread::ID identifier) : WebThreadImpl(identifier) {}
TestWebThreadImpl(WebThread::ID identifier, base::MessageLoop* message_loop)
: WebThreadImpl(identifier, message_loop) {}
~TestWebThreadImpl() override { Stop(); }
private:
DISALLOW_COPY_AND_ASSIGN(TestWebThreadImpl);
};
TestWebThread::TestWebThread(WebThread::ID identifier) TestWebThread::TestWebThread(WebThread::ID identifier)
: impl_(new TestWebThreadImpl(identifier)), identifier_(identifier) {} : identifier_(identifier),
real_thread_(std::make_unique<WebSubThread>(identifier_)) {
real_thread_->AllowBlockingForTesting();
}
TestWebThread::TestWebThread(
WebThread::ID identifier,
scoped_refptr<base::SingleThreadTaskRunner> thread_runner)
: identifier_(identifier),
fake_thread_(new WebThreadImpl(identifier_, thread_runner)) {}
TestWebThread::TestWebThread(WebThread::ID identifier, TestWebThread::TestWebThread(WebThread::ID identifier,
base::MessageLoop* message_loop) base::MessageLoop* message_loop)
: impl_(new TestWebThreadImpl(identifier, message_loop)), : TestWebThread(identifier, message_loop->task_runner()) {}
identifier_(identifier) {}
TestWebThread::~TestWebThread() { TestWebThread::~TestWebThread() {
// The upcoming WebThreadImpl::ResetGlobalsForTesting() call requires that // The upcoming WebThreadImpl::ResetGlobalsForTesting() call requires that
// |impl_| have triggered the shutdown phase for its WebThread::ID. This // |identifier_| completed its shutdown phase.
// either happens when the thread is stopped (if real) or destroyed (when fake real_thread_.reset();
// -- i.e. using an externally provided MessageLoop). fake_thread_.reset();
impl_.reset();
// Resets WebThreadImpl's globals so that |impl_| is no longer bound to // Resets WebThreadImpl's globals so that |identifier_| is no longer
// |identifier_|. This is fine since the underlying MessageLoop has already // bound. This is fine since the underlying MessageLoop has already been
// been flushed and deleted in Stop(). In the case of an externally provided // flushed and deleted above. In the case of an externally provided
// MessageLoop however, this means that TaskRunners obtained through // MessageLoop however, this means that TaskRunners obtained through
// |WebThreadImpl::GetTaskRunnerForThread(identifier_)| will no longer // |WebThreadImpl::GetTaskRunnerForThread(identifier_)| will no longer
// recognize their WebThreadImpl for RunsTasksInCurrentSequence(). This // recognize their WebThreadImpl for RunsTasksInCurrentSequence(). This
...@@ -54,22 +49,29 @@ TestWebThread::~TestWebThread() { ...@@ -54,22 +49,29 @@ TestWebThread::~TestWebThread() {
WebThreadImpl::ResetGlobalsForTesting(identifier_); WebThreadImpl::ResetGlobalsForTesting(identifier_);
} }
bool TestWebThread::Start() { void TestWebThread::Start() {
return impl_->Start(); CHECK(real_thread_->Start());
RegisterAsWebThread();
}
void TestWebThread::StartIOThread() {
StartIOThreadUnregistered();
RegisterAsWebThread();
} }
bool TestWebThread::StartIOThread() { void TestWebThread::StartIOThreadUnregistered() {
base::Thread::Options options; base::Thread::Options options;
options.message_loop_type = base::MessageLoop::TYPE_IO; options.message_loop_type = base::MessageLoop::TYPE_IO;
return impl_->StartWithOptions(options); CHECK(real_thread_->StartWithOptions(options));
} }
void TestWebThread::Stop() { void TestWebThread::RegisterAsWebThread() {
impl_->Stop(); real_thread_->RegisterAsWebThread();
} }
bool TestWebThread::IsRunning() { void TestWebThread::Stop() {
return impl_->IsRunning(); if (real_thread_)
real_thread_->Stop();
} }
} // namespace web } // namespace web
...@@ -4,43 +4,122 @@ ...@@ -4,43 +4,122 @@
#include "ios/web/web_sub_thread.h" #include "ios/web/web_sub_thread.h"
#include "base/compiler_specific.h"
#include "base/debug/alias.h"
#include "base/threading/thread_restrictions.h" #include "base/threading/thread_restrictions.h"
#include "ios/web/public/web_thread.h" #include "ios/web/public/web_thread_delegate.h"
#include "ios/web/web_thread_impl.h" #include "ios/web/web_thread_impl.h"
#include "net/url_request/url_fetcher.h" #include "net/url_request/url_fetcher.h"
namespace web { namespace web {
WebSubThread::WebSubThread(WebThread::ID identifier) namespace {
: WebThreadImpl(identifier) {} WebThreadDelegate* g_io_thread_delegate = nullptr;
} // namespace
// static
void WebThread::SetIOThreadDelegate(WebThreadDelegate* delegate) {
// |delegate| can only be set/unset while WebThread::IO isn't up.
DCHECK(!WebThread::IsThreadInitialized(WebThread::IO));
// and it cannot be set twice.
DCHECK(!g_io_thread_delegate || !delegate);
WebSubThread::WebSubThread(WebThread::ID identifier, g_io_thread_delegate = delegate;
base::MessageLoop* message_loop) }
: WebThreadImpl(identifier, message_loop) {}
WebSubThread::WebSubThread(WebThread::ID identifier)
: base::Thread(WebThreadImpl::GetThreadName(identifier)),
identifier_(identifier) {
// Not bound to creation thread.
DETACH_FROM_THREAD(web_thread_checker_);
}
WebSubThread::~WebSubThread() { WebSubThread::~WebSubThread() {
Stop(); Stop();
} }
void WebSubThread::RegisterAsWebThread() {
DCHECK(IsRunning());
DCHECK(!web_thread_);
web_thread_.reset(new WebThreadImpl(identifier_, task_runner()));
// Unretained(this) is safe as |this| outlives its underlying thread.
task_runner()->PostTask(
FROM_HERE,
base::BindOnce(&WebSubThread::CompleteInitializationOnWebThread,
Unretained(this)));
}
void WebSubThread::AllowBlockingForTesting() {
DCHECK(!IsRunning());
is_blocking_allowed_for_testing_ = true;
}
void WebSubThread::Init() { void WebSubThread::Init() {
WebThreadImpl::Init(); DCHECK_CALLED_ON_VALID_THREAD(web_thread_checker_);
if (WebThread::CurrentlyOn(WebThread::IO)) { if (!is_blocking_allowed_for_testing_) {
// Though this thread is called the "IO" thread, it actually just routes
// messages around; it shouldn't be allowed to perform any blocking disk
// I/O.
base::DisallowUnresponsiveTasks(); base::DisallowUnresponsiveTasks();
} }
} }
void WebSubThread::Run(base::RunLoop* run_loop) {
DCHECK_CALLED_ON_VALID_THREAD(web_thread_checker_);
switch (identifier_) {
case WebThread::UI:
// The main thread is usually promoted as the UI thread and doesn't go
// through Run() but some tests do run a separate UI thread.
UIThreadRun(run_loop);
break;
case WebThread::IO:
IOThreadRun(run_loop);
return;
case WebThread::ID_COUNT:
NOTREACHED();
break;
}
}
void WebSubThread::CleanUp() { void WebSubThread::CleanUp() {
DCHECK_CALLED_ON_VALID_THREAD(web_thread_checker_);
// Run extra cleanup if this thread represents WebThread::IO.
if (WebThread::CurrentlyOn(WebThread::IO)) if (WebThread::CurrentlyOn(WebThread::IO))
IOThreadPreCleanUp(); IOThreadCleanUp();
if (identifier_ == WebThread::IO && g_io_thread_delegate)
g_io_thread_delegate->CleanUp();
WebThreadImpl::CleanUp(); web_thread_.reset();
} }
void WebSubThread::IOThreadPreCleanUp() { void WebSubThread::CompleteInitializationOnWebThread() {
DCHECK_CALLED_ON_VALID_THREAD(web_thread_checker_);
if (identifier_ == WebThread::IO && g_io_thread_delegate) {
// Allow blocking calls while initializing the IO thread.
base::ScopedAllowBlocking allow_blocking_for_init;
g_io_thread_delegate->Init();
}
}
void WebSubThread::UIThreadRun(base::RunLoop* run_loop) {
const int line_number = __LINE__;
Thread::Run(run_loop);
base::debug::Alias(&line_number);
}
void WebSubThread::IOThreadRun(base::RunLoop* run_loop) {
const int line_number = __LINE__;
Thread::Run(run_loop);
base::debug::Alias(&line_number);
}
void WebSubThread::IOThreadCleanUp() {
DCHECK_CALLED_ON_VALID_THREAD(web_thread_checker_);
// Kill all things that might be holding onto // Kill all things that might be holding onto
// net::URLRequest/net::URLRequestContexts. // net::URLRequest/net::URLRequestContexts.
......
...@@ -6,26 +6,65 @@ ...@@ -6,26 +6,65 @@
#define IOS_WEB_WEB_SUB_THREAD_H_ #define IOS_WEB_WEB_SUB_THREAD_H_
#include "base/macros.h" #include "base/macros.h"
#include "ios/web/web_thread_impl.h" #include "base/threading/thread.h"
#include "base/threading/thread_checker.h"
#include "ios/web/public/web_thread.h"
namespace web { namespace web {
class WebThreadImpl;
}
// This simple thread object is used for the specialized threads that are spun namespace web {
// up during startup.
class WebSubThread : public WebThreadImpl { // A WebSubThread is a physical thread backing a WebThread.
class WebSubThread : public base::Thread {
public: public:
// Constructs a WebSubThread for |identifier|.
explicit WebSubThread(WebThread::ID identifier); explicit WebSubThread(WebThread::ID identifier);
WebSubThread(WebThread::ID identifier, base::MessageLoop* message_loop);
~WebSubThread() override; ~WebSubThread() override;
// Registers this thread to represent |identifier_| in the web_thread.h
// API. This thread must already be running when this is called. This can only
// be called once per WebSubThread instance.
void RegisterAsWebThread();
// Ideally there wouldn't be a special blanket allowance to block the
// WebThreads in tests but TestWebThreadImpl previously bypassed
// WebSubThread 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 WebSubThread.
void AllowBlockingForTesting();
protected: protected:
void Init() override; void Init() override;
void Run(base::RunLoop* run_loop) override;
void CleanUp() override; void CleanUp() override;
private: private:
// These methods encapsulate cleanup that needs to happen on the IO thread // Second Init() phase that must happen on this thread but can only happen
// before the embedder's |CleanUp()| function is called. // after it's promoted to a WebThread in |RegisterAsWebThread()|.
void IOThreadPreCleanUp(); void CompleteInitializationOnWebThread();
// These methods merely forwards to Thread::Run() but are useful to identify
// which WebThread 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 WebThread::ID identifier_;
// WebThreads are not allowed to do file I/O nor wait on synchronization
// primitives except when explicitly allowed in tests.
bool is_blocking_allowed_for_testing_ = false;
// The WebThread registration for this |identifier_|, initialized in
// RegisterAsWebThread().
std::unique_ptr<WebThreadImpl> web_thread_;
THREAD_CHECKER(web_thread_checker_);
DISALLOW_COPY_AND_ASSIGN(WebSubThread); DISALLOW_COPY_AND_ASSIGN(WebSubThread);
}; };
......
This diff is collapsed.
...@@ -6,28 +6,30 @@ ...@@ -6,28 +6,30 @@
#define IOS_WEB_WEB_THREAD_IMPL_H_ #define IOS_WEB_WEB_THREAD_IMPL_H_
#include "base/callback.h" #include "base/callback.h"
#include "base/memory/scoped_refptr.h"
#include "base/threading/thread.h" #include "base/threading/thread.h"
#include "ios/web/public/web_thread.h" #include "ios/web/public/web_thread.h"
namespace web { namespace web {
class WebTestSuiteListener; class TestWebThread;
class WebMainLoop;
class WebThreadImpl : public WebThread, public base::Thread { class WebSubThread;
// WebThreadImpl is a scoped object which maps a SingleThreadTaskRunner to a
// WebThread::ID. On ~WebThreadImpl() that ID enters a SHUTDOWN state
// (in which WebThread::IsThreadInitialized() returns false) but the mapping
// isn't undone to avoid shutdown races (the task runner is free to stop
// accepting tasks however).
//
// Very few users should use this directly. To mock WebThreads, tests should
// use TestWebThreadBundle instead.
class WebThreadImpl : public WebThread {
public: public:
// Construct a WebThreadImpl with the supplied identifier. It is an error ~WebThreadImpl();
// to construct a WebThreadImpl that already exists.
explicit WebThreadImpl(WebThread::ID identifier);
// Special constructor for the main (UI) thread and unittests. If a
// |message_loop| is provied, we use a dummy thread here since the main
// thread already exists.
WebThreadImpl(WebThread::ID identifier, base::MessageLoop* message_loop);
~WebThreadImpl() override;
bool Start(); // Returns the thread name for |identifier|.
bool StartWithOptions(const Options& options); static const char* GetThreadName(WebThread::ID identifier);
bool StartAndWaitForTesting();
// Creates and registers a TaskExecutor that facilitates posting tasks to a // Creates and registers a TaskExecutor that facilitates posting tasks to a
// WebThread via //base/task/post_task.h. // WebThread via //base/task/post_task.h.
...@@ -46,29 +48,19 @@ class WebThreadImpl : public WebThread, public base::Thread { ...@@ -46,29 +48,19 @@ class WebThreadImpl : public WebThread, public base::Thread {
// Also unregisters and deletes the TaskExecutor. // Also unregisters and deletes the TaskExecutor.
static void ResetGlobalsForTesting(WebThread::ID identifier); static void ResetGlobalsForTesting(WebThread::ID identifier);
protected:
void Init() override;
void Run(base::RunLoop* run_loop) override;
void CleanUp() override;
private: private:
// This class implements all the functionality of the public WebThread // Restrict instantiation to WebSubThread as it performs important
// functions, but state is stored in the WebThreadImpl to keep // initialization that shouldn't be bypassed (except by WebMainLoop for
// the API cleaner. Therefore make WebThread a friend class. // the main thread).
friend class WebThread; friend class WebSubThread;
friend class WebMainLoop;
// The following are unique function names that makes it possible to tell // TestWebThread is also allowed to construct this when instantiating fake
// the thread id from the callstack alone in crash dumps. // threads.
void UIThreadRun(base::RunLoop* run_loop); friend class TestWebThread;
void IOThreadRun(base::RunLoop* run_loop);
// Binds |identifier| to |task_runner| for the web_thread.h API.
// Common initialization code for the constructors. WebThreadImpl(WebThread::ID identifier,
void Initialize(); scoped_refptr<base::SingleThreadTaskRunner> task_runner);
// For testing.
friend class TestWebThreadBundle;
friend class TestWebThreadBundleImpl;
friend class WebTestSuiteListener;
// The identifier of this thread. Only one thread can exist with a given // The identifier of this thread. Only one thread can exist with a given
// identifier at a given time. // identifier at a given time.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment