summaryrefslogtreecommitdiffstats
path: root/dom/webscheduling/WebTaskScheduler.h
diff options
context:
space:
mode:
Diffstat (limited to 'dom/webscheduling/WebTaskScheduler.h')
-rw-r--r--dom/webscheduling/WebTaskScheduler.h172
1 files changed, 172 insertions, 0 deletions
diff --git a/dom/webscheduling/WebTaskScheduler.h b/dom/webscheduling/WebTaskScheduler.h
new file mode 100644
index 0000000000..fcddd09d36
--- /dev/null
+++ b/dom/webscheduling/WebTaskScheduler.h
@@ -0,0 +1,172 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:expandtab:shiftwidth=2:tabstop=2:
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_WebTaskScheduler_h
+#define mozilla_dom_WebTaskScheduler_h
+
+#include "nsThreadUtils.h"
+#include "nsPIDOMWindow.h"
+#include "nsWrapperCache.h"
+#include "nsClassHashtable.h"
+
+#include "mozilla/dom/Promise.h"
+#include "mozilla/dom/AbortFollower.h"
+#include "mozilla/dom/TimeoutHandler.h"
+#include "mozilla/dom/WebTaskSchedulingBinding.h"
+
+namespace mozilla::dom {
+class WebTask : public LinkedListElement<RefPtr<WebTask>>,
+ public AbortFollower,
+ public SupportsWeakPtr {
+ friend class WebTaskScheduler;
+
+ public:
+ MOZ_CAN_RUN_SCRIPT bool Run();
+
+ NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+
+ NS_DECL_CYCLE_COLLECTION_CLASS(WebTask)
+ WebTask(uint32_t aEnqueueOrder, SchedulerPostTaskCallback& aCallback,
+ Promise* aPromise)
+ : mEnqueueOrder(aEnqueueOrder),
+ mCallback(&aCallback),
+ mPromise(aPromise),
+ mHasScheduled(false) {}
+
+ void RunAbortAlgorithm() override;
+
+ bool HasScheduled() const { return mHasScheduled; }
+
+ uint32_t EnqueueOrder() const { return mEnqueueOrder; }
+
+ private:
+ void SetHasScheduled(bool aHasScheduled) { mHasScheduled = aHasScheduled; }
+
+ uint32_t mEnqueueOrder;
+
+ RefPtr<SchedulerPostTaskCallback> mCallback;
+ RefPtr<Promise> mPromise;
+
+ bool mHasScheduled;
+
+ ~WebTask() = default;
+};
+
+class WebTaskQueue {
+ public:
+ WebTaskQueue() = default;
+
+ TaskPriority Priority() const { return mPriority; }
+ void SetPriority(TaskPriority aNewPriority) { mPriority = aNewPriority; }
+
+ LinkedList<RefPtr<WebTask>>& Tasks() { return mTasks; }
+
+ void AddTask(WebTask* aTask) { mTasks.insertBack(aTask); }
+
+ // TODO: To optimize it, we could have the scheduled and unscheduled
+ // tasks stored separately.
+ WebTask* GetFirstScheduledTask() {
+ for (const auto& task : mTasks) {
+ if (task->HasScheduled()) {
+ return task;
+ }
+ }
+ return nullptr;
+ }
+
+ ~WebTaskQueue() { mTasks.clear(); }
+
+ private:
+ TaskPriority mPriority = TaskPriority::User_visible;
+ LinkedList<RefPtr<WebTask>> mTasks;
+};
+
+class WebTaskSchedulerMainThread;
+class WebTaskSchedulerWorker;
+
+class WebTaskScheduler : public nsWrapperCache, public SupportsWeakPtr {
+ friend class DelayedWebTaskHandler;
+
+ public:
+ NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebTaskScheduler)
+ NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebTaskScheduler)
+
+ static already_AddRefed<WebTaskSchedulerMainThread> CreateForMainThread(
+ nsGlobalWindowInner* aWindow);
+
+ static already_AddRefed<WebTaskSchedulerWorker> CreateForWorker(
+ WorkerPrivate* aWorkerPrivate);
+
+ explicit WebTaskScheduler(nsIGlobalObject* aParent);
+
+ already_AddRefed<Promise> PostTask(SchedulerPostTaskCallback& aCallback,
+ const SchedulerPostTaskOptions& aOptions);
+
+ nsIGlobalObject* GetParentObject() const { return mParent; }
+
+ virtual JSObject* WrapObject(JSContext* cx,
+ JS::Handle<JSObject*> aGivenProto) override;
+
+ WebTask* GetNextTask() const;
+
+ void Disconnect();
+
+ void RunTaskSignalPriorityChange(TaskSignal* aTaskSignal);
+
+ protected:
+ virtual ~WebTaskScheduler() = default;
+ nsCOMPtr<nsIGlobalObject> mParent;
+
+ uint32_t mNextEnqueueOrder;
+
+ private:
+ already_AddRefed<WebTask> CreateTask(
+ WebTaskQueue& aQueue, const Optional<OwningNonNull<AbortSignal>>& aSignal,
+ SchedulerPostTaskCallback& aCallback, Promise* aPromise);
+
+ bool QueueTask(WebTask* aTask);
+
+ WebTaskQueue& SelectTaskQueue(
+ const Optional<OwningNonNull<AbortSignal>>& aSignal,
+ const Optional<TaskPriority>& aPriority);
+
+ virtual nsresult SetTimeoutForDelayedTask(WebTask* aTask,
+ uint64_t aDelay) = 0;
+ virtual bool DispatchEventLoopRunnable() = 0;
+
+ nsClassHashtable<nsUint32HashKey, WebTaskQueue> mStaticPriorityTaskQueues;
+ nsClassHashtable<nsPtrHashKey<TaskSignal>, WebTaskQueue>
+ mDynamicPriorityTaskQueues;
+};
+
+class DelayedWebTaskHandler final : public TimeoutHandler {
+ public:
+ DelayedWebTaskHandler(JSContext* aCx, WebTaskScheduler* aScheduler,
+ WebTask* aTask)
+ : TimeoutHandler(aCx), mScheduler(aScheduler), mWebTask(aTask) {}
+
+ NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+ NS_DECL_CYCLE_COLLECTION_CLASS(DelayedWebTaskHandler)
+
+ MOZ_CAN_RUN_SCRIPT bool Call(const char* /* unused */) override {
+ if (mScheduler && mWebTask) {
+ MOZ_ASSERT(!mWebTask->HasScheduled());
+ if (!mScheduler->QueueTask(mWebTask)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private:
+ ~DelayedWebTaskHandler() override = default;
+ WeakPtr<WebTaskScheduler> mScheduler;
+ // WebTask gets added to WebTaskQueue, and WebTaskQueue keeps its alive.
+ WeakPtr<WebTask> mWebTask;
+};
+} // namespace mozilla::dom
+#endif