Index: third_party/WebKit/Source/platform/WebTaskRunner.cpp |
diff --git a/third_party/WebKit/Source/platform/WebTaskRunner.cpp b/third_party/WebKit/Source/platform/WebTaskRunner.cpp |
index 548dbc9ac1d500a31170856fbe2966d1ce612059..61b4f455802da021a16bb97614efc61db01fa3e2 100644 |
--- a/third_party/WebKit/Source/platform/WebTaskRunner.cpp |
+++ b/third_party/WebKit/Source/platform/WebTaskRunner.cpp |
@@ -6,6 +6,66 @@ |
namespace blink { |
+// This class holds a reference to a TaskHandle to keep it alive while a task is |
+// pending in a task queue, and clears the reference on the task disposal, so |
+// that it doesn't leave a circular reference like below: |
+// struct Foo : GarbageCollected<Foo> { |
+// void bar() {} |
+// RefPtr<TaskHandle> m_handle; |
+// }; |
+// |
+// foo->m_handle = taskRunner->postCancellableTask( |
+// BLINK_FROM_HERE, WTF::bind(&Foo::bar, wrapPersistent(foo))); |
+// |
+// There is a circular reference in the example above as: |
+// foo -> m_handle -> m_task -> Persistent<Foo> in WTF::bind. |
+// CancelOnTaskDestruction is needed to break the circle by clearing |m_task| |
+// when the wrapped WTF::Closure is deleted. |
+class TaskHandle::CancelOnTaskDestruction { |
+ public: |
+ explicit CancelOnTaskDestruction(RefPtr<TaskHandle> handle) |
+ : m_handle(std::move(handle)) {} |
+ |
+ CancelOnTaskDestruction(CancelOnTaskDestruction&&) = default; |
+ |
+ void cancel() const { |
+ if (m_handle) |
+ m_handle->cancel(); |
+ } |
+ |
+ ~CancelOnTaskDestruction() { cancel(); } |
+ |
+ private: |
+ RefPtr<TaskHandle> m_handle; |
+ DISALLOW_COPY_AND_ASSIGN(CancelOnTaskDestruction); |
+}; |
+ |
+bool TaskHandle::isActive() const { |
+ return static_cast<bool>(m_task); |
+} |
+ |
+void TaskHandle::cancel() { |
+ std::unique_ptr<WTF::Closure> task = std::move(m_task); |
+ m_weakPtrFactory.revokeAll(); |
+} |
+ |
+TaskHandle::~TaskHandle() {} |
+ |
+TaskHandle::TaskHandle(std::unique_ptr<WTF::Closure> task) |
+ : m_task(std::move(task)), m_weakPtrFactory(this) { |
+ DCHECK(m_task); |
+} |
+ |
+void TaskHandle::run(const CancelOnTaskDestruction& scoper) { |
+ std::unique_ptr<WTF::Closure> task = std::move(m_task); |
+ cancel(); |
+ (*task)(); |
+} |
+ |
+WTF::WeakPtr<TaskHandle> TaskHandle::asWeakPtr() { |
+ return m_weakPtrFactory.createWeakPtr(); |
+} |
+ |
void WebTaskRunner::postTask(const WebTraceLocation& location, |
std::unique_ptr<CrossThreadClosure> task) { |
toSingleThreadTaskRunner()->PostTask(location, |
@@ -34,4 +94,27 @@ void WebTaskRunner::postDelayedTask(const WebTraceLocation& location, |
base::TimeDelta::FromMilliseconds(delayMs)); |
} |
+RefPtr<TaskHandle> WebTaskRunner::postCancellableTask( |
+ const WebTraceLocation& location, |
+ std::unique_ptr<WTF::Closure> task) { |
+ DCHECK(runsTasksOnCurrentThread()); |
+ RefPtr<TaskHandle> handle = adoptRef(new TaskHandle(std::move(task))); |
+ postTask(location, WTF::bind(&TaskHandle::run, handle->asWeakPtr(), |
+ TaskHandle::CancelOnTaskDestruction(handle))); |
+ return handle; |
+} |
+ |
+RefPtr<TaskHandle> WebTaskRunner::postDelayedCancellableTask( |
+ const WebTraceLocation& location, |
+ std::unique_ptr<WTF::Closure> task, |
+ long long delayMs) { |
+ DCHECK(runsTasksOnCurrentThread()); |
+ RefPtr<TaskHandle> handle = adoptRef(new TaskHandle(std::move(task))); |
+ postDelayedTask(location, |
+ WTF::bind(&TaskHandle::run, handle->asWeakPtr(), |
+ TaskHandle::CancelOnTaskDestruction(handle)), |
+ delayMs); |
+ return handle; |
+} |
+ |
} // namespace blink |