/src/mozilla-central/xpcom/threads/PrioritizedEventQueue.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_PrioritizedEventQueue_h |
8 | | #define mozilla_PrioritizedEventQueue_h |
9 | | |
10 | | #include "mozilla/AbstractEventQueue.h" |
11 | | #include "LabeledEventQueue.h" |
12 | | #include "mozilla/TimeStamp.h" |
13 | | #include "mozilla/TypeTraits.h" |
14 | | #include "mozilla/UniquePtr.h" |
15 | | #include "nsCOMPtr.h" |
16 | | #include "nsIIdlePeriod.h" |
17 | | |
18 | | class nsIRunnable; |
19 | | |
20 | | namespace mozilla { |
21 | | |
22 | | // This AbstractEventQueue implementation has one queue for each EventPriority. |
23 | | // The type of queue used for each priority is determined by the template |
24 | | // parameter. |
25 | | // |
26 | | // When an event is pushed, its priority is determined by QIing the runnable to |
27 | | // nsIRunnablePriority, or by falling back to the aPriority parameter if the QI |
28 | | // fails. |
29 | | // |
30 | | // When an event is popped, a queue is selected based on heuristics that |
31 | | // optimize for performance. Roughly, events are selected from the highest |
32 | | // priority queue that is non-empty. However, there are a few exceptions: |
33 | | // - We try to avoid processing too many high-priority events in a row so |
34 | | // that the normal priority queue is not starved. When there are high- |
35 | | // and normal-priority events available, we interleave popping from the |
36 | | // normal and high queues. |
37 | | // - We do not select events from the idle queue if the current idle period |
38 | | // is almost over. |
39 | | template<class InnerQueueT> |
40 | | class PrioritizedEventQueue final : public AbstractEventQueue |
41 | | { |
42 | | public: |
43 | | static const bool SupportsPrioritization = true; |
44 | | |
45 | | PrioritizedEventQueue(UniquePtr<InnerQueueT> aHighQueue, |
46 | | UniquePtr<InnerQueueT> aInputQueue, |
47 | | UniquePtr<InnerQueueT> aNormalQueue, |
48 | | UniquePtr<InnerQueueT> aIdleQueue, |
49 | | already_AddRefed<nsIIdlePeriod> aIdlePeriod); |
50 | | |
51 | | void PutEvent(already_AddRefed<nsIRunnable>&& aEvent, |
52 | | EventPriority aPriority, |
53 | | const MutexAutoLock& aProofOfLock) final; |
54 | | already_AddRefed<nsIRunnable> GetEvent(EventPriority* aPriority, |
55 | | const MutexAutoLock& aProofOfLock) final; |
56 | | |
57 | | bool IsEmpty(const MutexAutoLock& aProofOfLock) final; |
58 | | size_t Count(const MutexAutoLock& aProofOfLock) const final; |
59 | | bool HasReadyEvent(const MutexAutoLock& aProofOfLock) final; |
60 | | |
61 | | // When checking the idle deadline, we need to drop whatever mutex protects |
62 | | // this queue. This method allows that mutex to be stored so that we can drop |
63 | | // it and reacquire it when checking the idle deadline. The mutex must live at |
64 | | // least as long as the queue. |
65 | 3 | void SetMutexRef(Mutex& aMutex) { mMutex = &aMutex; } mozilla::PrioritizedEventQueue<mozilla::EventQueue>::SetMutexRef(mozilla::Mutex&) Line | Count | Source | 65 | 3 | void SetMutexRef(Mutex& aMutex) { mMutex = &aMutex; } |
Unexecuted instantiation: mozilla::PrioritizedEventQueue<mozilla::LabeledEventQueue>::SetMutexRef(mozilla::Mutex&) |
66 | | |
67 | | #ifndef RELEASE_OR_BETA |
68 | | // nsThread.cpp sends telemetry containing the most recently computed idle |
69 | | // deadline. We store a reference to a field in nsThread where this deadline |
70 | | // will be stored so that it can be fetched quickly for telemetry. |
71 | 3 | void SetNextIdleDeadlineRef(TimeStamp& aDeadline) { mNextIdleDeadline = &aDeadline; } mozilla::PrioritizedEventQueue<mozilla::EventQueue>::SetNextIdleDeadlineRef(mozilla::TimeStamp&) Line | Count | Source | 71 | 3 | void SetNextIdleDeadlineRef(TimeStamp& aDeadline) { mNextIdleDeadline = &aDeadline; } |
Unexecuted instantiation: mozilla::PrioritizedEventQueue<mozilla::LabeledEventQueue>::SetNextIdleDeadlineRef(mozilla::TimeStamp&) |
72 | | #endif |
73 | | |
74 | | void EnableInputEventPrioritization(const MutexAutoLock& aProofOfLock) final; |
75 | | void FlushInputEventPrioritization(const MutexAutoLock& aProofOfLock) final; |
76 | | void SuspendInputEventPrioritization(const MutexAutoLock& aProofOfLock) final; |
77 | | void ResumeInputEventPrioritization(const MutexAutoLock& aProofOfLock) final; |
78 | | |
79 | | size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override |
80 | 0 | { |
81 | 0 | size_t n = 0; |
82 | 0 |
|
83 | 0 | n += mHighQueue->SizeOfIncludingThis(aMallocSizeOf); |
84 | 0 | n += mInputQueue->SizeOfIncludingThis(aMallocSizeOf); |
85 | 0 | n += mNormalQueue->SizeOfIncludingThis(aMallocSizeOf); |
86 | 0 | n += mIdleQueue->SizeOfIncludingThis(aMallocSizeOf); |
87 | 0 |
|
88 | 0 | if (mIdlePeriod) { |
89 | 0 | n += aMallocSizeOf(mIdlePeriod); |
90 | 0 | } |
91 | 0 |
|
92 | 0 | return n; |
93 | 0 | } Unexecuted instantiation: mozilla::PrioritizedEventQueue<mozilla::EventQueue>::SizeOfExcludingThis(unsigned long (*)(void const*)) const Unexecuted instantiation: mozilla::PrioritizedEventQueue<mozilla::LabeledEventQueue>::SizeOfExcludingThis(unsigned long (*)(void const*)) const |
94 | | |
95 | | private: |
96 | | EventPriority SelectQueue(bool aUpdateState, const MutexAutoLock& aProofOfLock); |
97 | | |
98 | | // Returns a null TimeStamp if we're not in the idle period. |
99 | | mozilla::TimeStamp GetIdleDeadline(); |
100 | | |
101 | | UniquePtr<InnerQueueT> mHighQueue; |
102 | | UniquePtr<InnerQueueT> mInputQueue; |
103 | | UniquePtr<InnerQueueT> mNormalQueue; |
104 | | UniquePtr<InnerQueueT> mIdleQueue; |
105 | | |
106 | | // We need to drop the queue mutex when checking the idle deadline, so we keep |
107 | | // a pointer to it here. |
108 | | Mutex* mMutex = nullptr; |
109 | | |
110 | | #ifndef RELEASE_OR_BETA |
111 | | // Pointer to a place where the most recently computed idle deadline is |
112 | | // stored. |
113 | | TimeStamp* mNextIdleDeadline = nullptr; |
114 | | #endif |
115 | | |
116 | | // Try to process one high priority runnable after each normal |
117 | | // priority runnable. This gives the processing model HTML spec has for |
118 | | // 'Update the rendering' in the case only vsync messages are in the |
119 | | // secondary queue and prevents starving the normal queue. |
120 | | bool mProcessHighPriorityQueue = false; |
121 | | |
122 | | // mIdlePeriod keeps track of the current idle period. If at any |
123 | | // time the main event queue is empty, calling |
124 | | // mIdlePeriod->GetIdlePeriodHint() will give an estimate of when |
125 | | // the current idle period will end. |
126 | | nsCOMPtr<nsIIdlePeriod> mIdlePeriod; |
127 | | |
128 | | // Set to true if HasPendingEvents() has been called and returned true because |
129 | | // of a pending idle event. This is used to remember to return that idle |
130 | | // event from GetIdleEvent() to ensure that HasPendingEvents() never lies. |
131 | | bool mHasPendingEventsPromisedIdleEvent = false; |
132 | | |
133 | | TimeStamp mInputHandlingStartTime; |
134 | | |
135 | | enum InputEventQueueState |
136 | | { |
137 | | STATE_DISABLED, |
138 | | STATE_FLUSHING, |
139 | | STATE_SUSPEND, |
140 | | STATE_ENABLED |
141 | | }; |
142 | | InputEventQueueState mInputQueueState = STATE_DISABLED; |
143 | | }; |
144 | | |
145 | | class EventQueue; |
146 | | extern template class PrioritizedEventQueue<EventQueue>; |
147 | | extern template class PrioritizedEventQueue<LabeledEventQueue>; |
148 | | |
149 | | } // namespace mozilla |
150 | | |
151 | | #endif // mozilla_PrioritizedEventQueue_h |