xpcom/threads/nsEventQueue.cpp

branch
TOR_BUG_9701
changeset 15
b8a032363ba2
equal deleted inserted replaced
-1:000000000000 0:f6d7c35eb980
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 #include "nsEventQueue.h"
8 #include "nsAutoPtr.h"
9 #include "prlog.h"
10 #include "nsThreadUtils.h"
11 #include "prthread.h"
12 #include "mozilla/ChaosMode.h"
13
14 using namespace mozilla;
15
16 #ifdef PR_LOGGING
17 static PRLogModuleInfo *
18 GetLog()
19 {
20 static PRLogModuleInfo *sLog;
21 if (!sLog)
22 sLog = PR_NewLogModule("nsEventQueue");
23 return sLog;
24 }
25 #endif
26 #ifdef LOG
27 #undef LOG
28 #endif
29 #define LOG(args) PR_LOG(GetLog(), PR_LOG_DEBUG, args)
30
31 nsEventQueue::nsEventQueue()
32 : mReentrantMonitor("nsEventQueue.mReentrantMonitor")
33 , mHead(nullptr)
34 , mTail(nullptr)
35 , mOffsetHead(0)
36 , mOffsetTail(0)
37 {
38 }
39
40 nsEventQueue::~nsEventQueue()
41 {
42 // It'd be nice to be able to assert that no one else is holding the monitor,
43 // but NSPR doesn't really expose APIs for it.
44 NS_ASSERTION(IsEmpty(), "Non-empty event queue being destroyed; events being leaked.");
45
46 if (mHead)
47 FreePage(mHead);
48 }
49
50 bool
51 nsEventQueue::GetEvent(bool mayWait, nsIRunnable **result)
52 {
53 {
54 ReentrantMonitorAutoEnter mon(mReentrantMonitor);
55
56 while (IsEmpty()) {
57 if (!mayWait) {
58 if (result)
59 *result = nullptr;
60 return false;
61 }
62 LOG(("EVENTQ(%p): wait begin\n", this));
63 mon.Wait();
64 LOG(("EVENTQ(%p): wait end\n", this));
65 }
66
67 if (result) {
68 *result = mHead->mEvents[mOffsetHead++];
69
70 // Check if mHead points to empty Page
71 if (mOffsetHead == EVENTS_PER_PAGE) {
72 Page *dead = mHead;
73 mHead = mHead->mNext;
74 FreePage(dead);
75 mOffsetHead = 0;
76 }
77 }
78 }
79
80 return true;
81 }
82
83 bool
84 nsEventQueue::PutEvent(nsIRunnable *runnable)
85 {
86 // Avoid calling AddRef+Release while holding our monitor.
87 nsRefPtr<nsIRunnable> event(runnable);
88 bool rv = true;
89 {
90 if (ChaosMode::isActive()) {
91 // With probability 0.5, yield so other threads have a chance to
92 // dispatch events to this queue first.
93 if (ChaosMode::randomUint32LessThan(2)) {
94 PR_Sleep(PR_INTERVAL_NO_WAIT);
95 }
96 }
97
98 ReentrantMonitorAutoEnter mon(mReentrantMonitor);
99
100 if (!mHead) {
101 mHead = NewPage();
102 if (!mHead) {
103 rv = false;
104 } else {
105 mTail = mHead;
106 mOffsetHead = 0;
107 mOffsetTail = 0;
108 }
109 } else if (mOffsetTail == EVENTS_PER_PAGE) {
110 Page *page = NewPage();
111 if (!page) {
112 rv = false;
113 } else {
114 mTail->mNext = page;
115 mTail = page;
116 mOffsetTail = 0;
117 }
118 }
119 if (rv) {
120 event.swap(mTail->mEvents[mOffsetTail]);
121 ++mOffsetTail;
122 LOG(("EVENTQ(%p): notify\n", this));
123 mon.NotifyAll();
124 }
125 }
126 return rv;
127 }

mercurial