1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: sw=2 ts=4 et :
3 */
4 #include "TestDemon.h"
5
6 #include <stdlib.h>
7
8 #include "IPDLUnitTests.h" // fail etc.
9 #if defined(OS_POSIX)
10 # include <sys/time.h>
11 # include <unistd.h>
12 #else
13 # include <time.h>
14 # include <windows.h>
15 #endif
16
17 namespace mozilla {
18 namespace _ipdltest {
19
20 const int kMaxStackHeight = 4;
21
22 static LazyLogModule sLogModule("demon");
23
24 #define DEMON_LOG(...) MOZ_LOG(sLogModule, LogLevel::Debug, (__VA_ARGS__))
25
26 static int gStackHeight = 0;
27 static bool gFlushStack = false;
28
Choose(int count)29 static int Choose(int count) {
30 #if defined(OS_POSIX)
31 return random() % count;
32 #else
33 return rand() % count;
34 #endif
35 }
36
37 //-----------------------------------------------------------------------------
38 // parent
39
TestDemonParent()40 TestDemonParent::TestDemonParent() : mDone(false), mIncoming(), mOutgoing() {
41 MOZ_COUNT_CTOR(TestDemonParent);
42 }
43
~TestDemonParent()44 TestDemonParent::~TestDemonParent() { MOZ_COUNT_DTOR(TestDemonParent); }
45
Main()46 void TestDemonParent::Main() {
47 if (!getenv("MOZ_TEST_IPC_DEMON")) {
48 QuitParent();
49 return;
50 }
51 #if defined(OS_POSIX)
52 srandom(time(nullptr));
53 #else
54 srand(time(nullptr));
55 #endif
56
57 DEMON_LOG("Start demon");
58
59 if (!SendStart()) fail("sending Start");
60
61 RunUnlimitedSequence();
62 }
63
64 #ifdef DEBUG
ShouldContinueFromReplyTimeout()65 bool TestDemonParent::ShouldContinueFromReplyTimeout() {
66 return Choose(2) == 0;
67 }
68
ArtificialTimeout()69 bool TestDemonParent::ArtificialTimeout() { return Choose(5) == 0; }
70
ArtificialSleep()71 void TestDemonParent::ArtificialSleep() {
72 if (Choose(2) == 0) {
73 // Sleep for anywhere from 0 to 100 milliseconds.
74 unsigned micros = Choose(100) * 1000;
75 # ifdef OS_POSIX
76 usleep(micros);
77 # else
78 Sleep(micros / 1000);
79 # endif
80 }
81 }
82 #endif
83
RecvAsyncMessage(const int & n)84 mozilla::ipc::IPCResult TestDemonParent::RecvAsyncMessage(const int& n) {
85 DEMON_LOG("Start RecvAsync [%d]", n);
86
87 MOZ_ASSERT(n == mIncoming[0]);
88 mIncoming[0]++;
89
90 RunLimitedSequence();
91
92 DEMON_LOG("End RecvAsync [%d]", n);
93 return IPC_OK();
94 }
95
RecvHiPrioSyncMessage()96 mozilla::ipc::IPCResult TestDemonParent::RecvHiPrioSyncMessage() {
97 DEMON_LOG("Start RecvHiPrioSyncMessage");
98 RunLimitedSequence();
99 DEMON_LOG("End RecvHiPrioSyncMessage");
100 return IPC_OK();
101 }
102
RecvSyncMessage(const int & n)103 mozilla::ipc::IPCResult TestDemonParent::RecvSyncMessage(const int& n) {
104 DEMON_LOG("Start RecvSync [%d]", n);
105
106 MOZ_ASSERT(n == mIncoming[0]);
107 mIncoming[0]++;
108
109 RunLimitedSequence(ASYNC_ONLY);
110
111 DEMON_LOG("End RecvSync [%d]", n);
112 return IPC_OK();
113 }
114
RecvUrgentAsyncMessage(const int & n)115 mozilla::ipc::IPCResult TestDemonParent::RecvUrgentAsyncMessage(const int& n) {
116 DEMON_LOG("Start RecvUrgentAsyncMessage [%d]", n);
117
118 MOZ_ASSERT(n == mIncoming[2]);
119 mIncoming[2]++;
120
121 RunLimitedSequence(ASYNC_ONLY);
122
123 DEMON_LOG("End RecvUrgentAsyncMessage [%d]", n);
124 return IPC_OK();
125 }
126
RecvUrgentSyncMessage(const int & n)127 mozilla::ipc::IPCResult TestDemonParent::RecvUrgentSyncMessage(const int& n) {
128 DEMON_LOG("Start RecvUrgentSyncMessage [%d]", n);
129
130 MOZ_ASSERT(n == mIncoming[2]);
131 mIncoming[2]++;
132
133 RunLimitedSequence(ASYNC_ONLY);
134
135 DEMON_LOG("End RecvUrgentSyncMessage [%d]", n);
136 return IPC_OK();
137 }
138
RunUnlimitedSequence()139 void TestDemonParent::RunUnlimitedSequence() {
140 if (mDone) {
141 return;
142 }
143
144 gFlushStack = false;
145 DoAction();
146
147 MessageLoop::current()->PostTask(NewNonOwningRunnableMethod(
148 "_ipdltest::TestDemonParent::RunUnlimitedSequence", this,
149 &TestDemonParent::RunUnlimitedSequence));
150 }
151
RunLimitedSequence(int flags)152 void TestDemonParent::RunLimitedSequence(int flags) {
153 if (gStackHeight >= kMaxStackHeight) {
154 return;
155 }
156 gStackHeight++;
157
158 int count = Choose(20);
159 for (int i = 0; i < count; i++) {
160 if (!DoAction(flags)) {
161 gFlushStack = true;
162 }
163 if (gFlushStack) {
164 gStackHeight--;
165 return;
166 }
167 }
168
169 gStackHeight--;
170 }
171
AllowAsync(int outgoing,int incoming)172 static bool AllowAsync(int outgoing, int incoming) {
173 return incoming >= outgoing - 5;
174 }
175
DoAction(int flags)176 bool TestDemonParent::DoAction(int flags) {
177 if (flags & ASYNC_ONLY) {
178 if (AllowAsync(mOutgoing[0], mIncoming[0])) {
179 DEMON_LOG("SendAsyncMessage [%d]", mOutgoing[0]);
180 return SendAsyncMessage(mOutgoing[0]++);
181 } else {
182 return true;
183 }
184 } else {
185 switch (Choose(3)) {
186 case 0:
187 if (AllowAsync(mOutgoing[0], mIncoming[0])) {
188 DEMON_LOG("SendAsyncMessage [%d]", mOutgoing[0]);
189 return SendAsyncMessage(mOutgoing[0]++);
190 } else {
191 return true;
192 }
193
194 case 1: {
195 DEMON_LOG("Start SendHiPrioSyncMessage");
196 bool r = SendHiPrioSyncMessage();
197 DEMON_LOG("End SendHiPrioSyncMessage result=%d", r);
198 return r;
199 }
200
201 case 2:
202 DEMON_LOG("Cancel");
203 GetIPCChannel()->CancelCurrentTransaction();
204 return true;
205 }
206 }
207 MOZ_CRASH();
208 return false;
209 }
210
211 //-----------------------------------------------------------------------------
212 // child
213
TestDemonChild()214 TestDemonChild::TestDemonChild() : mIncoming(), mOutgoing() {
215 MOZ_COUNT_CTOR(TestDemonChild);
216 }
217
~TestDemonChild()218 TestDemonChild::~TestDemonChild() { MOZ_COUNT_DTOR(TestDemonChild); }
219
RecvStart()220 mozilla::ipc::IPCResult TestDemonChild::RecvStart() {
221 #ifdef OS_POSIX
222 srandom(time(nullptr));
223 #else
224 srand(time(nullptr));
225 #endif
226
227 DEMON_LOG("RecvStart");
228
229 RunUnlimitedSequence();
230 return IPC_OK();
231 }
232
233 #ifdef DEBUG
ArtificialSleep()234 void TestDemonChild::ArtificialSleep() {
235 if (Choose(2) == 0) {
236 // Sleep for anywhere from 0 to 100 milliseconds.
237 unsigned micros = Choose(100) * 1000;
238 # ifdef OS_POSIX
239 usleep(micros);
240 # else
241 Sleep(micros / 1000);
242 # endif
243 }
244 }
245 #endif
246
RecvAsyncMessage(const int & n)247 mozilla::ipc::IPCResult TestDemonChild::RecvAsyncMessage(const int& n) {
248 DEMON_LOG("Start RecvAsyncMessage [%d]", n);
249
250 MOZ_ASSERT(n == mIncoming[0]);
251 mIncoming[0]++;
252
253 RunLimitedSequence();
254
255 DEMON_LOG("End RecvAsyncMessage [%d]", n);
256 return IPC_OK();
257 }
258
RecvHiPrioSyncMessage()259 mozilla::ipc::IPCResult TestDemonChild::RecvHiPrioSyncMessage() {
260 DEMON_LOG("Start RecvHiPrioSyncMessage");
261 RunLimitedSequence();
262 DEMON_LOG("End RecvHiPrioSyncMessage");
263 return IPC_OK();
264 }
265
RunUnlimitedSequence()266 void TestDemonChild::RunUnlimitedSequence() {
267 gFlushStack = false;
268 DoAction();
269
270 MessageLoop::current()->PostTask(NewNonOwningRunnableMethod(
271 "_ipdltest::TestDemonChild::RunUnlimitedSequence", this,
272 &TestDemonChild::RunUnlimitedSequence));
273 }
274
RunLimitedSequence()275 void TestDemonChild::RunLimitedSequence() {
276 if (gStackHeight >= kMaxStackHeight) {
277 return;
278 }
279 gStackHeight++;
280
281 int count = Choose(20);
282 for (int i = 0; i < count; i++) {
283 if (!DoAction()) {
284 gFlushStack = true;
285 }
286 if (gFlushStack) {
287 gStackHeight--;
288 return;
289 }
290 }
291
292 gStackHeight--;
293 }
294
DoAction()295 bool TestDemonChild::DoAction() {
296 switch (Choose(6)) {
297 case 0:
298 if (AllowAsync(mOutgoing[0], mIncoming[0])) {
299 DEMON_LOG("SendAsyncMessage [%d]", mOutgoing[0]);
300 return SendAsyncMessage(mOutgoing[0]++);
301 } else {
302 return true;
303 }
304
305 case 1: {
306 DEMON_LOG("Start SendHiPrioSyncMessage");
307 bool r = SendHiPrioSyncMessage();
308 DEMON_LOG("End SendHiPrioSyncMessage result=%d", r);
309 return r;
310 }
311
312 case 2: {
313 DEMON_LOG("Start SendSyncMessage [%d]", mOutgoing[0]);
314 bool r = SendSyncMessage(mOutgoing[0]++);
315 switch (GetIPCChannel()->LastSendError()) {
316 case SyncSendError::PreviousTimeout:
317 case SyncSendError::SendingCPOWWhileDispatchingSync:
318 case SyncSendError::SendingCPOWWhileDispatchingUrgent:
319 case SyncSendError::NotConnectedBeforeSend:
320 case SyncSendError::CancelledBeforeSend:
321 mOutgoing[0]--;
322 break;
323 default:
324 break;
325 }
326 DEMON_LOG("End SendSyncMessage result=%d", r);
327 return r;
328 }
329
330 case 3:
331 DEMON_LOG("SendUrgentAsyncMessage [%d]", mOutgoing[2]);
332 return SendUrgentAsyncMessage(mOutgoing[2]++);
333
334 case 4: {
335 DEMON_LOG("Start SendUrgentSyncMessage [%d]", mOutgoing[2]);
336 bool r = SendUrgentSyncMessage(mOutgoing[2]++);
337 switch (GetIPCChannel()->LastSendError()) {
338 case SyncSendError::PreviousTimeout:
339 case SyncSendError::SendingCPOWWhileDispatchingSync:
340 case SyncSendError::SendingCPOWWhileDispatchingUrgent:
341 case SyncSendError::NotConnectedBeforeSend:
342 case SyncSendError::CancelledBeforeSend:
343 mOutgoing[2]--;
344 break;
345 default:
346 break;
347 }
348 DEMON_LOG("End SendUrgentSyncMessage result=%d", r);
349 return r;
350 }
351
352 case 5:
353 DEMON_LOG("Cancel");
354 GetIPCChannel()->CancelCurrentTransaction();
355 return true;
356 }
357 MOZ_CRASH();
358 return false;
359 }
360
361 } // namespace _ipdltest
362 } // namespace mozilla
363