Bug 1586807 - Make pseudoclass locking work with Fission. r=pbro
[gecko.git] / xpcom / threads / PrioritizedEventQueue.h
blob60abb3bdc0ecf927de3d6468ac36342d82fa8f82
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/. */
7 #ifndef mozilla_PrioritizedEventQueue_h
8 #define mozilla_PrioritizedEventQueue_h
10 #include "mozilla/AbstractEventQueue.h"
11 #include "mozilla/EventQueue.h"
12 #include "mozilla/TimeStamp.h"
13 #include "mozilla/TypeTraits.h"
14 #include "mozilla/UniquePtr.h"
15 #include "nsCOMPtr.h"
16 #include "nsIIdlePeriod.h"
18 class nsIRunnable;
20 namespace mozilla {
21 namespace ipc {
22 class IdleSchedulerChild;
25 // This AbstractEventQueue implementation has one queue for each
26 // EventQueuePriority. The type of queue used for each priority is determined by
27 // the template parameter.
29 // When an event is pushed, its priority is determined by QIing the runnable to
30 // nsIRunnablePriority, or by falling back to the aPriority parameter if the QI
31 // fails.
33 // When an event is popped, a queue is selected based on heuristics that
34 // optimize for performance. Roughly, events are selected from the highest
35 // priority queue that is non-empty. However, there are a few exceptions:
36 // - We try to avoid processing too many high-priority events in a row so
37 // that the normal priority queue is not starved. When there are high-
38 // and normal-priority events available, we interleave popping from the
39 // normal and high queues.
40 // - We do not select events from the idle queue if the current idle period
41 // is almost over.
42 class PrioritizedEventQueue final : public AbstractEventQueue {
43 public:
44 static const bool SupportsPrioritization = true;
46 explicit PrioritizedEventQueue(already_AddRefed<nsIIdlePeriod> aIdlePeriod);
48 virtual ~PrioritizedEventQueue();
50 void PutEvent(already_AddRefed<nsIRunnable>&& aEvent,
51 EventQueuePriority aPriority,
52 const MutexAutoLock& aProofOfLock) final;
53 already_AddRefed<nsIRunnable> GetEvent(
54 EventQueuePriority* aPriority, const MutexAutoLock& aProofOfLock) final;
55 void DidRunEvent(const MutexAutoLock& aProofOfLock);
57 bool IsEmpty(const MutexAutoLock& aProofOfLock) final;
58 size_t Count(const MutexAutoLock& aProofOfLock) const final;
59 bool HasReadyEvent(const MutexAutoLock& aProofOfLock) final;
60 bool HasPendingHighPriorityEvents(const MutexAutoLock& aProofOfLock) final;
62 // When checking the idle deadline, we need to drop whatever mutex protects
63 // this queue. This method allows that mutex to be stored so that we can drop
64 // it and reacquire it when checking the idle deadline. The mutex must live at
65 // least as long as the queue.
66 void SetMutexRef(Mutex& aMutex) { mMutex = &aMutex; }
68 #ifndef RELEASE_OR_BETA
69 // nsThread.cpp sends telemetry containing the most recently computed idle
70 // deadline. We store a reference to a field in nsThread where this deadline
71 // will be stored so that it can be fetched quickly for telemetry.
72 void SetNextIdleDeadlineRef(TimeStamp& aDeadline) {
73 mNextIdleDeadline = &aDeadline;
75 #endif
77 void EnableInputEventPrioritization(const MutexAutoLock& aProofOfLock) final;
78 void FlushInputEventPrioritization(const MutexAutoLock& aProofOfLock) final;
79 void SuspendInputEventPrioritization(const MutexAutoLock& aProofOfLock) final;
80 void ResumeInputEventPrioritization(const MutexAutoLock& aProofOfLock) final;
82 size_t SizeOfExcludingThis(
83 mozilla::MallocSizeOf aMallocSizeOf) const override {
84 size_t n = 0;
86 n += mHighQueue->SizeOfIncludingThis(aMallocSizeOf);
87 n += mInputQueue->SizeOfIncludingThis(aMallocSizeOf);
88 n += mMediumHighQueue->SizeOfIncludingThis(aMallocSizeOf);
89 n += mNormalQueue->SizeOfIncludingThis(aMallocSizeOf);
90 n += mDeferredTimersQueue->SizeOfIncludingThis(aMallocSizeOf);
91 n += mIdleQueue->SizeOfIncludingThis(aMallocSizeOf);
93 if (mIdlePeriod) {
94 n += aMallocSizeOf(mIdlePeriod);
97 return n;
100 void SetIdleToken(uint64_t aId, TimeDuration aDuration);
102 bool IsActive() { return mActive; }
104 void EnsureIsActive() {
105 if (!mActive) {
106 SetActive();
110 void EnsureIsPaused() {
111 if (mActive) {
112 SetPaused();
116 private:
117 EventQueuePriority SelectQueue(bool aUpdateState,
118 const MutexAutoLock& aProofOfLock);
120 // Returns a null TimeStamp if we're not in the idle period.
121 mozilla::TimeStamp GetLocalIdleDeadline(bool& aShuttingDown);
123 // SetActive should be called when the event queue is running any type of
124 // tasks.
125 void SetActive();
126 // SetPaused should be called once the event queue doesn't have more
127 // tasks to process, or is waiting for the idle token.
128 void SetPaused();
130 // Gets the idle token, which is the end time of the idle period.
131 TimeStamp GetIdleToken(TimeStamp aLocalIdlePeriodHint);
133 // In case of child processes, requests idle time from the cross-process
134 // idle scheduler.
135 void RequestIdleToken(TimeStamp aLocalIdlePeriodHint);
137 // Returns true if the event queue either is waiting for an idle token
138 // from the idle scheduler or has one.
139 bool HasIdleRequest() { return mIdleRequestId != 0; }
141 // Mark that the event queue doesn't have idle time to use, nor is expecting
142 // to get idle token from the idle scheduler.
143 void ClearIdleToken();
145 UniquePtr<EventQueue> mHighQueue;
146 UniquePtr<EventQueue> mInputQueue;
147 UniquePtr<EventQueue> mMediumHighQueue;
148 UniquePtr<EventQueue> mNormalQueue;
149 UniquePtr<EventQueue> mDeferredTimersQueue;
150 UniquePtr<EventQueue> mIdleQueue;
152 // We need to drop the queue mutex when checking the idle deadline, so we keep
153 // a pointer to it here.
154 Mutex* mMutex = nullptr;
156 #ifndef RELEASE_OR_BETA
157 // Pointer to a place where the most recently computed idle deadline is
158 // stored.
159 TimeStamp* mNextIdleDeadline = nullptr;
160 #endif
162 // Try to process one high priority runnable after each normal
163 // priority runnable. This gives the processing model HTML spec has for
164 // 'Update the rendering' in the case only vsync messages are in the
165 // secondary queue and prevents starving the normal queue.
166 bool mProcessHighPriorityQueue = false;
168 // mIdlePeriod keeps track of the current idle period. If at any
169 // time the main event queue is empty, calling
170 // mIdlePeriod->GetIdlePeriodHint() will give an estimate of when
171 // the current idle period will end.
172 nsCOMPtr<nsIIdlePeriod> mIdlePeriod;
174 // Set to true if HasPendingEvents() has been called and returned true because
175 // of a pending idle event. This is used to remember to return that idle
176 // event from GetIdleEvent() to ensure that HasPendingEvents() never lies.
177 bool mHasPendingEventsPromisedIdleEvent = false;
179 TimeStamp mInputHandlingStartTime;
181 enum InputEventQueueState {
182 STATE_DISABLED,
183 STATE_FLUSHING,
184 STATE_SUSPEND,
185 STATE_ENABLED
187 InputEventQueueState mInputQueueState = STATE_DISABLED;
189 // If non-null, tells the end time of the idle period.
190 // Idle period starts when we get idle token from the parent process and
191 // ends when either there are no runnables in the event queues or
192 // mIdleToken < TimeStamp::Now()
193 TimeStamp mIdleToken;
195 // The id of the last idle request to the cross-process idle scheduler.
196 uint64_t mIdleRequestId = 0;
198 RefPtr<ipc::IdleSchedulerChild> mIdleScheduler;
199 bool mIdleSchedulerInitialized = false;
201 // mActive tells whether the event queue is running non-idle tasks.
202 bool mActive = true;
205 } // namespace mozilla
207 #endif // mozilla_PrioritizedEventQueue_h