Line data Source code
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 nsEventQueue_h__
8 : #define nsEventQueue_h__
9 :
10 : #include <stdlib.h>
11 : #include "mozilla/CondVar.h"
12 : #include "mozilla/Mutex.h"
13 : #include "nsIRunnable.h"
14 : #include "nsCOMPtr.h"
15 : #include "mozilla/AlreadyAddRefed.h"
16 : #include "mozilla/UniquePtr.h"
17 :
18 : class nsThreadPool;
19 :
20 : // A threadsafe FIFO event queue...
21 : class nsEventQueue
22 : {
23 : public:
24 : typedef mozilla::MutexAutoLock MutexAutoLock;
25 :
26 : enum EventQueueType
27 : {
28 : eNormalQueue,
29 : eSharedCondVarQueue
30 : };
31 :
32 : nsEventQueue(mozilla::CondVar& aCondVar, EventQueueType aType);
33 : ~nsEventQueue();
34 :
35 : // This method adds a new event to the pending event queue. The queue holds
36 : // a strong reference to the event after this method returns. This method
37 : // cannot fail.
38 : void PutEvent(nsIRunnable* aEvent, MutexAutoLock& aProofOfLock);
39 : void PutEvent(already_AddRefed<nsIRunnable>&& aEvent,
40 : MutexAutoLock& aProofOfLock);
41 :
42 : // Return the first event in the queue without popping it. Returns whether the
43 : // queue was empty or not. aEvent is set to null if the queue was empty.
44 : bool PeekEvent(nsIRunnable** aEvent, MutexAutoLock& aProofOfLock);
45 :
46 : // This method gets an event from the event queue. If mayWait is true, then
47 : // the method will block the calling thread until an event is available. If
48 : // the event is null, then the method returns immediately indicating whether
49 : // or not an event is pending. When the resulting event is non-null, the
50 : // caller is responsible for releasing the event object. This method does
51 : // not alter the reference count of the resulting event.
52 : bool GetEvent(bool aMayWait, nsIRunnable** aEvent,
53 : MutexAutoLock& aProofOfLock);
54 :
55 : // This method returns true if there is a pending event.
56 4825 : bool HasPendingEvent(MutexAutoLock& aProofOfLock)
57 : {
58 4825 : return GetEvent(false, nullptr, aProofOfLock);
59 : }
60 :
61 : // This method returns the next pending event or null.
62 159 : bool GetPendingEvent(nsIRunnable** aRunnable, MutexAutoLock& aProofOfLock)
63 : {
64 159 : return GetEvent(false, aRunnable, aProofOfLock);
65 : }
66 :
67 : size_t Count(MutexAutoLock&) const;
68 :
69 : private:
70 7205 : bool IsEmpty()
71 : {
72 7205 : return !mHead || (mHead == mTail && mOffsetHead == mOffsetTail);
73 : }
74 :
75 : enum
76 : {
77 : EVENTS_PER_PAGE = 255
78 : };
79 :
80 : // Page objects are linked together to form a simple deque.
81 :
82 : struct Page
83 : {
84 : struct Page* mNext;
85 : nsIRunnable* mEvents[EVENTS_PER_PAGE];
86 : };
87 :
88 : static_assert((sizeof(Page) & (sizeof(Page) - 1)) == 0,
89 : "sizeof(Page) should be a power of two to avoid heap slop.");
90 :
91 87 : static Page* NewPage()
92 : {
93 87 : return static_cast<Page*>(moz_xcalloc(1, sizeof(Page)));
94 : }
95 :
96 17 : static void FreePage(Page* aPage)
97 : {
98 17 : free(aPage);
99 17 : }
100 :
101 : Page* mHead;
102 : Page* mTail;
103 :
104 : uint16_t mOffsetHead; // offset into mHead where next item is removed
105 : uint16_t mOffsetTail; // offset into mTail where next item is added
106 : mozilla::CondVar& mEventsAvailable;
107 :
108 : EventQueueType mType;
109 :
110 : // These methods are made available to nsThreadPool as a hack, since
111 : // nsThreadPool needs to have its threads sleep for fixed amounts of
112 : // time as well as being able to wake up all threads when thread
113 : // limits change.
114 : friend class nsThreadPool;
115 73 : void Wait(PRIntervalTime aInterval)
116 : {
117 73 : MOZ_ASSERT(mType == eNormalQueue);
118 73 : mEventsAvailable.Wait(aInterval);
119 71 : }
120 0 : void NotifyAll()
121 : {
122 0 : MOZ_ASSERT(mType == eNormalQueue);
123 0 : mEventsAvailable.NotifyAll();
124 0 : }
125 : };
126 :
127 : #endif // nsEventQueue_h__
|