|
1 #include "base/process_util.h" |
|
2 |
|
3 #include "TestHangs.h" |
|
4 |
|
5 #include "IPDLUnitTests.h" // fail etc. |
|
6 |
|
7 using base::KillProcess; |
|
8 |
|
9 template<> |
|
10 struct RunnableMethodTraits<mozilla::_ipdltest::TestHangsParent> |
|
11 { |
|
12 static void RetainCallee(mozilla::_ipdltest::TestHangsParent* obj) { } |
|
13 static void ReleaseCallee(mozilla::_ipdltest::TestHangsParent* obj) { } |
|
14 }; |
|
15 |
|
16 namespace mozilla { |
|
17 namespace _ipdltest { |
|
18 |
|
19 //----------------------------------------------------------------------------- |
|
20 // parent |
|
21 |
|
22 TestHangsParent::TestHangsParent() : mDetectedHang(false) |
|
23 { |
|
24 MOZ_COUNT_CTOR(TestHangsParent); |
|
25 } |
|
26 |
|
27 TestHangsParent::~TestHangsParent() |
|
28 { |
|
29 MOZ_COUNT_DTOR(TestHangsParent); |
|
30 } |
|
31 |
|
32 void |
|
33 TestHangsParent::Main() |
|
34 { |
|
35 // Here we try to set things up to test the following sequence of events: |
|
36 // |
|
37 // - subprocess causes an OnMaybeDequeueOne() task to be posted to |
|
38 // this thread |
|
39 // |
|
40 // - subprocess hangs just long enough for the hang timer to expire |
|
41 // |
|
42 // - hang-kill code in the parent starts running |
|
43 // |
|
44 // - subprocess replies to message while hang code runs |
|
45 // |
|
46 // - reply is processed in OnMaybeDequeueOne() before Close() has |
|
47 // been called or the channel error notification has been posted |
|
48 |
|
49 // this tells the subprocess to send us Nonce() |
|
50 if (!SendStart()) |
|
51 fail("sending Start"); |
|
52 |
|
53 // now we sleep here for a while awaiting the Nonce() message from |
|
54 // the child. since we're not blocked on anything, the IO thread |
|
55 // will enqueue an OnMaybeDequeueOne() task to process that |
|
56 // message |
|
57 // |
|
58 // NB: PR_Sleep is exactly what we want, only the current thread |
|
59 // sleeping |
|
60 PR_Sleep(5000); |
|
61 |
|
62 // when we call into this, we'll pull the Nonce() message out of |
|
63 // the mPending queue, but that doesn't matter ... the |
|
64 // OnMaybeDequeueOne() event will remain |
|
65 if (CallStackFrame() && mDetectedHang) |
|
66 fail("should have timed out!"); |
|
67 |
|
68 // the Close() task in the queue will shut us down |
|
69 } |
|
70 |
|
71 bool |
|
72 TestHangsParent::ShouldContinueFromReplyTimeout() |
|
73 { |
|
74 mDetectedHang = true; |
|
75 |
|
76 // so we've detected a timeout after 2 ms ... now we cheat and |
|
77 // sleep for a long time, to allow the subprocess's reply to come |
|
78 // in |
|
79 |
|
80 PR_Sleep(5000); |
|
81 |
|
82 // reply should be here; we'll post a task to shut things down. |
|
83 // This must be after OnMaybeDequeueOne() in the event queue. |
|
84 MessageLoop::current()->PostTask( |
|
85 FROM_HERE, NewRunnableMethod(this, &TestHangsParent::CleanUp)); |
|
86 |
|
87 return false; |
|
88 } |
|
89 |
|
90 bool |
|
91 TestHangsParent::AnswerStackFrame() |
|
92 { |
|
93 if (PTestHangs::HANG != state()) { |
|
94 if (CallStackFrame()) |
|
95 fail("should have timed out!"); |
|
96 } |
|
97 else { |
|
98 // minimum possible, 2 ms. We want to detecting a hang to race |
|
99 // with the reply coming in, as reliably as possible |
|
100 SetReplyTimeoutMs(2); |
|
101 |
|
102 if (CallHang()) |
|
103 fail("should have timed out!"); |
|
104 } |
|
105 |
|
106 return true; |
|
107 } |
|
108 |
|
109 void |
|
110 TestHangsParent::CleanUp() |
|
111 { |
|
112 if (!KillProcess(OtherProcess(), 0, false)) |
|
113 fail("terminating child process"); |
|
114 Close(); |
|
115 } |
|
116 |
|
117 |
|
118 //----------------------------------------------------------------------------- |
|
119 // child |
|
120 |
|
121 TestHangsChild::TestHangsChild() |
|
122 { |
|
123 MOZ_COUNT_CTOR(TestHangsChild); |
|
124 } |
|
125 |
|
126 TestHangsChild::~TestHangsChild() |
|
127 { |
|
128 MOZ_COUNT_DTOR(TestHangsChild); |
|
129 } |
|
130 |
|
131 bool |
|
132 TestHangsChild::AnswerHang() |
|
133 { |
|
134 puts(" (child process is 'hanging' now)"); |
|
135 |
|
136 // just sleep until we're reasonably confident the 1ms hang |
|
137 // detector fired in the parent process and it's sleeping in |
|
138 // ShouldContinueFromReplyTimeout() |
|
139 PR_Sleep(1000); |
|
140 |
|
141 return true; |
|
142 } |
|
143 |
|
144 } // namespace _ipdltest |
|
145 } // namespace mozilla |