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