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"
16 #include "nsIIdlePeriod.h"
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
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
42 class PrioritizedEventQueue final
: public AbstractEventQueue
{
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
;
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
{
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
);
94 n
+= aMallocSizeOf(mIdlePeriod
);
100 void SetIdleToken(uint64_t aId
, TimeDuration aDuration
);
102 bool IsActive() { return mActive
; }
104 void EnsureIsActive() {
110 void EnsureIsPaused() {
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
126 // SetPaused should be called once the event queue doesn't have more
127 // tasks to process, or is waiting for the idle token.
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
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
159 TimeStamp
* mNextIdleDeadline
= nullptr;
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
{
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.
205 } // namespace mozilla
207 #endif // mozilla_PrioritizedEventQueue_h