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_EventQueue_h
8 #define mozilla_EventQueue_h
9 
10 #include "mozilla/Mutex.h"
11 #include "mozilla/Queue.h"
12 #include "mozilla/TimeStamp.h"
13 #include "nsCOMPtr.h"
14 
15 class nsIRunnable;
16 
17 namespace mozilla {
18 
19 enum class EventQueuePriority {
20   Idle,
21   DeferredTimers,
22   InputLow,
23   Normal,
24   MediumHigh,
25   InputHigh,
26   Vsync,
27   InputHighest,
28   Control,
29 
30   Count
31 };
32 
33 class IdlePeriodState;
34 
35 namespace detail {
36 
37 // EventQueue is our unsynchronized event queue implementation. It is a queue
38 // of runnables used for non-main thread, as well as optionally providing
39 // forwarding to TaskController.
40 //
41 // Since EventQueue is unsynchronized, it should be wrapped in an outer
42 // SynchronizedEventQueue implementation (like ThreadEventQueue).
43 template <size_t ItemsPerPage>
44 class EventQueueInternal {
45  public:
EventQueueInternal(bool aForwardToTC)46   explicit EventQueueInternal(bool aForwardToTC) : mForwardToTC(aForwardToTC) {}
47 
48   // Add an event to the end of the queue. Implementors are free to use
49   // aPriority however they wish.  If the runnable supports
50   // nsIRunnablePriority and the implementing class supports
51   // prioritization, aPriority represents the result of calling
52   // nsIRunnablePriority::GetPriority().  *aDelay is time the event has
53   // already been delayed (used when moving an event from one queue to
54   // another)
55   void PutEvent(already_AddRefed<nsIRunnable>&& aEvent,
56                 EventQueuePriority aPriority, const MutexAutoLock& aProofOfLock,
57                 mozilla::TimeDuration* aDelay = nullptr);
58 
59   // Get an event from the front of the queue. This should return null if the
60   // queue is non-empty but the event in front is not ready to run.
61   // *aLastEventDelay is the time the event spent in queues before being
62   // retrieved.
63   already_AddRefed<nsIRunnable> GetEvent(
64       const MutexAutoLock& aProofOfLock,
65       mozilla::TimeDuration* aLastEventDelay = nullptr);
66 
67   // Returns true if the queue is empty. Implies !HasReadyEvent().
68   bool IsEmpty(const MutexAutoLock& aProofOfLock);
69 
70   // Returns true if the queue is non-empty and if the event in front is ready
71   // to run. Implies !IsEmpty(). This should return true iff GetEvent returns a
72   // non-null value.
73   bool HasReadyEvent(const MutexAutoLock& aProofOfLock);
74 
75   // Returns the number of events in the queue.
76   size_t Count(const MutexAutoLock& aProofOfLock) const;
77   // For some reason, if we put this in the .cpp file the linker can't find it
PeekEvent(const MutexAutoLock & aProofOfLock)78   already_AddRefed<nsIRunnable> PeekEvent(const MutexAutoLock& aProofOfLock) {
79     if (mQueue.IsEmpty()) {
80       return nullptr;
81     }
82 
83     nsCOMPtr<nsIRunnable> result = mQueue.FirstElement();
84     return result.forget();
85   }
86 
EnableInputEventPrioritization(const MutexAutoLock & aProofOfLock)87   void EnableInputEventPrioritization(const MutexAutoLock& aProofOfLock) {}
FlushInputEventPrioritization(const MutexAutoLock & aProofOfLock)88   void FlushInputEventPrioritization(const MutexAutoLock& aProofOfLock) {}
SuspendInputEventPrioritization(const MutexAutoLock & aProofOfLock)89   void SuspendInputEventPrioritization(const MutexAutoLock& aProofOfLock) {}
ResumeInputEventPrioritization(const MutexAutoLock & aProofOfLock)90   void ResumeInputEventPrioritization(const MutexAutoLock& aProofOfLock) {}
91 
SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)92   size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const {
93     return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
94   }
95 
SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf)96   size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const {
97     size_t size = mQueue.ShallowSizeOfExcludingThis(aMallocSizeOf);
98     size += mDispatchTimes.ShallowSizeOfExcludingThis(aMallocSizeOf);
99     return size;
100   }
101 
102  private:
103   mozilla::Queue<nsCOMPtr<nsIRunnable>, ItemsPerPage> mQueue;
104   // This queue is only populated when the profiler is turned on.
105   mozilla::Queue<mozilla::TimeStamp, ItemsPerPage> mDispatchTimes;
106   TimeDuration mLastEventDelay;
107   // This indicates PutEvent forwards runnables to the TaskController. This
108   // should be true for the top level event queue on the main thread.
109   bool mForwardToTC;
110 };
111 
112 }  // namespace detail
113 
114 class EventQueue final : public mozilla::detail::EventQueueInternal<16> {
115  public:
116   explicit EventQueue(bool aForwardToTC = false)
117       : mozilla::detail::EventQueueInternal<16>(aForwardToTC) {}
118 };
119 
120 template <size_t ItemsPerPage = 16>
121 class EventQueueSized final
122     : public mozilla::detail::EventQueueInternal<ItemsPerPage> {
123  public:
124   explicit EventQueueSized(bool aForwardToTC = false)
125       : mozilla::detail::EventQueueInternal<ItemsPerPage>(aForwardToTC) {}
126 };
127 
128 }  // namespace mozilla
129 
130 #endif  // mozilla_EventQueue_h
131