|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */ |
|
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/ReentrantMonitor.h" |
|
12 #include "nsIRunnable.h" |
|
13 |
|
14 // A threadsafe FIFO event queue... |
|
15 class nsEventQueue |
|
16 { |
|
17 typedef mozilla::ReentrantMonitor ReentrantMonitor; |
|
18 |
|
19 public: |
|
20 nsEventQueue(); |
|
21 ~nsEventQueue(); |
|
22 |
|
23 // This method adds a new event to the pending event queue. The event object |
|
24 // is AddRef'd if this method succeeds. This method returns true if the |
|
25 // event was stored in the event queue, and it returns false if it could |
|
26 // not allocate sufficient memory. |
|
27 bool PutEvent(nsIRunnable *event); |
|
28 |
|
29 // This method gets an event from the event queue. If mayWait is true, then |
|
30 // the method will block the calling thread until an event is available. If |
|
31 // the event is null, then the method returns immediately indicating whether |
|
32 // or not an event is pending. When the resulting event is non-null, the |
|
33 // caller is responsible for releasing the event object. This method does |
|
34 // not alter the reference count of the resulting event. |
|
35 bool GetEvent(bool mayWait, nsIRunnable **event); |
|
36 |
|
37 // This method returns true if there is a pending event. |
|
38 bool HasPendingEvent() { |
|
39 return GetEvent(false, nullptr); |
|
40 } |
|
41 |
|
42 // This method returns the next pending event or null. |
|
43 bool GetPendingEvent(nsIRunnable **runnable) { |
|
44 return GetEvent(false, runnable); |
|
45 } |
|
46 |
|
47 // This method waits for and returns the next pending event. |
|
48 bool WaitPendingEvent(nsIRunnable **runnable) { |
|
49 return GetEvent(true, runnable); |
|
50 } |
|
51 |
|
52 // Expose the event queue's monitor for "power users" |
|
53 ReentrantMonitor& GetReentrantMonitor() { |
|
54 return mReentrantMonitor; |
|
55 } |
|
56 |
|
57 private: |
|
58 |
|
59 bool IsEmpty() { |
|
60 return !mHead || (mHead == mTail && mOffsetHead == mOffsetTail); |
|
61 } |
|
62 |
|
63 enum { EVENTS_PER_PAGE = 255 }; |
|
64 |
|
65 // Page objects are linked together to form a simple deque. |
|
66 |
|
67 struct Page { |
|
68 struct Page *mNext; |
|
69 nsIRunnable *mEvents[EVENTS_PER_PAGE]; |
|
70 }; |
|
71 |
|
72 static_assert((sizeof(Page) & (sizeof(Page) - 1)) == 0, |
|
73 "sizeof(Page) should be a power of two to avoid heap slop."); |
|
74 |
|
75 static Page *NewPage() { |
|
76 return static_cast<Page *>(calloc(1, sizeof(Page))); |
|
77 } |
|
78 |
|
79 static void FreePage(Page *p) { |
|
80 free(p); |
|
81 } |
|
82 |
|
83 ReentrantMonitor mReentrantMonitor; |
|
84 |
|
85 Page *mHead; |
|
86 Page *mTail; |
|
87 |
|
88 uint16_t mOffsetHead; // offset into mHead where next item is removed |
|
89 uint16_t mOffsetTail; // offset into mTail where next item is added |
|
90 }; |
|
91 |
|
92 #endif // nsEventQueue_h__ |