Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / third_party / WebKit / Source / core / dom / ScriptedIdleTaskController.cpp
blob74eadc0252a86534de5bc5f5d028a065955761fe
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "config.h"
6 #include "core/dom/ScriptedIdleTaskController.h"
8 #include "core/dom/ExecutionContext.h"
9 #include "core/dom/IdleRequestCallback.h"
10 #include "platform/Logging.h"
11 #include "platform/TraceEvent.h"
12 #include "public/platform/Platform.h"
13 #include "public/platform/WebScheduler.h"
14 #include "public/platform/WebTraceLocation.h"
15 #include "wtf/CurrentTime.h"
16 #include "wtf/Functional.h"
18 namespace blink {
20 namespace internal {
22 class IdleRequestCallbackWrapper : public RefCounted<IdleRequestCallbackWrapper> {
23 public:
24 static PassRefPtr<IdleRequestCallbackWrapper> create(ScriptedIdleTaskController::CallbackId id, PassRefPtrWillBeRawPtr<ScriptedIdleTaskController> controller)
26 return adoptRef(new IdleRequestCallbackWrapper(id, controller));
28 virtual ~IdleRequestCallbackWrapper()
32 static void idleTaskFired(PassRefPtr<IdleRequestCallbackWrapper> callbackWrapper, double deadlineSeconds)
34 // TODO(rmcilroy): Implement clamping of deadline in some form.
35 callbackWrapper->controller()->callbackFired(callbackWrapper->id(), deadlineSeconds, IdleDeadline::CallbackType::CalledWhenIdle);
38 static void timeoutFired(PassRefPtr<IdleRequestCallbackWrapper> callbackWrapper)
40 callbackWrapper->controller()->callbackFired(callbackWrapper->id(), monotonicallyIncreasingTime(), IdleDeadline::CallbackType::CalledByTimeout);
43 ScriptedIdleTaskController::CallbackId id() const { return m_id; }
44 PassRefPtrWillBeRawPtr<ScriptedIdleTaskController> controller() const { return m_controller; }
46 private:
47 IdleRequestCallbackWrapper(ScriptedIdleTaskController::CallbackId id, PassRefPtrWillBeRawPtr<ScriptedIdleTaskController> controller)
48 : m_id(id)
49 , m_controller(controller)
53 ScriptedIdleTaskController::CallbackId m_id;
54 RefPtrWillBePersistent<ScriptedIdleTaskController> m_controller;
57 } // namespace internal
59 ScriptedIdleTaskController::ScriptedIdleTaskController(ExecutionContext* context)
60 : ActiveDOMObject(context)
61 , m_scheduler(Platform::current()->currentThread()->scheduler())
62 , m_nextCallbackId(0)
63 , m_suspended(false)
65 suspendIfNeeded();
68 ScriptedIdleTaskController::~ScriptedIdleTaskController()
72 DEFINE_TRACE(ScriptedIdleTaskController)
74 visitor->trace(m_callbacks);
75 ActiveDOMObject::trace(visitor);
78 ScriptedIdleTaskController::CallbackId ScriptedIdleTaskController::registerCallback(IdleRequestCallback* callback, double timeoutMillis)
80 CallbackId id = ++m_nextCallbackId;
81 m_callbacks.set(id, callback);
83 RefPtr<internal::IdleRequestCallbackWrapper> callbackWrapper = internal::IdleRequestCallbackWrapper::create(id, this);
84 m_scheduler->postIdleTask(FROM_HERE, WTF::bind<double>(&internal::IdleRequestCallbackWrapper::idleTaskFired, callbackWrapper));
85 if (timeoutMillis > 0)
86 m_scheduler->timerTaskRunner()->postDelayedTask(FROM_HERE, WTF::bind(&internal::IdleRequestCallbackWrapper::timeoutFired, callbackWrapper), static_cast<long long>(timeoutMillis));
88 // TODO(rmcilroy): Add devtools tracing.
89 return id;
92 void ScriptedIdleTaskController::cancelCallback(CallbackId id)
94 // TODO(rmcilroy): Add devtools tracing.
95 m_callbacks.remove(id);
98 void ScriptedIdleTaskController::callbackFired(CallbackId id, double deadlineSeconds, IdleDeadline::CallbackType callbackType)
100 if (!m_callbacks.contains(id))
101 return;
103 if (m_suspended) {
104 if (callbackType == IdleDeadline::CallbackType::CalledByTimeout) {
105 // Queue for execution when we are resumed.
106 m_pendingTimeouts.append(id);
108 // Just drop callbacks called while suspended, these will be reposted on the idle task queue when we are resumed.
109 return;
112 runCallback(id, deadlineSeconds, callbackType);
115 void ScriptedIdleTaskController::runCallback(CallbackId id, double deadlineSeconds, IdleDeadline::CallbackType callbackType)
117 ASSERT(!m_suspended);
118 auto callback = m_callbacks.take(id);
119 if (!callback)
120 return;
122 double allotedTimeMillis = std::max((deadlineSeconds - monotonicallyIncreasingTime()) * 1000, 0.0);
123 Platform::current()->histogramCustomCounts("WebCore.ScriptedIdleTaskController.IdleCallbackDeadline", allotedTimeMillis, 0, 50, 50);
125 // TODO(rmcilroy): Add devtools tracing.
126 callback->handleEvent(IdleDeadline::create(deadlineSeconds, callbackType));
128 double overrunMillis = std::max((monotonicallyIncreasingTime() - deadlineSeconds) * 1000, 0.0);
129 Platform::current()->histogramCustomCounts("WebCore.ScriptedIdleTaskController.IdleCallbackOverrun", overrunMillis, 0, 10000, 50);
132 void ScriptedIdleTaskController::stop()
134 m_callbacks.clear();
137 void ScriptedIdleTaskController::suspend()
139 m_suspended = true;
142 void ScriptedIdleTaskController::resume()
144 ASSERT(m_suspended);
145 m_suspended = false;
147 // Run any pending timeouts.
148 Vector<CallbackId> pendingTimeouts;
149 m_pendingTimeouts.swap(pendingTimeouts);
150 for (auto& id : pendingTimeouts)
151 runCallback(id, monotonicallyIncreasingTime(), IdleDeadline::CallbackType::CalledByTimeout);
153 // Repost idle tasks for any remaining callbacks.
154 for (auto& callback : m_callbacks) {
155 RefPtr<internal::IdleRequestCallbackWrapper> callbackWrapper = internal::IdleRequestCallbackWrapper::create(callback.key, this);
156 m_scheduler->postIdleTask(FROM_HERE, WTF::bind<double>(&internal::IdleRequestCallbackWrapper::idleTaskFired, callbackWrapper));
160 bool ScriptedIdleTaskController::hasPendingActivity() const
162 return !m_callbacks.isEmpty();
165 } // namespace blink