diff options
28 files changed, 1166 insertions, 92 deletions
diff --git a/content/child/blink_platform_impl.cc b/content/child/blink_platform_impl.cc index fe029a0..24b615a 100644 --- a/content/child/blink_platform_impl.cc +++ b/content/child/blink_platform_impl.cc @@ -40,11 +40,11 @@ #include "content/child/permissions/permission_dispatcher_thread_proxy.h" #include "content/child/push_messaging/push_dispatcher.h" #include "content/child/push_messaging/push_provider.h" +#include "content/child/scheduler/webthread_impl_for_worker_scheduler.h" #include "content/child/thread_safe_sender.h" #include "content/child/web_discardable_memory_impl.h" #include "content/child/web_url_loader_impl.h" #include "content/child/websocket_bridge.h" -#include "content/child/webthread_impl.h" #include "content/child/worker_task_runner.h" #include "content/public/common/content_client.h" #include "net/base/data_url.h" @@ -506,7 +506,8 @@ bool BlinkPlatformImpl::isReservedIPAddress( } blink::WebThread* BlinkPlatformImpl::createThread(const char* name) { - WebThreadImpl* thread = new WebThreadImpl(name); + WebThreadImplForWorkerScheduler* thread = + new WebThreadImplForWorkerScheduler(name); thread->TaskRunner()->PostTask( FROM_HERE, base::Bind(&BlinkPlatformImpl::UpdateWebThreadTLS, base::Unretained(this), thread)); diff --git a/content/child/scheduler/null_worker_scheduler.cc b/content/child/scheduler/null_worker_scheduler.cc new file mode 100644 index 0000000..5949bbd --- /dev/null +++ b/content/child/scheduler/null_worker_scheduler.cc @@ -0,0 +1,51 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/child/scheduler/null_worker_scheduler.h" + +#include "base/bind.h" +#include "base/message_loop/message_loop_proxy.h" +#include "content/child/scheduler/null_idle_task_runner.h" + +namespace content { + +NullWorkerScheduler::NullWorkerScheduler() + : task_runner_(base::MessageLoopProxy::current()), + idle_task_runner_(new NullIdleTaskRunner()) { +} + +NullWorkerScheduler::~NullWorkerScheduler() { +} + +scoped_refptr<base::SingleThreadTaskRunner> +NullWorkerScheduler::DefaultTaskRunner() { + return task_runner_; +} + +scoped_refptr<SingleThreadIdleTaskRunner> +NullWorkerScheduler::IdleTaskRunner() { + return idle_task_runner_; +} + +void NullWorkerScheduler::AddTaskObserver( + base::MessageLoop::TaskObserver* task_observer) { + base::MessageLoop::current()->AddTaskObserver(task_observer); +} + +void NullWorkerScheduler::RemoveTaskObserver( + base::MessageLoop::TaskObserver* task_observer) { + base::MessageLoop::current()->RemoveTaskObserver(task_observer); +} + +bool NullWorkerScheduler::CanExceedIdleDeadlineIfRequired() const { + return false; +} + +void NullWorkerScheduler::Init() { +} + +void NullWorkerScheduler::Shutdown() { +} + +} // namespace content diff --git a/content/child/scheduler/null_worker_scheduler.h b/content/child/scheduler/null_worker_scheduler.h new file mode 100644 index 0000000..919ffad --- /dev/null +++ b/content/child/scheduler/null_worker_scheduler.h @@ -0,0 +1,36 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_CHILD_SCHEDULER_NULL_WORKER_SCHEDULER_H_ +#define CONTENT_CHILD_SCHEDULER_NULL_WORKER_SCHEDULER_H_ + +#include "content/child/scheduler/worker_scheduler.h" + +namespace content { + +class NullWorkerScheduler : public WorkerScheduler { + public: + NullWorkerScheduler(); + ~NullWorkerScheduler() override; + + scoped_refptr<base::SingleThreadTaskRunner> DefaultTaskRunner() override; + scoped_refptr<SingleThreadIdleTaskRunner> IdleTaskRunner() override; + + void AddTaskObserver(base::MessageLoop::TaskObserver* task_observer) override; + void RemoveTaskObserver( + base::MessageLoop::TaskObserver* task_observer) override; + bool CanExceedIdleDeadlineIfRequired() const override; + void Init() override; + void Shutdown() override; + + private: + scoped_refptr<base::SingleThreadTaskRunner> task_runner_; + scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner_; + + DISALLOW_COPY_AND_ASSIGN(NullWorkerScheduler); +}; + +} // namespace content + +#endif // CONTENT_CHILD_SCHEDULER_NULL_WORKER_SCHEDULER_H_ diff --git a/content/child/scheduler/scheduler_helper.cc b/content/child/scheduler/scheduler_helper.cc index 77fb9fb..16b4432 100644 --- a/content/child/scheduler/scheduler_helper.cc +++ b/content/child/scheduler/scheduler_helper.cc @@ -190,6 +190,7 @@ void SchedulerHelper::EnableLongIdlePeriod() { control_task_runner_->PostDelayedTask( FROM_HERE, enable_next_long_idle_period_closure_.callback(), required_quiescence_duration_before_long_idle_period_); + scheduler_helper_delegate_->IsNotQuiescent(); return; } diff --git a/content/child/scheduler/scheduler_helper.h b/content/child/scheduler/scheduler_helper.h index 0fefde6..9834380 100644 --- a/content/child/scheduler/scheduler_helper.h +++ b/content/child/scheduler/scheduler_helper.h @@ -31,6 +31,10 @@ class CONTENT_EXPORT SchedulerHelper { base::TimeTicks now, base::TimeDelta* next_long_idle_period_delay_out) = 0; + // Signals that the Long Idle Period hasn't started yet because the system + // isn't quiescent. + virtual void IsNotQuiescent() = 0; + private: DISALLOW_COPY_AND_ASSIGN(SchedulerHelperDelegate); }; diff --git a/content/child/scheduler/scheduler_helper_unittest.cc b/content/child/scheduler/scheduler_helper_unittest.cc index 219c4eb..9d57e72 100644 --- a/content/child/scheduler/scheduler_helper_unittest.cc +++ b/content/child/scheduler/scheduler_helper_unittest.cc @@ -133,6 +133,8 @@ class SchedulerHelperForTest : public SchedulerHelper, MOCK_METHOD2(CanEnterLongIdlePeriod, bool(base::TimeTicks now, base::TimeDelta* next_long_idle_period_delay_out)); + + MOCK_METHOD0(IsNotQuiescent, void()); }; class BaseSchedulerHelperTest : public testing::Test { diff --git a/content/child/scheduler/webthread_impl_for_worker_scheduler.cc b/content/child/scheduler/webthread_impl_for_worker_scheduler.cc new file mode 100644 index 0000000..bc4fe59 --- /dev/null +++ b/content/child/scheduler/webthread_impl_for_worker_scheduler.cc @@ -0,0 +1,83 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/child/scheduler/webthread_impl_for_worker_scheduler.h" + +#include "base/bind.h" +#include "base/synchronization/waitable_event.h" +#include "content/child/scheduler/scheduler_message_loop_delegate.h" +#include "content/child/scheduler/worker_scheduler_impl.h" +#include "third_party/WebKit/public/platform/WebTraceLocation.h" + +namespace content { + +WebThreadImplForWorkerScheduler::WebThreadImplForWorkerScheduler( + const char* name) + : thread_(new base::Thread(name)) { + thread_->Start(); + + base::WaitableEvent completion(false, false); + thread_->message_loop()->PostTask( + FROM_HERE, base::Bind(&WebThreadImplForWorkerScheduler::InitOnThread, + base::Unretained(this), &completion)); + completion.Wait(); +} + +WebThreadImplForWorkerScheduler::~WebThreadImplForWorkerScheduler() { + base::WaitableEvent completion(false, false); + thread_->message_loop()->PostTask( + FROM_HERE, base::Bind(&WebThreadImplForWorkerScheduler::ShutDownOnThread, + base::Unretained(this), &completion)); + completion.Wait(); + + thread_->Stop(); +} + +void WebThreadImplForWorkerScheduler::InitOnThread( + base::WaitableEvent* completion) { + worker_scheduler_ = WorkerScheduler::Create(thread_->message_loop()); + worker_scheduler_->Init(); + task_runner_ = worker_scheduler_->DefaultTaskRunner(); + idle_task_runner_ = worker_scheduler_->IdleTaskRunner(); + completion->Signal(); +} + +void WebThreadImplForWorkerScheduler::ShutDownOnThread( + base::WaitableEvent* completion) { + task_runner_ = nullptr; + idle_task_runner_ = nullptr; + worker_scheduler_.reset(nullptr); + completion->Signal(); +} + +blink::PlatformThreadId WebThreadImplForWorkerScheduler::threadId() const { + return thread_->thread_id(); +} + +base::MessageLoop* WebThreadImplForWorkerScheduler::MessageLoop() const { + // As per WebThreadImpl::MessageLoop() + return nullptr; +} + +base::SingleThreadTaskRunner* WebThreadImplForWorkerScheduler::TaskRunner() + const { + return task_runner_.get(); +} + +SingleThreadIdleTaskRunner* WebThreadImplForWorkerScheduler::IdleTaskRunner() + const { + return idle_task_runner_.get(); +} + +void WebThreadImplForWorkerScheduler::AddTaskObserverInternal( + base::MessageLoop::TaskObserver* observer) { + worker_scheduler_->AddTaskObserver(observer); +} + +void WebThreadImplForWorkerScheduler::RemoveTaskObserverInternal( + base::MessageLoop::TaskObserver* observer) { + worker_scheduler_->RemoveTaskObserver(observer); +} + +} // namespace content diff --git a/content/child/scheduler/webthread_impl_for_worker_scheduler.h b/content/child/scheduler/webthread_impl_for_worker_scheduler.h new file mode 100644 index 0000000..25362d7 --- /dev/null +++ b/content/child/scheduler/webthread_impl_for_worker_scheduler.h @@ -0,0 +1,50 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_CHILD_SCHEDULER_WEBTHREAD_IMPL_FOR_WORKER_SCHEDULER_H_ +#define CONTENT_CHILD_SCHEDULER_WEBTHREAD_IMPL_FOR_WORKER_SCHEDULER_H_ + +#include "content/child/scheduler/task_queue_manager.h" +#include "content/child/webthread_base.h" + +namespace base { +class WaitableEvent; +}; + +namespace content { + +class SingleThreadIdleTaskRunner; +class WorkerScheduler; + +class CONTENT_EXPORT WebThreadImplForWorkerScheduler : public WebThreadBase { + public: + explicit WebThreadImplForWorkerScheduler(const char* name); + virtual ~WebThreadImplForWorkerScheduler(); + + // blink::WebThread implementation. + blink::PlatformThreadId threadId() const override; + + // WebThreadBase implementation. + base::SingleThreadTaskRunner* TaskRunner() const override; + SingleThreadIdleTaskRunner* IdleTaskRunner() const override; + + private: + base::MessageLoop* MessageLoop() const override; + void AddTaskObserverInternal( + base::MessageLoop::TaskObserver* observer) override; + void RemoveTaskObserverInternal( + base::MessageLoop::TaskObserver* observer) override; + + void InitOnThread(base::WaitableEvent* completion); + void ShutDownOnThread(base::WaitableEvent* completion); + + scoped_ptr<base::Thread> thread_; + scoped_ptr<WorkerScheduler> worker_scheduler_; + scoped_refptr<base::SingleThreadTaskRunner> task_runner_; + scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner_; +}; + +} // namespace content + +#endif // CONTENT_CHILD_SCHEDULER_WEBTHREAD_IMPL_FOR_WORKER_SCHEDULER_H_ diff --git a/content/child/scheduler/webthread_impl_for_worker_scheduler_unittest.cc b/content/child/scheduler/webthread_impl_for_worker_scheduler_unittest.cc new file mode 100644 index 0000000..d8da51f --- /dev/null +++ b/content/child/scheduler/webthread_impl_for_worker_scheduler_unittest.cc @@ -0,0 +1,153 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/child/scheduler/webthread_impl_for_worker_scheduler.h" + +#include "base/synchronization/waitable_event.h" +#include "content/child/scheduler/worker_scheduler_impl.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/WebKit/public/platform/WebTraceLocation.h" + +using testing::_; +using testing::AnyOf; +using testing::ElementsAre; +using testing::Invoke; + +namespace content { +namespace { + +class NopTask : public blink::WebThread::Task { + public: + ~NopTask() override {} + + void run() {} +}; + +class MockTask : public blink::WebThread::Task { + public: + ~MockTask() override {} + + MOCK_METHOD0(run, void()); +}; + +class MockIdleTask : public blink::WebThread::IdleTask { + public: + ~MockIdleTask() override {} + + MOCK_METHOD1(run, void(double deadline)); +}; + +class TestObserver : public blink::WebThread::TaskObserver { + public: + explicit TestObserver(std::string* calls) : calls_(calls) {} + + ~TestObserver() override {} + + void willProcessTask() override { calls_->append(" willProcessTask"); } + + void didProcessTask() override { calls_->append(" didProcessTask"); } + + private: + std::string* calls_; // NOT OWNED +}; + +class TestTask : public blink::WebThread::Task { + public: + explicit TestTask(std::string* calls) : calls_(calls) {} + + ~TestTask() override {} + + void run() override { calls_->append(" run"); } + + private: + std::string* calls_; // NOT OWNED +}; + +void addTaskObserver(WebThreadImplForWorkerScheduler* thread, + TestObserver* observer) { + thread->addTaskObserver(observer); +} + +void removeTaskObserver(WebThreadImplForWorkerScheduler* thread, + TestObserver* observer) { + thread->removeTaskObserver(observer); +} + +} // namespace + +class WebThreadImplForWorkerSchedulerTest : public testing::Test { + public: + WebThreadImplForWorkerSchedulerTest() : thread_("test thread") {} + + ~WebThreadImplForWorkerSchedulerTest() override {} + + void RunOnWorkerThread(const tracked_objects::Location& from_here, + const base::Closure& task) { + base::WaitableEvent completion(false, false); + thread_.TaskRunner()->PostTask( + from_here, + base::Bind(&WebThreadImplForWorkerSchedulerTest::RunOnWorkerThreadTask, + base::Unretained(this), task, &completion)); + completion.Wait(); + } + + protected: + void RunOnWorkerThreadTask(const base::Closure& task, + base::WaitableEvent* completion) { + task.Run(); + completion->Signal(); + } + + WebThreadImplForWorkerScheduler thread_; + + DISALLOW_COPY_AND_ASSIGN(WebThreadImplForWorkerSchedulerTest); +}; + +TEST_F(WebThreadImplForWorkerSchedulerTest, TestDefaultTask) { + scoped_ptr<MockTask> task(new MockTask()); + base::WaitableEvent completion(false, false); + + EXPECT_CALL(*task, run()); + ON_CALL(*task, run()) + .WillByDefault(Invoke([&completion]() { completion.Signal(); })); + + thread_.postTask(blink::WebTraceLocation(), task.release()); + completion.Wait(); +} + +TEST_F(WebThreadImplForWorkerSchedulerTest, TestIdleTask) { + scoped_ptr<MockIdleTask> task(new MockIdleTask()); + base::WaitableEvent completion(false, false); + + EXPECT_CALL(*task, run(_)); + ON_CALL(*task, run(_)) + .WillByDefault(Invoke([&completion](double) { completion.Signal(); })); + + thread_.postIdleTask(blink::WebTraceLocation(), task.release()); + // We need to post a wakeup task or idle work will never happen. + thread_.postDelayedTask(blink::WebTraceLocation(), new NopTask(), 50ul); + + completion.Wait(); +} + +TEST_F(WebThreadImplForWorkerSchedulerTest, TestTaskObserver) { + std::string calls; + TestObserver observer(&calls); + + RunOnWorkerThread(FROM_HERE, + base::Bind(&addTaskObserver, &thread_, &observer)); + thread_.postTask(blink::WebTraceLocation(), new TestTask(&calls)); + RunOnWorkerThread(FROM_HERE, + base::Bind(&removeTaskObserver, &thread_, &observer)); + + // We need to be careful what we test here. We want to make sure the + // observers are un in the expected order before and after the task. + // Sometimes we get an internal scheduler task running before or after + // TestTask as well. This is not a bug, and we need to make sure the test + // doesn't fail when that happens. + EXPECT_THAT(calls, testing::HasSubstr("willProcessTask run didProcessTask")); +} + +} // namespace content diff --git a/content/child/scheduler/worker_scheduler.cc b/content/child/scheduler/worker_scheduler.cc new file mode 100644 index 0000000..ac30ab3 --- /dev/null +++ b/content/child/scheduler/worker_scheduler.cc @@ -0,0 +1,34 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/child/scheduler/worker_scheduler.h" + +#include "base/command_line.h" +#include "base/message_loop/message_loop.h" +#include "content/child/scheduler/null_worker_scheduler.h" +#include "content/child/scheduler/scheduler_message_loop_delegate.h" +#include "content/child/scheduler/worker_scheduler_impl.h" +#include "content/public/common/content_switches.h" + +namespace content { + +WorkerScheduler::WorkerScheduler() { +} + +WorkerScheduler::~WorkerScheduler() { +} + +// static +scoped_ptr<WorkerScheduler> WorkerScheduler::Create( + base::MessageLoop* message_loop) { + base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); + if (command_line->HasSwitch(switches::kDisableBlinkScheduler)) { + return make_scoped_ptr(new NullWorkerScheduler()); + } else { + return make_scoped_ptr(new WorkerSchedulerImpl( + SchedulerMessageLoopDelegate::Create(message_loop))); + } +} + +} // namespace content diff --git a/content/child/scheduler/worker_scheduler.h b/content/child/scheduler/worker_scheduler.h new file mode 100644 index 0000000..6d90626 --- /dev/null +++ b/content/child/scheduler/worker_scheduler.h @@ -0,0 +1,65 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_CHILD_SCHEDULER_WORKER_SCHEDULER_H_ +#define CONTENT_CHILD_SCHEDULER_WORKER_SCHEDULER_H_ + +#include "base/message_loop/message_loop.h" +#include "content/child/scheduler/single_thread_idle_task_runner.h" +#include "content/common/content_export.h" + +namespace base { +class MessageLoop; +} + +namespace content { + +class CONTENT_EXPORT WorkerScheduler { + public: + virtual ~WorkerScheduler(); + static scoped_ptr<WorkerScheduler> Create(base::MessageLoop* message_loop); + + // Must be called before the scheduler can be used. Does any post construction + // initialization needed such as initializing idle period detection. + virtual void Init() = 0; + + // Returns the default task runner. + virtual scoped_refptr<base::SingleThreadTaskRunner> DefaultTaskRunner() = 0; + + // Returns the idle task runner. Tasks posted to this runner may be reordered + // relative to other task types and may be starved for an arbitrarily long + // time if no idle time is available. + virtual scoped_refptr<SingleThreadIdleTaskRunner> IdleTaskRunner() = 0; + + // Returns true if a currently running idle task could exceed its deadline + // without impacting user experience too much. This should only be used if + // there is a task which cannot be pre-empted and is likely to take longer + // than the largest expected idle task deadline. It should NOT be polled to + // check whether more work can be performed on the current idle task after + // its deadline has expired - post a new idle task for the continuation of the + // work in this case. + // Must be called from the worker's thread. + virtual bool CanExceedIdleDeadlineIfRequired() const = 0; + + // Adds or removes a task observer from the scheduler. The observer will be + // notified before and after every executed task. These functions can only be + // called on the main thread. + virtual void AddTaskObserver( + base::MessageLoop::TaskObserver* task_observer) = 0; + virtual void RemoveTaskObserver( + base::MessageLoop::TaskObserver* task_observer) = 0; + + // Shuts down the scheduler by dropping any remaining pending work in the work + // queues. After this call any work posted to the task runners will be + // silently dropped. + virtual void Shutdown() = 0; + + protected: + WorkerScheduler(); + DISALLOW_COPY_AND_ASSIGN(WorkerScheduler); +}; + +} // namespace content + +#endif // CONTENT_CHILD_SCHEDULER_WORKER_SCHEDULER_H_ diff --git a/content/child/scheduler/worker_scheduler_impl.cc b/content/child/scheduler/worker_scheduler_impl.cc new file mode 100644 index 0000000..63661db --- /dev/null +++ b/content/child/scheduler/worker_scheduler_impl.cc @@ -0,0 +1,92 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/child/scheduler/worker_scheduler_impl.h" + +#include "base/bind.h" +#include "base/message_loop/message_loop_proxy.h" +#include "base/trace_event/trace_event.h" +#include "base/trace_event/trace_event_argument.h" +#include "content/child/scheduler/nestable_single_thread_task_runner.h" + +namespace content { + +WorkerSchedulerImpl::WorkerSchedulerImpl( + scoped_refptr<NestableSingleThreadTaskRunner> main_task_runner) + : helper_(main_task_runner, + this, + "worker.scheduler", + TRACE_DISABLED_BY_DEFAULT("worker.scheduler"), + SchedulerHelper::TASK_QUEUE_COUNT, + base::TimeDelta::FromMilliseconds(300)) { + initialized_ = false; + TRACE_EVENT_OBJECT_CREATED_WITH_ID( + TRACE_DISABLED_BY_DEFAULT("worker.scheduler"), "WorkerScheduler", this); +} + +WorkerSchedulerImpl::~WorkerSchedulerImpl() { + TRACE_EVENT_OBJECT_DELETED_WITH_ID( + TRACE_DISABLED_BY_DEFAULT("worker.scheduler"), "WorkerScheduler", this); +} + +void WorkerSchedulerImpl::Init() { + initialized_ = true; + helper_.EnableLongIdlePeriod(); +} + +scoped_refptr<base::SingleThreadTaskRunner> +WorkerSchedulerImpl::DefaultTaskRunner() { + DCHECK(initialized_); + return helper_.DefaultTaskRunner(); +} + +scoped_refptr<SingleThreadIdleTaskRunner> +WorkerSchedulerImpl::IdleTaskRunner() { + DCHECK(initialized_); + return helper_.IdleTaskRunner(); +} + +bool WorkerSchedulerImpl::CanExceedIdleDeadlineIfRequired() const { + DCHECK(initialized_); + return helper_.CanExceedIdleDeadlineIfRequired(); +} + +void WorkerSchedulerImpl::AddTaskObserver( + base::MessageLoop::TaskObserver* task_observer) { + DCHECK(initialized_); + helper_.AddTaskObserver(task_observer); +} + +void WorkerSchedulerImpl::RemoveTaskObserver( + base::MessageLoop::TaskObserver* task_observer) { + DCHECK(initialized_); + helper_.RemoveTaskObserver(task_observer); +} + +void WorkerSchedulerImpl::Shutdown() { + DCHECK(initialized_); + helper_.Shutdown(); +} + +void WorkerSchedulerImpl::SetTimeSourceForTesting( + scoped_refptr<cc::TestNowSource> time_source) { + helper_.SetTimeSourceForTesting(time_source); +} + +void WorkerSchedulerImpl::SetWorkBatchSizeForTesting(size_t work_batch_size) { + helper_.SetWorkBatchSizeForTesting(work_batch_size); +} + +bool WorkerSchedulerImpl::CanEnterLongIdlePeriod(base::TimeTicks, + base::TimeDelta*) { + return true; +} + +base::TimeTicks WorkerSchedulerImpl::CurrentIdleTaskDeadlineForTesting() const { + base::TimeTicks deadline; + helper_.CurrentIdleTaskDeadlineCallback(&deadline); + return deadline; +} + +} // namespace content diff --git a/content/child/scheduler/worker_scheduler_impl.h b/content/child/scheduler/worker_scheduler_impl.h new file mode 100644 index 0000000..186d2bc --- /dev/null +++ b/content/child/scheduler/worker_scheduler_impl.h @@ -0,0 +1,61 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_CHILD_SCHEDULER_WORKER_SCHEDULER_IMPL_H_ +#define CONTENT_CHILD_SCHEDULER_WORKER_SCHEDULER_IMPL_H_ + +#include "content/child/scheduler/worker_scheduler.h" +#include "content/child/scheduler/scheduler_helper.h" + +namespace base { +namespace trace_event { +class ConvertableToTraceFormat; +} +} + +namespace content { + +class NestableSingleThreadTaskRunner; + +class CONTENT_EXPORT WorkerSchedulerImpl + : public WorkerScheduler, + public SchedulerHelper::SchedulerHelperDelegate { + public: + explicit WorkerSchedulerImpl( + scoped_refptr<NestableSingleThreadTaskRunner> main_task_runner); + ~WorkerSchedulerImpl() override; + + // WorkerScheduler implementation: + scoped_refptr<base::SingleThreadTaskRunner> DefaultTaskRunner() override; + scoped_refptr<SingleThreadIdleTaskRunner> IdleTaskRunner() override; + bool CanExceedIdleDeadlineIfRequired() const override; + void AddTaskObserver(base::MessageLoop::TaskObserver* task_observer) override; + void RemoveTaskObserver( + base::MessageLoop::TaskObserver* task_observer) override; + void Init() override; + void Shutdown() override; + + void SetTimeSourceForTesting(scoped_refptr<cc::TestNowSource> time_source); + void SetWorkBatchSizeForTesting(size_t work_batch_size); + base::TimeTicks CurrentIdleTaskDeadlineForTesting() const; + + protected: + // SchedulerHelperDelegate implementation: + bool CanEnterLongIdlePeriod( + base::TimeTicks now, + base::TimeDelta* next_long_idle_period_delay_out) override; + void IsNotQuiescent() override {} + + private: + void MaybeStartLongIdlePeriod(); + + SchedulerHelper helper_; + bool initialized_; + + DISALLOW_COPY_AND_ASSIGN(WorkerSchedulerImpl); +}; + +} // namespace content + +#endif // CONTENT_CHILD_SCHEDULER_WORKER_SCHEDULER_IMPL_H_ diff --git a/content/child/scheduler/worker_scheduler_impl_unittest.cc b/content/child/scheduler/worker_scheduler_impl_unittest.cc new file mode 100644 index 0000000..eed8f55 --- /dev/null +++ b/content/child/scheduler/worker_scheduler_impl_unittest.cc @@ -0,0 +1,420 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/child/scheduler/worker_scheduler_impl.h" + +#include "base/callback.h" +#include "base/strings/stringprintf.h" +#include "cc/test/ordered_simple_task_runner.h" +#include "content/child/scheduler/nestable_task_runner_for_test.h" +#include "content/child/scheduler/scheduler_message_loop_delegate.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using testing::ElementsAreArray; + +namespace content { + +namespace { +void NopTask() { +} + +int TimeTicksToIntMs(const base::TimeTicks& time) { + return static_cast<int>((time - base::TimeTicks()).InMilliseconds()); +} + +void WakeUpTask(std::vector<std::string>* timeline, cc::TestNowSource* clock) { + if (timeline) { + timeline->push_back(base::StringPrintf( + "run WakeUpTask @ %d", TimeTicksToIntMs(clock->Now()))); + } +} + +void RecordTimelineTask(std::vector<std::string>* timeline, + cc::TestNowSource* clock) { + timeline->push_back(base::StringPrintf( + "run RecordTimelineTask @ %d", TimeTicksToIntMs(clock->Now()))); +} + +void AppendToVectorTestTask(std::vector<std::string>* vector, + std::string value) { + vector->push_back(value); +} + +void AppendToVectorIdleTestTask(std::vector<std::string>* vector, + std::string value, + base::TimeTicks deadline) { + AppendToVectorTestTask(vector, value); +} + +void TimelineIdleTestTask(std::vector<std::string>* timeline, + base::TimeTicks deadline) { + timeline->push_back(base::StringPrintf("run TimelineIdleTestTask deadline %d", + TimeTicksToIntMs(deadline))); +} + +}; // namespace + +class WorkerSchedulerImplForTest : public WorkerSchedulerImpl { + public: + WorkerSchedulerImplForTest( + scoped_refptr<NestableSingleThreadTaskRunner> main_task_runner, + scoped_refptr<cc::TestNowSource> clock_) + : WorkerSchedulerImpl(main_task_runner), + clock_(clock_), + timeline_(nullptr) {} + + void RecordTimelineEvents(std::vector<std::string>* timeline) { + timeline_ = timeline; + } + + private: + bool CanEnterLongIdlePeriod( + base::TimeTicks now, + base::TimeDelta* next_long_idle_period_delay_out) override { + if (timeline_) { + timeline_->push_back(base::StringPrintf("CanEnterLongIdlePeriod @ %d", + TimeTicksToIntMs(now))); + } + return WorkerSchedulerImpl::CanEnterLongIdlePeriod( + now, next_long_idle_period_delay_out); + } + + void IsNotQuiescent() override { + if (timeline_) { + timeline_->push_back(base::StringPrintf("IsNotQuiescent @ %d", + TimeTicksToIntMs(clock_->Now()))); + } + WorkerSchedulerImpl::IsNotQuiescent(); + } + + scoped_refptr<cc::TestNowSource> clock_; + std::vector<std::string>* timeline_; // NOT OWNED +}; + +class WorkerSchedulerImplTest : public testing::Test { + public: + WorkerSchedulerImplTest() + : clock_(cc::TestNowSource::Create(5000)), + mock_task_runner_(new cc::OrderedSimpleTaskRunner(clock_, true)), + nestable_task_runner_( + NestableTaskRunnerForTest::Create(mock_task_runner_)), + scheduler_( + new WorkerSchedulerImplForTest(nestable_task_runner_, clock_)), + timeline_(nullptr) { + scheduler_->SetTimeSourceForTesting(clock_); + } + + ~WorkerSchedulerImplTest() override {} + + void TearDown() override { + // Check that all tests stop posting tasks. + while (mock_task_runner_->RunUntilIdle()) { + } + } + + void Init() { + scheduler_->Init(); + default_task_runner_ = scheduler_->DefaultTaskRunner(); + idle_task_runner_ = scheduler_->IdleTaskRunner(); + timeline_ = nullptr; + } + + void RecordTimelineEvents(std::vector<std::string>* timeline) { + timeline_ = timeline; + scheduler_->RecordTimelineEvents(timeline); + } + + void RunUntilIdle() { + if (timeline_) { + timeline_->push_back(base::StringPrintf("RunUntilIdle begin @ %d", + TimeTicksToIntMs(clock_->Now()))); + } + mock_task_runner_->RunUntilIdle(); + if (timeline_) { + timeline_->push_back(base::StringPrintf("RunUntilIdle end @ %d", + TimeTicksToIntMs(clock_->Now()))); + } + } + + void InitAndPostDelayedWakeupTask() { + Init(); + // WorkerSchedulerImpl::Init causes a delayed task to be posted on the + // after wakeup control runner. We need a task to wake the system up + // AFTER the delay for this has expired. + default_task_runner_->PostDelayedTask( + FROM_HERE, base::Bind(&WakeUpTask, base::Unretained(timeline_), + base::Unretained(clock_.get())), + base::TimeDelta::FromMilliseconds(100)); + } + + // Helper for posting several tasks of specific types. |task_descriptor| is a + // string with space delimited task identifiers. The first letter of each + // task identifier specifies the task type: + // - 'D': Default task + // - 'I': Idle task + void PostTestTasks(std::vector<std::string>* run_order, + const std::string& task_descriptor) { + std::istringstream stream(task_descriptor); + while (!stream.eof()) { + std::string task; + stream >> task; + switch (task[0]) { + case 'D': + default_task_runner_->PostTask( + FROM_HERE, base::Bind(&AppendToVectorTestTask, run_order, task)); + break; + case 'I': + idle_task_runner_->PostIdleTask( + FROM_HERE, + base::Bind(&AppendToVectorIdleTestTask, run_order, task)); + break; + default: + NOTREACHED(); + } + } + } + + static base::TimeDelta maximum_idle_period_duration() { + return base::TimeDelta::FromMilliseconds( + SchedulerHelper::kMaximumIdlePeriodMillis); + } + + protected: + scoped_refptr<cc::TestNowSource> clock_; + // Only one of mock_task_runner_ or message_loop_ will be set. + scoped_refptr<cc::OrderedSimpleTaskRunner> mock_task_runner_; + + scoped_refptr<NestableSingleThreadTaskRunner> nestable_task_runner_; + scoped_ptr<WorkerSchedulerImplForTest> scheduler_; + scoped_refptr<base::SingleThreadTaskRunner> default_task_runner_; + scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner_; + std::vector<std::string>* timeline_; // NOT OWNED + + DISALLOW_COPY_AND_ASSIGN(WorkerSchedulerImplTest); +}; + +TEST_F(WorkerSchedulerImplTest, TestPostDefaultTask) { + InitAndPostDelayedWakeupTask(); + + std::vector<std::string> run_order; + PostTestTasks(&run_order, "D1 D2 D3 D4"); + + RunUntilIdle(); + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("D1"), std::string("D2"), + std::string("D3"), std::string("D4"))); +} + +TEST_F(WorkerSchedulerImplTest, TestPostIdleTask) { + InitAndPostDelayedWakeupTask(); + + std::vector<std::string> run_order; + PostTestTasks(&run_order, "I1"); + + RunUntilIdle(); + EXPECT_THAT(run_order, testing::ElementsAre(std::string("I1"))); +} + +TEST_F(WorkerSchedulerImplTest, TestPostIdleTask_NoWakeup) { + Init(); + std::vector<std::string> run_order; + PostTestTasks(&run_order, "I1"); + + RunUntilIdle(); + EXPECT_TRUE(run_order.empty()); +} + +TEST_F(WorkerSchedulerImplTest, TestPostDefaultAndIdleTasks) { + InitAndPostDelayedWakeupTask(); + + std::vector<std::string> run_order; + PostTestTasks(&run_order, "I1 D2 D3 D4"); + + RunUntilIdle(); + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("D2"), std::string("D3"), + std::string("D4"), std::string("I1"))); +} + +TEST_F(WorkerSchedulerImplTest, TestPostIdleTaskWithWakeupNeeded_NoWakeup) { + InitAndPostDelayedWakeupTask(); + + RunUntilIdle(); + // The delayed call to EnableLongIdlePeriod happened and it posted a call to + // EnableLongIdlePeriod on the after wakeup control queue. + + std::vector<std::string> run_order; + PostTestTasks(&run_order, "I1"); + + RunUntilIdle(); + EXPECT_TRUE(run_order.empty()); +} + +TEST_F(WorkerSchedulerImplTest, TestPostDefaultDelayedAndIdleTasks) { + InitAndPostDelayedWakeupTask(); + + std::vector<std::string> run_order; + PostTestTasks(&run_order, "I1 D2 D3 D4"); + + default_task_runner_->PostDelayedTask( + FROM_HERE, base::Bind(&AppendToVectorTestTask, &run_order, "DELAYED"), + base::TimeDelta::FromMilliseconds(1000)); + + RunUntilIdle(); + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("D2"), std::string("D3"), + std::string("D4"), std::string("I1"), + std::string("DELAYED"))); +} + +TEST_F(WorkerSchedulerImplTest, TestIdleDeadlineWithPendingDelayedTask) { + std::vector<std::string> timeline; + RecordTimelineEvents(&timeline); + InitAndPostDelayedWakeupTask(); + + timeline.push_back("Post delayed and idle tasks"); + // Post a delayed task timed to occur mid way during the long idle period. + default_task_runner_->PostDelayedTask( + FROM_HERE, base::Bind(&RecordTimelineTask, base::Unretained(&timeline), + base::Unretained(clock_.get())), + base::TimeDelta::FromMilliseconds(420)); + idle_task_runner_->PostIdleTask(FROM_HERE, + base::Bind(&TimelineIdleTestTask, &timeline)); + + RunUntilIdle(); + + std::string expected_timeline[] = { + "CanEnterLongIdlePeriod @ 5", + "Post delayed and idle tasks", + "IsNotQuiescent @ 105", + "CanEnterLongIdlePeriod @ 405", + "run TimelineIdleTestTask deadline 425", // Note the short 20ms deadline. + "CanEnterLongIdlePeriod @ 425", + "run RecordTimelineTask @ 425"}; + + EXPECT_THAT(timeline, ElementsAreArray(expected_timeline)); +} + +TEST_F(WorkerSchedulerImplTest, + TestIdleDeadlineWithPendingDelayedTaskFarInTheFuture) { + std::vector<std::string> timeline; + RecordTimelineEvents(&timeline); + InitAndPostDelayedWakeupTask(); + + timeline.push_back("Post delayed and idle tasks"); + // Post a delayed task timed to occur well after the long idle period. + default_task_runner_->PostDelayedTask( + FROM_HERE, base::Bind(&RecordTimelineTask, base::Unretained(&timeline), + base::Unretained(clock_.get())), + base::TimeDelta::FromMilliseconds(1000)); + idle_task_runner_->PostIdleTask(FROM_HERE, + base::Bind(&TimelineIdleTestTask, &timeline)); + + RunUntilIdle(); + + std::string expected_timeline[] = { + "CanEnterLongIdlePeriod @ 5", + "Post delayed and idle tasks", + "IsNotQuiescent @ 105", + "CanEnterLongIdlePeriod @ 405", + "run TimelineIdleTestTask deadline 455", // Note the full 50ms deadline. + "CanEnterLongIdlePeriod @ 455", + "run RecordTimelineTask @ 1005"}; + + EXPECT_THAT(timeline, ElementsAreArray(expected_timeline)); +} + +TEST_F(WorkerSchedulerImplTest, + TestPostIdleTaskAfterRunningUntilIdle_NoWakeUp) { + InitAndPostDelayedWakeupTask(); + + default_task_runner_->PostDelayedTask( + FROM_HERE, base::Bind(&NopTask), base::TimeDelta::FromMilliseconds(1000)); + RunUntilIdle(); + + // The delayed call to EnableLongIdlePeriod happened and it posted a call to + // EnableLongIdlePeriod on the after wakeup control queue. Without an other + // non-idle task posted, the idle tasks won't run. + std::vector<std::string> run_order; + PostTestTasks(&run_order, "I1 I2"); + + RunUntilIdle(); + EXPECT_TRUE(run_order.empty()); +} + +TEST_F(WorkerSchedulerImplTest, + TestPostIdleTaskAfterRunningUntilIdle_WithWakeUp) { + InitAndPostDelayedWakeupTask(); + + default_task_runner_->PostDelayedTask( + FROM_HERE, base::Bind(&NopTask), base::TimeDelta::FromMilliseconds(1000)); + RunUntilIdle(); + // The delayed call to EnableLongIdlePeriod happened and it posted a call to + // EnableLongIdlePeriod on the after wakeup control queue. Without an other + // non-idle task posted, the idle tasks won't run. + + std::vector<std::string> run_order; + PostTestTasks(&run_order, "I1 I2 D3"); + + RunUntilIdle(); + EXPECT_THAT(run_order, + testing::ElementsAre(std::string("D3"), std::string("I1"), + std::string("I2"))); +} + +TEST_F(WorkerSchedulerImplTest, TestLongIdlePeriodTimeline) { + Init(); + + std::vector<std::string> timeline; + RecordTimelineEvents(&timeline); + + // The scheduler should not run the initiate_next_long_idle_period task if + // there are no idle tasks and no other task woke up the scheduler, thus + // the idle period deadline shouldn't update at the end of the current long + // idle period. + base::TimeTicks idle_period_deadline = + scheduler_->CurrentIdleTaskDeadlineForTesting(); + clock_->AdvanceNow(maximum_idle_period_duration()); + RunUntilIdle(); + + base::TimeTicks new_idle_period_deadline = + scheduler_->CurrentIdleTaskDeadlineForTesting(); + EXPECT_EQ(idle_period_deadline, new_idle_period_deadline); + + // Posting a after-wakeup idle task also shouldn't wake the scheduler or + // initiate the next long idle period. + timeline.push_back("PostIdleTaskAfterWakeup"); + idle_task_runner_->PostIdleTaskAfterWakeup( + FROM_HERE, base::Bind(&TimelineIdleTestTask, &timeline)); + RunUntilIdle(); + new_idle_period_deadline = scheduler_->CurrentIdleTaskDeadlineForTesting(); + + // Running a normal task should initiate a new long idle period after waiting + // 300ms for quiescence. + timeline.push_back("Post RecordTimelineTask"); + default_task_runner_->PostTask( + FROM_HERE, base::Bind(&RecordTimelineTask, base::Unretained(&timeline), + base::Unretained(clock_.get()))); + RunUntilIdle(); + + std::string expected_timeline[] = { + "RunUntilIdle begin @ 55", + "RunUntilIdle end @ 55", + "PostIdleTaskAfterWakeup", + "RunUntilIdle begin @ 55", // NOTE idle task doesn't run till later. + "RunUntilIdle end @ 55", + "Post RecordTimelineTask", + "RunUntilIdle begin @ 55", + "run RecordTimelineTask @ 55", + "IsNotQuiescent @ 55", // NOTE we have to wait for quiescence. + "CanEnterLongIdlePeriod @ 355", + "run TimelineIdleTestTask deadline 405", + "CanEnterLongIdlePeriod @ 405", + "RunUntilIdle end @ 455"}; + + EXPECT_THAT(timeline, ElementsAreArray(expected_timeline)); +} + +} // namespace content diff --git a/content/child/threaded_data_provider.cc b/content/child/threaded_data_provider.cc index 64daeeb..395e452 100644 --- a/content/child/threaded_data_provider.cc +++ b/content/child/threaded_data_provider.cc @@ -7,8 +7,8 @@ #include "content/child/child_process.h" #include "content/child/child_thread_impl.h" #include "content/child/resource_dispatcher.h" +#include "content/child/scheduler/webthread_impl_for_worker_scheduler.h" #include "content/child/thread_safe_sender.h" -#include "content/child/webthread_impl.h" #include "content/common/resource_messages.h" #include "ipc/ipc_sync_channel.h" #include "third_party/WebKit/public/platform/WebThread.h" @@ -23,7 +23,7 @@ class DataProviderMessageFilter : public IPC::MessageFilter { DataProviderMessageFilter( const scoped_refptr<base::MessageLoopProxy>& io_message_loop, scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner, - const WebThreadImpl& background_thread, + const WebThreadImplForWorkerScheduler& background_thread, const base::WeakPtr<ThreadedDataProvider>& background_thread_resource_provider, const base::WeakPtr<ThreadedDataProvider>& main_thread_resource_provider, @@ -41,7 +41,7 @@ class DataProviderMessageFilter : public IPC::MessageFilter { const scoped_refptr<base::MessageLoopProxy> io_message_loop_; scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_; - const WebThreadImpl& background_thread_; + const WebThreadImplForWorkerScheduler& background_thread_; // This weakptr can only be dereferenced on the background thread. base::WeakPtr<ThreadedDataProvider> background_thread_resource_provider_; @@ -54,7 +54,7 @@ class DataProviderMessageFilter : public IPC::MessageFilter { DataProviderMessageFilter::DataProviderMessageFilter( const scoped_refptr<base::MessageLoopProxy>& io_message_loop, scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner, - const WebThreadImpl& background_thread, + const WebThreadImplForWorkerScheduler& background_thread, const base::WeakPtr<ThreadedDataProvider>& background_thread_resource_provider, const base::WeakPtr<ThreadedDataProvider>& main_thread_resource_provider, @@ -126,7 +126,7 @@ ThreadedDataProvider::ThreadedDataProvider( : request_id_(request_id), shm_buffer_(shm_buffer), shm_size_(shm_size), - background_thread_(static_cast<WebThreadImpl&>( + background_thread_(static_cast<WebThreadImplForWorkerScheduler&>( *threaded_data_receiver->backgroundThread())), ipc_channel_(ChildThreadImpl::current()->channel()), threaded_data_receiver_(threaded_data_receiver), @@ -186,7 +186,7 @@ void ThreadedDataProvider::Stop() { // We should never end up with a different parser thread than from when the // ThreadedDataProvider gets created. DCHECK(current_background_thread == - static_cast<WebThreadImpl*>(&background_thread_)); + static_cast<WebThreadImplForWorkerScheduler*>(&background_thread_)); background_thread_.TaskRunner()->PostTask( FROM_HERE, base::Bind(&ThreadedDataProvider::StopOnBackgroundThread, base::Unretained(this))); diff --git a/content/child/threaded_data_provider.h b/content/child/threaded_data_provider.h index 9ac2ac2..effb4f9 100644 --- a/content/child/threaded_data_provider.h +++ b/content/child/threaded_data_provider.h @@ -26,7 +26,7 @@ class SyncChannel; namespace content { class ResourceDispatcher; -class WebThreadImpl; +class WebThreadImplForWorkerScheduler; class ThreadedDataProvider { public: @@ -78,7 +78,7 @@ class ThreadedDataProvider { int shm_size_; scoped_ptr<base::WeakPtrFactory<ThreadedDataProvider> > background_thread_weak_factory_; - WebThreadImpl& background_thread_; + WebThreadImplForWorkerScheduler& background_thread_; IPC::SyncChannel* ipc_channel_; blink::WebThreadedDataReceiver* threaded_data_receiver_; bool resource_filter_active_; diff --git a/content/child/webthread_impl.cc b/content/child/webthread_base.cc index 572e589..818c960 100644 --- a/content/child/webthread_impl.cc +++ b/content/child/webthread_base.cc @@ -5,12 +5,13 @@ // An implementation of WebThread in terms of base::MessageLoop and // base::Thread -#include "content/child/webthread_impl.h" +#include "content/child/webthread_base.h" #include "base/bind.h" #include "base/bind_helpers.h" #include "base/pending_task.h" #include "base/threading/platform_thread.h" +#include "content/child/scheduler/single_thread_idle_task_runner.h" #include "third_party/WebKit/public/platform/WebTraceLocation.h" namespace content { @@ -29,7 +30,7 @@ class WebThreadBase::TaskObserverAdapter observer_->didProcessTask(); } -private: + private: WebThread::TaskObserver* observer_; }; @@ -100,6 +101,13 @@ void WebThreadBase::RunWebThreadTask(scoped_ptr<blink::WebThread::Task> task) { task->run(); } +// static +void WebThreadBase::RunWebThreadIdleTask( + scoped_ptr<blink::WebThread::IdleTask> idle_task, + base::TimeTicks deadline) { + idle_task->run((deadline - base::TimeTicks()).InSecondsF()); +} + void WebThreadBase::postTask(const blink::WebTraceLocation& location, Task* task) { postDelayedTask(location, task, 0); @@ -116,6 +124,25 @@ void WebThreadBase::postDelayedTask(const blink::WebTraceLocation& web_location, base::TimeDelta::FromMilliseconds(delay_ms)); } +void WebThreadBase::postIdleTask(const blink::WebTraceLocation& web_location, + IdleTask* idle_task) { + tracked_objects::Location location(web_location.functionName(), + web_location.fileName(), -1, nullptr); + IdleTaskRunner()->PostIdleTask( + location, base::Bind(&WebThreadBase::RunWebThreadIdleTask, + base::Passed(make_scoped_ptr(idle_task)))); +} + +void WebThreadBase::postIdleTaskAfterWakeup( + const blink::WebTraceLocation& web_location, + IdleTask* idle_task) { + tracked_objects::Location location(web_location.functionName(), + web_location.fileName(), -1, nullptr); + IdleTaskRunner()->PostIdleTaskAfterWakeup( + location, base::Bind(&WebThreadBase::RunWebThreadIdleTask, + base::Passed(make_scoped_ptr(idle_task)))); +} + void WebThreadBase::enterRunLoop() { CHECK(isCurrentThread()); CHECK(MessageLoop()); @@ -134,25 +161,4 @@ bool WebThreadBase::isCurrentThread() const { return TaskRunner()->BelongsToCurrentThread(); } -blink::PlatformThreadId WebThreadImpl::threadId() const { - return thread_->thread_id(); -} - -WebThreadImpl::WebThreadImpl(const char* name) - : thread_(new base::Thread(name)) { - thread_->Start(); -} - -WebThreadImpl::~WebThreadImpl() { - thread_->Stop(); -} - -base::MessageLoop* WebThreadImpl::MessageLoop() const { - return nullptr; -} - -base::SingleThreadTaskRunner* WebThreadImpl::TaskRunner() const { - return thread_->message_loop_proxy().get(); -} - } // namespace content diff --git a/content/child/webthread_impl.h b/content/child/webthread_base.h index c502952..5d6ebb9b 100644 --- a/content/child/webthread_impl.h +++ b/content/child/webthread_base.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CONTENT_CHILD_WEBTHREAD_IMPL_H_ -#define CONTENT_CHILD_WEBTHREAD_IMPL_H_ +#ifndef CONTENT_CHILD_WEBTHREAD_BASE_H_ +#define CONTENT_CHILD_WEBTHREAD_BASE_H_ #include <map> @@ -17,6 +17,7 @@ class WebTraceLocation; } namespace content { +class SingleThreadIdleTaskRunner; class CONTENT_EXPORT WebThreadBase : public blink::WebThread { public: @@ -30,6 +31,10 @@ class CONTENT_EXPORT WebThreadBase : public blink::WebThread { virtual void postDelayedTask(const blink::WebTraceLocation& location, Task* task, long long delay_ms); + virtual void postIdleTask(const blink::WebTraceLocation& location, + IdleTask* idle_task); + virtual void postIdleTaskAfterWakeup(const blink::WebTraceLocation& location, + IdleTask* idle_task); virtual void enterRunLoop(); virtual void exitRunLoop(); @@ -41,6 +46,10 @@ class CONTENT_EXPORT WebThreadBase : public blink::WebThread { // thread. Can be called from any thread. virtual base::SingleThreadTaskRunner* TaskRunner() const = 0; + // Returns the base::Bind-compatible task runner for posting idle tasks to + // this thread. Can be called from any thread. + virtual SingleThreadIdleTaskRunner* IdleTaskRunner() const = 0; + protected: class TaskObserverAdapter; @@ -57,29 +66,15 @@ class CONTENT_EXPORT WebThreadBase : public blink::WebThread { base::MessageLoop::TaskObserver* observer); static void RunWebThreadTask(scoped_ptr<blink::WebThread::Task> task); + static void RunWebThreadIdleTask( + scoped_ptr<blink::WebThread::IdleTask> idle_task, + base::TimeTicks deadline); private: typedef std::map<TaskObserver*, TaskObserverAdapter*> TaskObserverMap; TaskObserverMap task_observer_map_; }; -class CONTENT_EXPORT WebThreadImpl : public WebThreadBase { - public: - explicit WebThreadImpl(const char* name); - virtual ~WebThreadImpl(); - - // blink::WebThread implementation. - blink::PlatformThreadId threadId() const override; - - // WebThreadBase implementation. - base::SingleThreadTaskRunner* TaskRunner() const override; - - private: - base::MessageLoop* MessageLoop() const override; - - scoped_ptr<base::Thread> thread_; -}; - -} // namespace content +} // namespace content -#endif // CONTENT_CHILD_WEBTHREAD_IMPL_H_ +#endif // CONTENT_CHILD_WEBTHREAD_BASE_H_ diff --git a/content/content_child.gypi b/content/content_child.gypi index 769cf3e..92269c1 100644 --- a/content/content_child.gypi +++ b/content/content_child.gypi @@ -194,6 +194,8 @@ 'child/scheduler/nestable_single_thread_task_runner.h', 'child/scheduler/null_idle_task_runner.cc', 'child/scheduler/null_idle_task_runner.h', + 'child/scheduler/null_worker_scheduler.cc', + 'child/scheduler/null_worker_scheduler.h', 'child/scheduler/prioritizing_task_queue_selector.cc', 'child/scheduler/prioritizing_task_queue_selector.h', 'child/scheduler/scheduler_helper.cc', @@ -205,6 +207,12 @@ 'child/scheduler/task_queue_selector.h', 'child/scheduler/task_queue_manager.cc', 'child/scheduler/task_queue_manager.h', + 'child/scheduler/webthread_impl_for_worker_scheduler.cc', + 'child/scheduler/webthread_impl_for_worker_scheduler.h', + 'child/scheduler/worker_scheduler.cc', + 'child/scheduler/worker_scheduler.h', + 'child/scheduler/worker_scheduler_impl.cc', + 'child/scheduler/worker_scheduler_impl.h', 'child/resource_dispatcher.cc', 'child/resource_dispatcher.h', 'child/resource_scheduling_filter.cc', @@ -291,8 +299,8 @@ 'child/webthemeengine_impl_default.cc', 'child/webthemeengine_impl_default.h', 'child/webthemeengine_impl_mac.h', - 'child/webthread_impl.cc', - 'child/webthread_impl.h', + 'child/webthread_base.cc', + 'child/webthread_base.h', 'child/weburlresponse_extradata_impl.cc', 'child/weburlresponse_extradata_impl.h', 'child/worker_task_runner.cc', diff --git a/content/content_renderer.gypi b/content/content_renderer.gypi index 5491340..879cba6 100644 --- a/content/content_renderer.gypi +++ b/content/content_renderer.gypi @@ -383,8 +383,8 @@ 'renderer/scheduler/resource_dispatch_throttler.h', 'renderer/scheduler/web_scheduler_impl.cc', 'renderer/scheduler/web_scheduler_impl.h', - 'renderer/scheduler/webthread_impl_for_scheduler.cc', - 'renderer/scheduler/webthread_impl_for_scheduler.h', + 'renderer/scheduler/webthread_impl_for_renderer_scheduler.cc', + 'renderer/scheduler/webthread_impl_for_renderer_scheduler.h', 'renderer/screen_orientation/screen_orientation_dispatcher.cc', 'renderer/screen_orientation/screen_orientation_dispatcher.h', 'renderer/screen_orientation/screen_orientation_observer.cc', diff --git a/content/content_tests.gypi b/content/content_tests.gypi index 1b68294..4dd854f 100644 --- a/content/content_tests.gypi +++ b/content/content_tests.gypi @@ -587,6 +587,8 @@ 'child/scheduler/prioritizing_task_queue_selector_unittest.cc', 'child/scheduler/scheduler_helper_unittest.cc', 'child/scheduler/task_queue_manager_unittest.cc', + 'child/scheduler/webthread_impl_for_worker_scheduler_unittest.cc', + 'child/scheduler/worker_scheduler_impl_unittest.cc', 'child/service_worker/service_worker_dispatcher_unittest.cc', 'child/simple_webmimeregistry_impl_unittest.cc', 'child/site_isolation_policy_unittest.cc', @@ -675,7 +677,7 @@ 'renderer/scheduler/deadline_task_runner_unittest.cc', 'renderer/scheduler/renderer_scheduler_impl_unittest.cc', 'renderer/scheduler/resource_dispatch_throttler_unittest.cc', - 'renderer/scheduler/webthread_impl_for_scheduler_unittest.cc', + 'renderer/scheduler/webthread_impl_for_renderer_scheduler_unittest.cc', 'renderer/screen_orientation/screen_orientation_dispatcher_unittest.cc', 'renderer/skia_benchmarking_extension_unittest.cc', 'test/fileapi_test_file_set.cc', diff --git a/content/renderer/renderer_blink_platform_impl.cc b/content/renderer/renderer_blink_platform_impl.cc index 19f1a54..ca7e1b8 100644 --- a/content/renderer/renderer_blink_platform_impl.cc +++ b/content/renderer/renderer_blink_platform_impl.cc @@ -53,7 +53,7 @@ #include "content/renderer/renderer_clipboard_delegate.h" #include "content/renderer/scheduler/renderer_scheduler.h" #include "content/renderer/scheduler/web_scheduler_impl.h" -#include "content/renderer/scheduler/webthread_impl_for_scheduler.h" +#include "content/renderer/scheduler/webthread_impl_for_renderer_scheduler.h" #include "content/renderer/screen_orientation/screen_orientation_observer.h" #include "content/renderer/webclipboard_impl.h" #include "content/renderer/webgraphicscontext3d_provider_impl.h" @@ -224,7 +224,7 @@ RendererBlinkPlatformImpl::RendererBlinkPlatformImpl( RendererScheduler* renderer_scheduler) : BlinkPlatformImpl(renderer_scheduler->DefaultTaskRunner()), web_scheduler_(new WebSchedulerImpl(renderer_scheduler)), - main_thread_(new WebThreadImplForScheduler(renderer_scheduler)), + main_thread_(new WebThreadImplForRendererScheduler(renderer_scheduler)), clipboard_delegate_(new RendererClipboardDelegate), clipboard_(new WebClipboardImpl(clipboard_delegate_.get())), mime_registry_(new RendererBlinkPlatformImpl::MimeRegistry), diff --git a/content/renderer/renderer_blink_platform_impl.h b/content/renderer/renderer_blink_platform_impl.h index f91e8cf..f668a71 100644 --- a/content/renderer/renderer_blink_platform_impl.h +++ b/content/renderer/renderer_blink_platform_impl.h @@ -51,7 +51,7 @@ class ThreadSafeSender; class WebClipboardImpl; class WebDatabaseObserverImpl; class WebFileSystemImpl; -class WebThreadImplForScheduler; +class WebThreadImplForRendererScheduler; class WebSchedulerImpl; class CONTENT_EXPORT RendererBlinkPlatformImpl : public BlinkPlatformImpl { @@ -211,7 +211,7 @@ class CONTENT_EXPORT RendererBlinkPlatformImpl : public BlinkPlatformImpl { device::VibrationManagerPtr& GetConnectedVibrationManagerService(); scoped_ptr<WebSchedulerImpl> web_scheduler_; - scoped_ptr<WebThreadImplForScheduler> main_thread_; + scoped_ptr<WebThreadImplForRendererScheduler> main_thread_; scoped_ptr<RendererClipboardDelegate> clipboard_delegate_; scoped_ptr<WebClipboardImpl> clipboard_; diff --git a/content/renderer/scheduler/renderer_scheduler_impl.h b/content/renderer/scheduler/renderer_scheduler_impl.h index e4fd630..9c3fc12 100644 --- a/content/renderer/scheduler/renderer_scheduler_impl.h +++ b/content/renderer/scheduler/renderer_scheduler_impl.h @@ -99,6 +99,7 @@ class CONTENT_EXPORT RendererSchedulerImpl bool CanEnterLongIdlePeriod( base::TimeTicks now, base::TimeDelta* next_long_idle_period_delay_out) override; + void IsNotQuiescent() override {} // Returns the serialized scheduler state for tracing. scoped_refptr<base::trace_event::ConvertableToTraceFormat> AsValueLocked( diff --git a/content/renderer/scheduler/webthread_impl_for_scheduler.cc b/content/renderer/scheduler/webthread_impl_for_renderer_scheduler.cc index b328142..4855df19 100644 --- a/content/renderer/scheduler/webthread_impl_for_scheduler.cc +++ b/content/renderer/scheduler/webthread_impl_for_renderer_scheduler.cc @@ -2,42 +2,49 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "content/renderer/scheduler/webthread_impl_for_scheduler.h" +#include "content/renderer/scheduler/webthread_impl_for_renderer_scheduler.h" #include "content/renderer/scheduler/renderer_scheduler.h" #include "third_party/WebKit/public/platform/WebTraceLocation.h" namespace content { -WebThreadImplForScheduler::WebThreadImplForScheduler( +WebThreadImplForRendererScheduler::WebThreadImplForRendererScheduler( RendererScheduler* scheduler) : task_runner_(scheduler->DefaultTaskRunner()), + idle_task_runner_(scheduler->IdleTaskRunner()), scheduler_(scheduler), thread_id_(base::PlatformThread::CurrentId()) { } -WebThreadImplForScheduler::~WebThreadImplForScheduler() { +WebThreadImplForRendererScheduler::~WebThreadImplForRendererScheduler() { } -blink::PlatformThreadId WebThreadImplForScheduler::threadId() const { +blink::PlatformThreadId WebThreadImplForRendererScheduler::threadId() const { return thread_id_; } -base::MessageLoop* WebThreadImplForScheduler::MessageLoop() const { +base::MessageLoop* WebThreadImplForRendererScheduler::MessageLoop() const { DCHECK(isCurrentThread()); return base::MessageLoop::current(); } -base::SingleThreadTaskRunner* WebThreadImplForScheduler::TaskRunner() const { +base::SingleThreadTaskRunner* WebThreadImplForRendererScheduler::TaskRunner() + const { return task_runner_.get(); } -void WebThreadImplForScheduler::AddTaskObserverInternal( +SingleThreadIdleTaskRunner* WebThreadImplForRendererScheduler::IdleTaskRunner() + const { + return idle_task_runner_.get(); +} + +void WebThreadImplForRendererScheduler::AddTaskObserverInternal( base::MessageLoop::TaskObserver* observer) { scheduler_->AddTaskObserver(observer); } -void WebThreadImplForScheduler::RemoveTaskObserverInternal( +void WebThreadImplForRendererScheduler::RemoveTaskObserverInternal( base::MessageLoop::TaskObserver* observer) { scheduler_->RemoveTaskObserver(observer); } diff --git a/content/renderer/scheduler/webthread_impl_for_scheduler.h b/content/renderer/scheduler/webthread_impl_for_renderer_scheduler.h index 36bd2e2..4b8d9fb 100644 --- a/content/renderer/scheduler/webthread_impl_for_scheduler.h +++ b/content/renderer/scheduler/webthread_impl_for_renderer_scheduler.h @@ -2,27 +2,27 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CONTENT_RENDERER_SCHEDULER_WEBTHREAD_IMPL_FOR_SCHEDULER_H_ -#define CONTENT_RENDERER_SCHEDULER_WEBTHREAD_IMPL_FOR_SCHEDULER_H_ - -#include "content/child/webthread_impl.h" +#ifndef CONTENT_RENDERER_SCHEDULER_WEBTHREAD_IMPL_FOR_RENDERER_SCHEDULER_H_ +#define CONTENT_RENDERER_SCHEDULER_WEBTHREAD_IMPL_FOR_RENDERER_SCHEDULER_H_ #include "base/containers/scoped_ptr_hash_map.h" +#include "content/child/webthread_base.h" namespace content { class RendererScheduler; -class CONTENT_EXPORT WebThreadImplForScheduler : public WebThreadBase { +class CONTENT_EXPORT WebThreadImplForRendererScheduler : public WebThreadBase { public: - explicit WebThreadImplForScheduler(RendererScheduler* scheduler); - virtual ~WebThreadImplForScheduler(); + explicit WebThreadImplForRendererScheduler(RendererScheduler* scheduler); + virtual ~WebThreadImplForRendererScheduler(); // blink::WebThread implementation. blink::PlatformThreadId threadId() const override; // WebThreadBase implementation. base::SingleThreadTaskRunner* TaskRunner() const override; + SingleThreadIdleTaskRunner* IdleTaskRunner() const override; private: base::MessageLoop* MessageLoop() const override; @@ -32,10 +32,11 @@ class CONTENT_EXPORT WebThreadImplForScheduler : public WebThreadBase { base::MessageLoop::TaskObserver* observer) override; scoped_refptr<base::SingleThreadTaskRunner> task_runner_; + scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner_; RendererScheduler* scheduler_; // Not owned. blink::PlatformThreadId thread_id_; }; } // namespace content -#endif // CONTENT_RENDERER_SCHEDULER_WEBTHREAD_IMPL_FOR_SCHEDULER_H_ +#endif // CONTENT_RENDERER_SCHEDULER_WEBTHREAD_IMPL_FOR_RENDERER_SCHEDULER_H_ diff --git a/content/renderer/scheduler/webthread_impl_for_scheduler_unittest.cc b/content/renderer/scheduler/webthread_impl_for_renderer_scheduler_unittest.cc index e9e359a..191a271 100644 --- a/content/renderer/scheduler/webthread_impl_for_scheduler_unittest.cc +++ b/content/renderer/scheduler/webthread_impl_for_renderer_scheduler_unittest.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "content/renderer/scheduler/webthread_impl_for_scheduler.h" +#include "content/renderer/scheduler/webthread_impl_for_renderer_scheduler.h" #include "base/run_loop.h" #include "content/child/scheduler/scheduler_message_loop_delegate.h" @@ -28,14 +28,14 @@ class MockTaskObserver : public blink::WebThread::TaskObserver { }; } // namespace -class WebThreadImplForSchedulerTest : public testing::Test { +class WebThreadImplForRendererSchedulerTest : public testing::Test { public: - WebThreadImplForSchedulerTest() + WebThreadImplForRendererSchedulerTest() : scheduler_(SchedulerMessageLoopDelegate::Create(&message_loop_)), default_task_runner_(scheduler_.DefaultTaskRunner()), thread_(&scheduler_) {} - ~WebThreadImplForSchedulerTest() override {} + ~WebThreadImplForRendererSchedulerTest() override {} void SetWorkBatchSizeForTesting(size_t work_batch_size) { scheduler_.SetWorkBatchSizeForTesting(work_batch_size); @@ -51,12 +51,12 @@ class WebThreadImplForSchedulerTest : public testing::Test { base::MessageLoop message_loop_; RendererSchedulerImpl scheduler_; scoped_refptr<base::SingleThreadTaskRunner> default_task_runner_; - WebThreadImplForScheduler thread_; + WebThreadImplForRendererScheduler thread_; - DISALLOW_COPY_AND_ASSIGN(WebThreadImplForSchedulerTest); + DISALLOW_COPY_AND_ASSIGN(WebThreadImplForRendererSchedulerTest); }; -TEST_F(WebThreadImplForSchedulerTest, TestTaskObserver) { +TEST_F(WebThreadImplForRendererSchedulerTest, TestTaskObserver) { MockTaskObserver observer; thread_.addTaskObserver(&observer); scoped_ptr<MockTask> task(new MockTask()); @@ -75,7 +75,7 @@ TEST_F(WebThreadImplForSchedulerTest, TestTaskObserver) { thread_.removeTaskObserver(&observer); } -TEST_F(WebThreadImplForSchedulerTest, TestWorkBatchWithOneTask) { +TEST_F(WebThreadImplForRendererSchedulerTest, TestWorkBatchWithOneTask) { MockTaskObserver observer; thread_.addTaskObserver(&observer); scoped_ptr<MockTask> task(new MockTask()); @@ -95,7 +95,7 @@ TEST_F(WebThreadImplForSchedulerTest, TestWorkBatchWithOneTask) { thread_.removeTaskObserver(&observer); } -TEST_F(WebThreadImplForSchedulerTest, TestWorkBatchWithTwoTasks) { +TEST_F(WebThreadImplForRendererSchedulerTest, TestWorkBatchWithTwoTasks) { MockTaskObserver observer; thread_.addTaskObserver(&observer); scoped_ptr<MockTask> task1(new MockTask()); @@ -121,7 +121,7 @@ TEST_F(WebThreadImplForSchedulerTest, TestWorkBatchWithTwoTasks) { thread_.removeTaskObserver(&observer); } -TEST_F(WebThreadImplForSchedulerTest, TestWorkBatchWithThreeTasks) { +TEST_F(WebThreadImplForRendererSchedulerTest, TestWorkBatchWithThreeTasks) { MockTaskObserver observer; thread_.addTaskObserver(&observer); scoped_ptr<MockTask> task1(new MockTask()); @@ -172,7 +172,7 @@ void EnterRunLoop(base::MessageLoop* message_loop, blink::WebThread* thread) { run_loop.Run(); } -TEST_F(WebThreadImplForSchedulerTest, TestNestedRunLoop) { +TEST_F(WebThreadImplForRendererSchedulerTest, TestNestedRunLoop) { MockTaskObserver observer; thread_.addTaskObserver(&observer); diff --git a/content/test/test_blink_web_unit_test_support.cc b/content/test/test_blink_web_unit_test_support.cc index 1326e7d..35ed7a7 100644 --- a/content/test/test_blink_web_unit_test_support.cc +++ b/content/test/test_blink_web_unit_test_support.cc @@ -11,7 +11,7 @@ #include "base/strings/utf_string_conversions.h" #include "content/renderer/scheduler/renderer_scheduler.h" #include "content/renderer/scheduler/web_scheduler_impl.h" -#include "content/renderer/scheduler/webthread_impl_for_scheduler.h" +#include "content/renderer/scheduler/webthread_impl_for_renderer_scheduler.h" #include "content/test/mock_webclipboard_impl.h" #include "content/test/web_gesture_curve_mock.h" #include "content/test/web_layer_tree_view_impl_for_testing.h" @@ -59,7 +59,8 @@ TestBlinkWebUnitTestSupport::TestBlinkWebUnitTestSupport() { if (base::MessageLoopProxy::current()) { renderer_scheduler_ = RendererScheduler::Create(); web_scheduler_.reset(new WebSchedulerImpl(renderer_scheduler_.get())); - web_thread_.reset(new WebThreadImplForScheduler(renderer_scheduler_.get())); + web_thread_.reset( + new WebThreadImplForRendererScheduler(renderer_scheduler_.get())); } blink::initialize(this); |