1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:expandtab:shiftwidth=2:tabstop=2:
4 /* This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #ifndef mozilla_dom_WebTaskScheduler_h
9 #define mozilla_dom_WebTaskScheduler_h
11 #include "nsThreadUtils.h"
12 #include "nsPIDOMWindow.h"
13 #include "nsWrapperCache.h"
14 #include "nsClassHashtable.h"
16 #include "mozilla/Variant.h"
17 #include "mozilla/dom/Promise.h"
18 #include "mozilla/dom/AbortFollower.h"
19 #include "mozilla/dom/TimeoutHandler.h"
20 #include "mozilla/dom/WebTaskSchedulingBinding.h"
22 namespace mozilla::dom
{
24 class WebTask
: public LinkedListElement
<RefPtr
<WebTask
>>,
26 public SupportsWeakPtr
{
27 friend class WebTaskScheduler
;
30 MOZ_CAN_RUN_SCRIPT
bool Run();
32 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
34 NS_DECL_CYCLE_COLLECTION_CLASS(WebTask
)
35 WebTask(uint32_t aEnqueueOrder
, SchedulerPostTaskCallback
& aCallback
,
37 : mEnqueueOrder(aEnqueueOrder
),
38 mCallback(&aCallback
),
41 mOwnerQueue(nullptr) {}
43 void RunAbortAlgorithm() override
;
45 bool HasScheduled() const { return mHasScheduled
; }
47 uint32_t EnqueueOrder() const { return mEnqueueOrder
; }
49 void SetWebTaskQueue(WebTaskQueue
* aWebTaskQueue
) {
50 mOwnerQueue
= aWebTaskQueue
;
54 void SetHasScheduled(bool aHasScheduled
) { mHasScheduled
= aHasScheduled
; }
56 uint32_t mEnqueueOrder
;
58 RefPtr
<SchedulerPostTaskCallback
> mCallback
;
59 RefPtr
<Promise
> mPromise
;
63 // WebTaskQueue owns WebTask, so it's okay to use a raw pointer
64 WebTaskQueue
* mOwnerQueue
;
71 WebTaskQueue(uint32_t aKey
, WebTaskScheduler
* aScheduler
)
72 : mOwnerKey(AsVariant(aKey
)), mScheduler(aScheduler
) {}
73 WebTaskQueue(TaskSignal
* aKey
, WebTaskScheduler
* aScheduler
)
74 : mOwnerKey(AsVariant(aKey
)), mScheduler(aScheduler
) {}
76 TaskPriority
Priority() const { return mPriority
; }
77 void SetPriority(TaskPriority aNewPriority
) { mPriority
= aNewPriority
; }
79 LinkedList
<RefPtr
<WebTask
>>& Tasks() { return mTasks
; }
81 void AddTask(WebTask
* aTask
) {
82 mTasks
.insertBack(aTask
);
83 aTask
->SetWebTaskQueue(this);
86 void RemoveEntryFromTaskQueueMapIfNeeded();
87 // TODO: To optimize it, we could have the scheduled and unscheduled
88 // tasks stored separately.
89 WebTask
* GetFirstScheduledTask() {
90 for (const auto& task
: mTasks
) {
91 if (task
->HasScheduled()) {
99 mOwnerKey
= AsVariant(Nothing());
100 for (const auto& task
: mTasks
) {
101 task
->SetWebTaskQueue(nullptr);
107 TaskPriority mPriority
= TaskPriority::User_visible
;
108 LinkedList
<RefPtr
<WebTask
>> mTasks
;
110 // When mOwnerKey is TaskSignal*, it means as long as
111 // WebTaskQueue is alive, the corresponding TaskSignal
112 // is alive, so using a raw pointer is ok.
113 Variant
<Nothing
, uint32_t, TaskSignal
*> mOwnerKey
;
115 // WebTaskScheduler owns WebTaskQueue as a hashtable value, so using a raw
116 // pointer points to WebTaskScheduler is ok.
117 WebTaskScheduler
* mScheduler
;
120 class WebTaskSchedulerMainThread
;
121 class WebTaskSchedulerWorker
;
123 class WebTaskScheduler
: public nsWrapperCache
, public SupportsWeakPtr
{
124 friend class DelayedWebTaskHandler
;
127 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebTaskScheduler
)
128 NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebTaskScheduler
)
130 static already_AddRefed
<WebTaskSchedulerMainThread
> CreateForMainThread(
131 nsGlobalWindowInner
* aWindow
);
133 static already_AddRefed
<WebTaskSchedulerWorker
> CreateForWorker(
134 WorkerPrivate
* aWorkerPrivate
);
136 explicit WebTaskScheduler(nsIGlobalObject
* aParent
);
138 already_AddRefed
<Promise
> PostTask(SchedulerPostTaskCallback
& aCallback
,
139 const SchedulerPostTaskOptions
& aOptions
);
141 nsIGlobalObject
* GetParentObject() const { return mParent
; }
143 virtual JSObject
* WrapObject(JSContext
* cx
,
144 JS::Handle
<JSObject
*> aGivenProto
) override
;
146 WebTask
* GetNextTask() const;
148 virtual void Disconnect();
150 void RunTaskSignalPriorityChange(TaskSignal
* aTaskSignal
);
152 void DeleteEntryFromStaticQueueMap(uint32_t aKey
);
153 void DeleteEntryFromDynamicQueueMap(TaskSignal
* aKey
);
156 virtual ~WebTaskScheduler() = default;
157 nsCOMPtr
<nsIGlobalObject
> mParent
;
159 uint32_t mNextEnqueueOrder
;
162 already_AddRefed
<WebTask
> CreateTask(
163 WebTaskQueue
& aQueue
, const Optional
<OwningNonNull
<AbortSignal
>>& aSignal
,
164 SchedulerPostTaskCallback
& aCallback
, Promise
* aPromise
);
166 bool QueueTask(WebTask
* aTask
);
168 WebTaskQueue
& SelectTaskQueue(
169 const Optional
<OwningNonNull
<AbortSignal
>>& aSignal
,
170 const Optional
<TaskPriority
>& aPriority
);
172 virtual nsresult
SetTimeoutForDelayedTask(WebTask
* aTask
,
173 uint64_t aDelay
) = 0;
174 virtual bool DispatchEventLoopRunnable() = 0;
176 nsClassHashtable
<nsUint32HashKey
, WebTaskQueue
> mStaticPriorityTaskQueues
;
177 nsClassHashtable
<nsRefPtrHashKey
<TaskSignal
>, WebTaskQueue
>
178 mDynamicPriorityTaskQueues
;
181 class DelayedWebTaskHandler final
: public TimeoutHandler
{
183 DelayedWebTaskHandler(JSContext
* aCx
, WebTaskScheduler
* aScheduler
,
185 : TimeoutHandler(aCx
), mScheduler(aScheduler
), mWebTask(aTask
) {}
187 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
188 NS_DECL_CYCLE_COLLECTION_CLASS(DelayedWebTaskHandler
)
190 MOZ_CAN_RUN_SCRIPT
bool Call(const char* /* unused */) override
{
191 if (mScheduler
&& mWebTask
) {
192 MOZ_ASSERT(!mWebTask
->HasScheduled());
193 if (!mScheduler
->QueueTask(mWebTask
)) {
201 ~DelayedWebTaskHandler() override
= default;
202 WeakPtr
<WebTaskScheduler
> mScheduler
;
203 // WebTask gets added to WebTaskQueue, and WebTaskQueue keeps its alive.
204 WeakPtr
<WebTask
> mWebTask
;
206 } // namespace mozilla::dom