/work/obj-fuzz/dist/include/mozilla/SchedulerGroup.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
3 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | #ifndef mozilla_SchedulerGroup_h |
8 | | #define mozilla_SchedulerGroup_h |
9 | | |
10 | | #include "mozilla/AbstractEventQueue.h" |
11 | | #include "mozilla/AlreadyAddRefed.h" |
12 | | #include "mozilla/LinkedList.h" |
13 | | #include "mozilla/Queue.h" |
14 | | #include "mozilla/TaskCategory.h" |
15 | | #include "mozilla/ThreadLocal.h" |
16 | | #include "mozilla/TimeStamp.h" |
17 | | #include "nsCOMPtr.h" |
18 | | #include "nsILabelableRunnable.h" |
19 | | #include "nsISupportsImpl.h" |
20 | | #include "nsThreadUtils.h" |
21 | | |
22 | | class nsIEventTarget; |
23 | | class nsIRunnable; |
24 | | class nsISerialEventTarget; |
25 | | |
26 | | namespace mozilla { |
27 | | class AbstractThread; |
28 | | namespace dom { |
29 | | class DocGroup; |
30 | | class TabGroup; |
31 | | } |
32 | | |
33 | | #define NS_SCHEDULERGROUPRUNNABLE_IID \ |
34 | | { 0xd31b7420, 0x872b, 0x4cfb, \ |
35 | | { 0xa9, 0xc6, 0xae, 0x4c, 0x0f, 0x06, 0x36, 0x74 } } |
36 | | |
37 | | // The "main thread" in Gecko will soon be a set of cooperatively scheduled |
38 | | // "fibers". Global state in Gecko will be partitioned into a series of "groups" |
39 | | // (with roughly one group per tab). Runnables will be annotated with the set of |
40 | | // groups that they touch. Two runnables may run concurrently on different |
41 | | // fibers as long as they touch different groups. |
42 | | // |
43 | | // A SchedulerGroup is an abstract class to represent a "group". Essentially the |
44 | | // only functionality offered by a SchedulerGroup is the ability to dispatch |
45 | | // runnables to the group. TabGroup, DocGroup, and SystemGroup are the concrete |
46 | | // implementations of SchedulerGroup. |
47 | | class SchedulerGroup : public LinkedListElement<SchedulerGroup> |
48 | | { |
49 | | public: |
50 | | SchedulerGroup(); |
51 | | |
52 | | NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING |
53 | | |
54 | | // This method returns true if all members of the "group" are in a |
55 | | // "background" state. |
56 | 0 | virtual bool IsBackground() const { return false; } |
57 | | |
58 | | // This function returns true if it's currently safe to run code associated |
59 | | // with this SchedulerGroup. It will return true either if we're inside an |
60 | | // unlabeled runnable or if we're inside a runnable labeled with this |
61 | | // SchedulerGroup. |
62 | | bool IsSafeToRun() const |
63 | 0 | { |
64 | 0 | return !sTlsValidatingAccess.get() || mIsRunning; |
65 | 0 | } |
66 | | |
67 | | // This function returns true if it's currently safe to run unlabeled code |
68 | | // with no known SchedulerGroup. It will only return true if we're inside an |
69 | | // unlabeled runnable. |
70 | | static bool IsSafeToRunUnlabeled() |
71 | 0 | { |
72 | 0 | return !sTlsValidatingAccess.get(); |
73 | 0 | } |
74 | | |
75 | | // Ensure that it's valid to access the TabGroup at this time. |
76 | | void ValidateAccess() const |
77 | 0 | { |
78 | 0 | MOZ_ASSERT(IsSafeToRun()); |
79 | 0 | } |
80 | | |
81 | | enum EnqueueStatus |
82 | | { |
83 | | NewlyQueued, |
84 | | AlreadyQueued, |
85 | | }; |
86 | | |
87 | | // Records that this SchedulerGroup had an event enqueued in some |
88 | | // queue. Returns whether the SchedulerGroup was already in a queue before |
89 | | // EnqueueEvent() was called. |
90 | | EnqueueStatus EnqueueEvent() |
91 | 0 | { |
92 | 0 | mEventCount++; |
93 | 0 | return mEventCount == 1 ? NewlyQueued : AlreadyQueued; |
94 | 0 | } |
95 | | |
96 | | enum DequeueStatus |
97 | | { |
98 | | StillQueued, |
99 | | NoLongerQueued, |
100 | | }; |
101 | | |
102 | | // Records that this SchedulerGroup had an event dequeued from some |
103 | | // queue. Returns whether the SchedulerGroup is still in a queue after |
104 | | // DequeueEvent() returns. |
105 | | DequeueStatus DequeueEvent() |
106 | 0 | { |
107 | 0 | mEventCount--; |
108 | 0 | return mEventCount == 0 ? NoLongerQueued : StillQueued; |
109 | 0 | } |
110 | | |
111 | | class Runnable final : public mozilla::Runnable |
112 | | , public nsIRunnablePriority |
113 | | , public nsILabelableRunnable |
114 | | { |
115 | | public: |
116 | | Runnable(already_AddRefed<nsIRunnable>&& aRunnable, |
117 | | SchedulerGroup* aGroup, |
118 | | dom::DocGroup* aDocGroup); |
119 | | |
120 | | bool GetAffectedSchedulerGroups(SchedulerGroupSet& aGroups) override; |
121 | | |
122 | 0 | SchedulerGroup* Group() const { return mGroup; } |
123 | | dom::DocGroup* DocGroup() const; |
124 | | |
125 | | #ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY |
126 | | NS_IMETHOD GetName(nsACString& aName) override; |
127 | | #endif |
128 | | |
129 | 0 | bool IsBackground() const { return mGroup->IsBackground(); } |
130 | | |
131 | | NS_DECL_ISUPPORTS_INHERITED |
132 | | NS_DECL_NSIRUNNABLE |
133 | | NS_DECL_NSIRUNNABLEPRIORITY |
134 | | |
135 | | NS_DECLARE_STATIC_IID_ACCESSOR(NS_SCHEDULERGROUPRUNNABLE_IID); |
136 | | |
137 | | private: |
138 | | friend class SchedulerGroup; |
139 | | |
140 | 0 | ~Runnable() = default; |
141 | | |
142 | | nsCOMPtr<nsIRunnable> mRunnable; |
143 | | RefPtr<SchedulerGroup> mGroup; |
144 | | RefPtr<dom::DocGroup> mDocGroup; |
145 | | }; |
146 | | friend class Runnable; |
147 | | |
148 | 0 | bool* GetValidAccessPtr() { return &mIsRunning; } |
149 | | |
150 | | virtual nsresult Dispatch(TaskCategory aCategory, |
151 | | already_AddRefed<nsIRunnable>&& aRunnable); |
152 | | |
153 | | virtual nsISerialEventTarget* EventTargetFor(TaskCategory aCategory) const; |
154 | | |
155 | | // Must always be called on the main thread. The returned AbstractThread can |
156 | | // always be used off the main thread. |
157 | | AbstractThread* AbstractMainThreadFor(TaskCategory aCategory); |
158 | | |
159 | | // This method performs a safe cast. It returns null if |this| is not of the |
160 | | // requested type. |
161 | 0 | virtual dom::TabGroup* AsTabGroup() { return nullptr; } |
162 | | |
163 | | static nsresult UnlabeledDispatch(TaskCategory aCategory, |
164 | | already_AddRefed<nsIRunnable>&& aRunnable); |
165 | | |
166 | | static void MarkVsyncReceived(); |
167 | | |
168 | | static void MarkVsyncRan(); |
169 | | |
170 | 0 | void SetIsRunning(bool aIsRunning) { mIsRunning = aIsRunning; } |
171 | 0 | bool IsRunning() const { return mIsRunning; } |
172 | | |
173 | | enum ValidationType { |
174 | | StartValidation, |
175 | | EndValidation, |
176 | | }; |
177 | | static void SetValidatingAccess(ValidationType aType); |
178 | | |
179 | | struct EpochQueueEntry |
180 | | { |
181 | | nsCOMPtr<nsIRunnable> mRunnable; |
182 | | uintptr_t mEpochNumber; |
183 | | |
184 | | EpochQueueEntry(already_AddRefed<nsIRunnable> aRunnable, uintptr_t aEpoch) |
185 | | : mRunnable(aRunnable) |
186 | | , mEpochNumber(aEpoch) |
187 | 0 | { |
188 | 0 | } |
189 | | }; |
190 | | |
191 | | using RunnableEpochQueue = Queue<EpochQueueEntry, 32>; |
192 | | |
193 | | RunnableEpochQueue& GetQueue(mozilla::EventPriority aPriority) |
194 | 0 | { |
195 | 0 | return mEventQueues[size_t(aPriority)]; |
196 | 0 | } |
197 | | |
198 | | protected: |
199 | | nsresult DispatchWithDocGroup(TaskCategory aCategory, |
200 | | already_AddRefed<nsIRunnable>&& aRunnable, |
201 | | dom::DocGroup* aDocGroup); |
202 | | |
203 | | static nsresult InternalUnlabeledDispatch(TaskCategory aCategory, |
204 | | already_AddRefed<Runnable>&& aRunnable); |
205 | | |
206 | | // Implementations are guaranteed that this method is called on the main |
207 | | // thread. |
208 | | virtual AbstractThread* AbstractMainThreadForImpl(TaskCategory aCategory); |
209 | | |
210 | | // Helper method to create an event target specific to a particular TaskCategory. |
211 | | virtual already_AddRefed<nsISerialEventTarget> |
212 | | CreateEventTargetFor(TaskCategory aCategory); |
213 | | |
214 | | // Given an event target returned by |dispatcher->CreateEventTargetFor|, this |
215 | | // function returns |dispatcher|. |
216 | | static SchedulerGroup* FromEventTarget(nsIEventTarget* aEventTarget); |
217 | | |
218 | | nsresult LabeledDispatch(TaskCategory aCategory, |
219 | | already_AddRefed<nsIRunnable>&& aRunnable, |
220 | | dom::DocGroup* aDocGroup); |
221 | | |
222 | | void CreateEventTargets(bool aNeedValidation); |
223 | | |
224 | | // Shuts down this dispatcher. If aXPCOMShutdown is true, invalidates this |
225 | | // dispatcher. |
226 | | void Shutdown(bool aXPCOMShutdown); |
227 | | |
228 | | static MOZ_THREAD_LOCAL(bool) sTlsValidatingAccess; |
229 | | |
230 | | bool mIsRunning; |
231 | | |
232 | | // Number of events that are currently enqueued for this SchedulerGroup |
233 | | // (across all queues). |
234 | | size_t mEventCount = 0; |
235 | | |
236 | | nsCOMPtr<nsISerialEventTarget> mEventTargets[size_t(TaskCategory::Count)]; |
237 | | RefPtr<AbstractThread> mAbstractThreads[size_t(TaskCategory::Count)]; |
238 | | RunnableEpochQueue mEventQueues[size_t(mozilla::EventPriority::Count)]; |
239 | | }; |
240 | | |
241 | | NS_DEFINE_STATIC_IID_ACCESSOR(SchedulerGroup::Runnable, NS_SCHEDULERGROUPRUNNABLE_IID); |
242 | | |
243 | | } // namespace mozilla |
244 | | |
245 | | #endif // mozilla_SchedulerGroup_h |