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_ThreadEventQueue_h
8 #define mozilla_ThreadEventQueue_h
9 
10 #include "mozilla/AbstractEventQueue.h"
11 #include "mozilla/CondVar.h"
12 #include "mozilla/SynchronizedEventQueue.h"
13 #include "nsCOMPtr.h"
14 #include "nsTArray.h"
15 
16 class nsIEventTarget;
17 class nsISerialEventTarget;
18 class nsIThreadObserver;
19 
20 namespace mozilla {
21 
22 class EventQueue;
23 
24 template <typename InnerQueueT>
25 class PrioritizedEventQueue;
26 
27 class LabeledEventQueue;
28 
29 class ThreadEventTarget;
30 
31 // A ThreadEventQueue implements normal monitor-style synchronization over the
32 // InnerQueueT AbstractEventQueue. It also implements PushEventQueue and
33 // PopEventQueue for workers (see the documentation below for an explanation of
34 // those). All threads use a ThreadEventQueue as their event queue. InnerQueueT
35 // is a template parameter to avoid virtual dispatch overhead.
36 template <class InnerQueueT>
37 class ThreadEventQueue final : public SynchronizedEventQueue {
38  public:
39   explicit ThreadEventQueue(UniquePtr<InnerQueueT> aQueue);
40 
41   bool PutEvent(already_AddRefed<nsIRunnable>&& aEvent,
42                 EventPriority aPriority) final;
43 
44   already_AddRefed<nsIRunnable> GetEvent(bool aMayWait,
45                                          EventPriority* aPriority) final;
46   bool HasPendingEvent() final;
47 
48   bool ShutdownIfNoPendingEvents() final;
49 
Disconnect(const MutexAutoLock & aProofOfLock)50   void Disconnect(const MutexAutoLock& aProofOfLock) final {}
51 
52   void EnableInputEventPrioritization() final;
53   void FlushInputEventPrioritization() final;
54   void SuspendInputEventPrioritization() final;
55   void ResumeInputEventPrioritization() final;
56 
57   /**
58    * This method causes any events currently enqueued on the thread to be
59    * suppressed until PopEventQueue is called, and any event dispatched to this
60    * thread's nsIEventTarget will queue as well. Calls to PushEventQueue may be
61    * nested and must each be paired with a call to PopEventQueue in order to
62    * restore the original state of the thread. The returned nsIEventTarget may
63    * be used to push events onto the nested queue. Dispatching will be disabled
64    * once the event queue is popped. The thread will only ever process pending
65    * events for the innermost event queue. Must only be called on the target
66    * thread.
67    */
68   already_AddRefed<nsISerialEventTarget> PushEventQueue();
69 
70   /**
71    * Revert a call to PushEventQueue. When an event queue is popped, any events
72    * remaining in the queue are appended to the elder queue. This also causes
73    * the nsIEventTarget returned from PushEventQueue to stop dispatching events.
74    * Must only be called on the target thread, and with the innermost event
75    * queue.
76    */
77   void PopEventQueue(nsIEventTarget* aTarget);
78 
79   already_AddRefed<nsIThreadObserver> GetObserver() final;
80   already_AddRefed<nsIThreadObserver> GetObserverOnThread() final;
81   void SetObserver(nsIThreadObserver* aObserver) final;
82 
MutexRef()83   Mutex& MutexRef() { return mLock; }
84 
85  private:
86   class NestedSink;
87 
88   virtual ~ThreadEventQueue();
89 
90   bool PutEventInternal(already_AddRefed<nsIRunnable>&& aEvent,
91                         EventPriority aPriority, NestedSink* aQueue);
92 
93   UniquePtr<InnerQueueT> mBaseQueue;
94 
95   struct NestedQueueItem {
96     UniquePtr<EventQueue> mQueue;
97     RefPtr<ThreadEventTarget> mEventTarget;
98 
NestedQueueItemNestedQueueItem99     NestedQueueItem(UniquePtr<EventQueue> aQueue,
100                     ThreadEventTarget* aEventTarget)
101         : mQueue(Move(aQueue)), mEventTarget(aEventTarget) {}
102   };
103 
104   nsTArray<NestedQueueItem> mNestedQueues;
105 
106   Mutex mLock;
107   CondVar mEventsAvailable;
108 
109   bool mEventsAreDoomed = false;
110   nsCOMPtr<nsIThreadObserver> mObserver;
111 };
112 
113 extern template class ThreadEventQueue<EventQueue>;
114 extern template class ThreadEventQueue<PrioritizedEventQueue<EventQueue>>;
115 extern template class ThreadEventQueue<
116     PrioritizedEventQueue<LabeledEventQueue>>;
117 
118 };  // namespace mozilla
119 
120 #endif  // mozilla_ThreadEventQueue_h
121