OLD | NEW |
| (Empty) |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 // NOTE(vtl): Some of these tests are inherently flaky (e.g., if run on a | |
6 // heavily-loaded system). Sorry. |test::EpsilonDeadline()| may be increased to | |
7 // increase tolerance and reduce observed flakiness (though doing so reduces the | |
8 // meaningfulness of the test). | |
9 | |
10 #include "mojo/edk/system/waiter.h" | |
11 | |
12 #include <stdint.h> | |
13 | |
14 #include "base/macros.h" | |
15 #include "base/synchronization/lock.h" | |
16 #include "base/threading/simple_thread.h" | |
17 #include "mojo/edk/system/test_utils.h" | |
18 #include "testing/gtest/include/gtest/gtest.h" | |
19 | |
20 namespace mojo { | |
21 namespace edk { | |
22 namespace { | |
23 | |
24 const unsigned kPollTimeMs = 10; | |
25 | |
26 class WaitingThread : public base::SimpleThread { | |
27 public: | |
28 explicit WaitingThread(MojoDeadline deadline) | |
29 : base::SimpleThread("waiting_thread"), | |
30 deadline_(deadline), | |
31 done_(false), | |
32 result_(MOJO_RESULT_UNKNOWN), | |
33 context_(static_cast<uintptr_t>(-1)) { | |
34 waiter_.Init(); | |
35 } | |
36 | |
37 ~WaitingThread() override { Join(); } | |
38 | |
39 void WaitUntilDone(MojoResult* result, | |
40 uintptr_t* context, | |
41 MojoDeadline* elapsed) { | |
42 for (;;) { | |
43 { | |
44 base::AutoLock locker(lock_); | |
45 if (done_) { | |
46 *result = result_; | |
47 *context = context_; | |
48 *elapsed = elapsed_; | |
49 break; | |
50 } | |
51 } | |
52 | |
53 test::Sleep(test::DeadlineFromMilliseconds(kPollTimeMs)); | |
54 } | |
55 } | |
56 | |
57 Waiter* waiter() { return &waiter_; } | |
58 | |
59 private: | |
60 void Run() override { | |
61 test::Stopwatch stopwatch; | |
62 MojoResult result; | |
63 uintptr_t context = static_cast<uintptr_t>(-1); | |
64 MojoDeadline elapsed; | |
65 | |
66 stopwatch.Start(); | |
67 result = waiter_.Wait(deadline_, &context); | |
68 elapsed = stopwatch.Elapsed(); | |
69 | |
70 { | |
71 base::AutoLock locker(lock_); | |
72 done_ = true; | |
73 result_ = result; | |
74 context_ = context; | |
75 elapsed_ = elapsed; | |
76 } | |
77 } | |
78 | |
79 const MojoDeadline deadline_; | |
80 Waiter waiter_; // Thread-safe. | |
81 | |
82 base::Lock lock_; // Protects the following members. | |
83 bool done_; | |
84 MojoResult result_; | |
85 uintptr_t context_; | |
86 MojoDeadline elapsed_; | |
87 | |
88 DISALLOW_COPY_AND_ASSIGN(WaitingThread); | |
89 }; | |
90 | |
91 TEST(WaiterTest, Basic) { | |
92 MojoResult result; | |
93 uintptr_t context; | |
94 MojoDeadline elapsed; | |
95 | |
96 // Finite deadline. | |
97 | |
98 // Awake immediately after thread start. | |
99 { | |
100 WaitingThread thread(10 * test::EpsilonDeadline()); | |
101 thread.Start(); | |
102 thread.waiter()->Awake(MOJO_RESULT_OK, 1); | |
103 thread.WaitUntilDone(&result, &context, &elapsed); | |
104 EXPECT_EQ(MOJO_RESULT_OK, result); | |
105 EXPECT_EQ(1u, context); | |
106 EXPECT_LT(elapsed, test::EpsilonDeadline()); | |
107 } | |
108 | |
109 // Awake before after thread start. | |
110 { | |
111 WaitingThread thread(10 * test::EpsilonDeadline()); | |
112 thread.waiter()->Awake(MOJO_RESULT_CANCELLED, 2); | |
113 thread.Start(); | |
114 thread.WaitUntilDone(&result, &context, &elapsed); | |
115 EXPECT_EQ(MOJO_RESULT_CANCELLED, result); | |
116 EXPECT_EQ(2u, context); | |
117 EXPECT_LT(elapsed, test::EpsilonDeadline()); | |
118 } | |
119 | |
120 // Awake some time after thread start. | |
121 { | |
122 WaitingThread thread(10 * test::EpsilonDeadline()); | |
123 thread.Start(); | |
124 test::Sleep(2 * test::EpsilonDeadline()); | |
125 thread.waiter()->Awake(1, 3); | |
126 thread.WaitUntilDone(&result, &context, &elapsed); | |
127 EXPECT_EQ(1u, result); | |
128 EXPECT_EQ(3u, context); | |
129 EXPECT_GT(elapsed, (2 - 1) * test::EpsilonDeadline()); | |
130 EXPECT_LT(elapsed, (2 + 1) * test::EpsilonDeadline()); | |
131 } | |
132 | |
133 // Awake some longer time after thread start. | |
134 { | |
135 WaitingThread thread(10 * test::EpsilonDeadline()); | |
136 thread.Start(); | |
137 test::Sleep(5 * test::EpsilonDeadline()); | |
138 thread.waiter()->Awake(2, 4); | |
139 thread.WaitUntilDone(&result, &context, &elapsed); | |
140 EXPECT_EQ(2u, result); | |
141 EXPECT_EQ(4u, context); | |
142 EXPECT_GT(elapsed, (5 - 1) * test::EpsilonDeadline()); | |
143 EXPECT_LT(elapsed, (5 + 1) * test::EpsilonDeadline()); | |
144 } | |
145 | |
146 // Don't awake -- time out (on another thread). | |
147 { | |
148 WaitingThread thread(2 * test::EpsilonDeadline()); | |
149 thread.Start(); | |
150 thread.WaitUntilDone(&result, &context, &elapsed); | |
151 EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, result); | |
152 EXPECT_EQ(static_cast<uintptr_t>(-1), context); | |
153 EXPECT_GT(elapsed, (2 - 1) * test::EpsilonDeadline()); | |
154 EXPECT_LT(elapsed, (2 + 1) * test::EpsilonDeadline()); | |
155 } | |
156 | |
157 // No (indefinite) deadline. | |
158 | |
159 // Awake immediately after thread start. | |
160 { | |
161 WaitingThread thread(MOJO_DEADLINE_INDEFINITE); | |
162 thread.Start(); | |
163 thread.waiter()->Awake(MOJO_RESULT_OK, 5); | |
164 thread.WaitUntilDone(&result, &context, &elapsed); | |
165 EXPECT_EQ(MOJO_RESULT_OK, result); | |
166 EXPECT_EQ(5u, context); | |
167 EXPECT_LT(elapsed, test::EpsilonDeadline()); | |
168 } | |
169 | |
170 // Awake before after thread start. | |
171 { | |
172 WaitingThread thread(MOJO_DEADLINE_INDEFINITE); | |
173 thread.waiter()->Awake(MOJO_RESULT_CANCELLED, 6); | |
174 thread.Start(); | |
175 thread.WaitUntilDone(&result, &context, &elapsed); | |
176 EXPECT_EQ(MOJO_RESULT_CANCELLED, result); | |
177 EXPECT_EQ(6u, context); | |
178 EXPECT_LT(elapsed, test::EpsilonDeadline()); | |
179 } | |
180 | |
181 // Awake some time after thread start. | |
182 { | |
183 WaitingThread thread(MOJO_DEADLINE_INDEFINITE); | |
184 thread.Start(); | |
185 test::Sleep(2 * test::EpsilonDeadline()); | |
186 thread.waiter()->Awake(1, 7); | |
187 thread.WaitUntilDone(&result, &context, &elapsed); | |
188 EXPECT_EQ(1u, result); | |
189 EXPECT_EQ(7u, context); | |
190 EXPECT_GT(elapsed, (2 - 1) * test::EpsilonDeadline()); | |
191 EXPECT_LT(elapsed, (2 + 1) * test::EpsilonDeadline()); | |
192 } | |
193 | |
194 // Awake some longer time after thread start. | |
195 { | |
196 WaitingThread thread(MOJO_DEADLINE_INDEFINITE); | |
197 thread.Start(); | |
198 test::Sleep(5 * test::EpsilonDeadline()); | |
199 thread.waiter()->Awake(2, 8); | |
200 thread.WaitUntilDone(&result, &context, &elapsed); | |
201 EXPECT_EQ(2u, result); | |
202 EXPECT_EQ(8u, context); | |
203 EXPECT_GT(elapsed, (5 - 1) * test::EpsilonDeadline()); | |
204 EXPECT_LT(elapsed, (5 + 1) * test::EpsilonDeadline()); | |
205 } | |
206 } | |
207 | |
208 TEST(WaiterTest, TimeOut) { | |
209 test::Stopwatch stopwatch; | |
210 MojoDeadline elapsed; | |
211 | |
212 Waiter waiter; | |
213 uintptr_t context = 123; | |
214 | |
215 waiter.Init(); | |
216 stopwatch.Start(); | |
217 EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, waiter.Wait(0, &context)); | |
218 elapsed = stopwatch.Elapsed(); | |
219 EXPECT_LT(elapsed, test::EpsilonDeadline()); | |
220 EXPECT_EQ(123u, context); | |
221 | |
222 waiter.Init(); | |
223 stopwatch.Start(); | |
224 EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, | |
225 waiter.Wait(2 * test::EpsilonDeadline(), &context)); | |
226 elapsed = stopwatch.Elapsed(); | |
227 EXPECT_GT(elapsed, (2 - 1) * test::EpsilonDeadline()); | |
228 EXPECT_LT(elapsed, (2 + 1) * test::EpsilonDeadline()); | |
229 EXPECT_EQ(123u, context); | |
230 | |
231 waiter.Init(); | |
232 stopwatch.Start(); | |
233 EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, | |
234 waiter.Wait(5 * test::EpsilonDeadline(), &context)); | |
235 elapsed = stopwatch.Elapsed(); | |
236 EXPECT_GT(elapsed, (5 - 1) * test::EpsilonDeadline()); | |
237 EXPECT_LT(elapsed, (5 + 1) * test::EpsilonDeadline()); | |
238 EXPECT_EQ(123u, context); | |
239 } | |
240 | |
241 // The first |Awake()| should always win. | |
242 TEST(WaiterTest, MultipleAwakes) { | |
243 MojoResult result; | |
244 uintptr_t context; | |
245 MojoDeadline elapsed; | |
246 | |
247 { | |
248 WaitingThread thread(MOJO_DEADLINE_INDEFINITE); | |
249 thread.Start(); | |
250 thread.waiter()->Awake(MOJO_RESULT_OK, 1); | |
251 thread.waiter()->Awake(1, 2); | |
252 thread.WaitUntilDone(&result, &context, &elapsed); | |
253 EXPECT_EQ(MOJO_RESULT_OK, result); | |
254 EXPECT_EQ(1u, context); | |
255 EXPECT_LT(elapsed, test::EpsilonDeadline()); | |
256 } | |
257 | |
258 { | |
259 WaitingThread thread(MOJO_DEADLINE_INDEFINITE); | |
260 thread.waiter()->Awake(1, 3); | |
261 thread.Start(); | |
262 thread.waiter()->Awake(MOJO_RESULT_OK, 4); | |
263 thread.WaitUntilDone(&result, &context, &elapsed); | |
264 EXPECT_EQ(1u, result); | |
265 EXPECT_EQ(3u, context); | |
266 EXPECT_LT(elapsed, test::EpsilonDeadline()); | |
267 } | |
268 | |
269 { | |
270 WaitingThread thread(MOJO_DEADLINE_INDEFINITE); | |
271 thread.Start(); | |
272 thread.waiter()->Awake(10, 5); | |
273 test::Sleep(2 * test::EpsilonDeadline()); | |
274 thread.waiter()->Awake(20, 6); | |
275 thread.WaitUntilDone(&result, &context, &elapsed); | |
276 EXPECT_EQ(10u, result); | |
277 EXPECT_EQ(5u, context); | |
278 EXPECT_LT(elapsed, test::EpsilonDeadline()); | |
279 } | |
280 | |
281 { | |
282 WaitingThread thread(10 * test::EpsilonDeadline()); | |
283 thread.Start(); | |
284 test::Sleep(1 * test::EpsilonDeadline()); | |
285 thread.waiter()->Awake(MOJO_RESULT_FAILED_PRECONDITION, 7); | |
286 test::Sleep(2 * test::EpsilonDeadline()); | |
287 thread.waiter()->Awake(MOJO_RESULT_OK, 8); | |
288 thread.WaitUntilDone(&result, &context, &elapsed); | |
289 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result); | |
290 EXPECT_EQ(7u, context); | |
291 EXPECT_GT(elapsed, (1 - 1) * test::EpsilonDeadline()); | |
292 EXPECT_LT(elapsed, (1 + 1) * test::EpsilonDeadline()); | |
293 } | |
294 } | |
295 | |
296 } // namespace | |
297 } // namespace edk | |
298 } // namespace mojo | |
OLD | NEW |