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