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