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