Coverage Report

Created: 2018-09-25 14:53

/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