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