Line data Source code
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/AlreadyAddRefed.h"
11 : #include "mozilla/TaskCategory.h"
12 : #include "mozilla/TimeStamp.h"
13 : #include "nsCOMPtr.h"
14 : #include "nsISupportsImpl.h"
15 : #include "nsThreadUtils.h"
16 :
17 : class nsIEventTarget;
18 : class nsIRunnable;
19 : class nsISerialEventTarget;
20 :
21 : namespace mozilla {
22 : class AbstractThread;
23 : namespace dom {
24 : class TabGroup;
25 : }
26 :
27 : #define NS_SCHEDULERGROUPRUNNABLE_IID \
28 : { 0xd31b7420, 0x872b, 0x4cfb, \
29 : { 0xa9, 0xc6, 0xae, 0x4c, 0x0f, 0x06, 0x36, 0x74 } }
30 :
31 : // The "main thread" in Gecko will soon be a set of cooperatively scheduled
32 : // "fibers". Global state in Gecko will be partitioned into a series of "groups"
33 : // (with roughly one group per tab). Runnables will be annotated with the set of
34 : // groups that they touch. Two runnables may run concurrently on different
35 : // fibers as long as they touch different groups.
36 : //
37 : // A SchedulerGroup is an abstract class to represent a "group". Essentially the
38 : // only functionality offered by a SchedulerGroup is the ability to dispatch
39 : // runnables to the group. TabGroup, DocGroup, and SystemGroup are the concrete
40 : // implementations of SchedulerGroup.
41 0 : class SchedulerGroup
42 : {
43 : public:
44 : SchedulerGroup();
45 :
46 : NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
47 :
48 : // This method returns true if all members of the "group" are in a
49 : // "background" state.
50 12 : virtual bool IsBackground() const { return false; }
51 :
52 : class MOZ_STACK_CLASS AutoProcessEvent final {
53 : public:
54 : AutoProcessEvent();
55 : ~AutoProcessEvent();
56 :
57 : private:
58 : SchedulerGroup* mPrevRunningDispatcher;
59 : };
60 :
61 : // This function returns true if it's currently safe to run code associated
62 : // with this SchedulerGroup. It will return true either if we're inside an
63 : // unlabeled runnable or if we're inside a runnable labeled with this
64 : // SchedulerGroup.
65 622 : bool IsSafeToRun() const
66 : {
67 622 : return !sRunningDispatcher || mAccessValid;
68 : }
69 :
70 : // Ensure that it's valid to access the TabGroup at this time.
71 622 : void ValidateAccess() const
72 : {
73 622 : MOZ_ASSERT(IsSafeToRun());
74 622 : }
75 :
76 : class Runnable final : public mozilla::Runnable
77 : {
78 : public:
79 : Runnable(already_AddRefed<nsIRunnable>&& aRunnable,
80 : SchedulerGroup* aGroup);
81 :
82 : SchedulerGroup* Group() const { return mGroup; }
83 :
84 : NS_IMETHOD GetName(nsACString& aName) override;
85 :
86 129 : bool IsBackground() const { return mGroup->IsBackground(); }
87 :
88 : NS_DECL_ISUPPORTS_INHERITED
89 : NS_DECL_NSIRUNNABLE
90 :
91 : NS_DECLARE_STATIC_IID_ACCESSOR(NS_SCHEDULERGROUPRUNNABLE_IID);
92 :
93 : private:
94 387 : ~Runnable() = default;
95 :
96 : nsCOMPtr<nsIRunnable> mRunnable;
97 : RefPtr<SchedulerGroup> mGroup;
98 : };
99 : friend class Runnable;
100 :
101 4 : bool* GetValidAccessPtr() { return &mAccessValid; }
102 :
103 : virtual nsresult Dispatch(const char* aName,
104 : TaskCategory aCategory,
105 : already_AddRefed<nsIRunnable>&& aRunnable);
106 :
107 : virtual nsISerialEventTarget* EventTargetFor(TaskCategory aCategory) const;
108 :
109 : // Must always be called on the main thread. The returned AbstractThread can
110 : // always be used off the main thread.
111 : AbstractThread* AbstractMainThreadFor(TaskCategory aCategory);
112 :
113 : // This method performs a safe cast. It returns null if |this| is not of the
114 : // requested type.
115 0 : virtual dom::TabGroup* AsTabGroup() { return nullptr; }
116 :
117 : static nsresult UnlabeledDispatch(const char* aName,
118 : TaskCategory aCategory,
119 : already_AddRefed<nsIRunnable>&& aRunnable);
120 :
121 : static void MarkVsyncReceived();
122 :
123 : static void MarkVsyncRan();
124 :
125 : protected:
126 : // Implementations are guaranteed that this method is called on the main
127 : // thread.
128 : virtual AbstractThread* AbstractMainThreadForImpl(TaskCategory aCategory);
129 :
130 : // Helper method to create an event target specific to a particular TaskCategory.
131 : virtual already_AddRefed<nsISerialEventTarget>
132 : CreateEventTargetFor(TaskCategory aCategory);
133 :
134 : // Given an event target returned by |dispatcher->CreateEventTargetFor|, this
135 : // function returns |dispatcher|.
136 : static SchedulerGroup* FromEventTarget(nsIEventTarget* aEventTarget);
137 :
138 : nsresult LabeledDispatch(const char* aName,
139 : TaskCategory aCategory,
140 : already_AddRefed<nsIRunnable>&& aRunnable);
141 :
142 : void CreateEventTargets(bool aNeedValidation);
143 :
144 : // Shuts down this dispatcher. If aXPCOMShutdown is true, invalidates this
145 : // dispatcher.
146 : void Shutdown(bool aXPCOMShutdown);
147 :
148 : enum ValidationType {
149 : StartValidation,
150 : EndValidation,
151 : };
152 : void SetValidatingAccess(ValidationType aType);
153 :
154 : static SchedulerGroup* sRunningDispatcher;
155 : bool mAccessValid;
156 :
157 : nsCOMPtr<nsISerialEventTarget> mEventTargets[size_t(TaskCategory::Count)];
158 : RefPtr<AbstractThread> mAbstractThreads[size_t(TaskCategory::Count)];
159 : };
160 :
161 : NS_DEFINE_STATIC_IID_ACCESSOR(SchedulerGroup::Runnable, NS_SCHEDULERGROUPRUNNABLE_IID);
162 :
163 : } // namespace mozilla
164 :
165 : #endif // mozilla_SchedulerGroup_h
|