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.
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).
10 #include "mojo/edk/system/waiter.h"
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"
26 const int64_t kMicrosPerMs = 1000;
27 const int64_t kPollTimeMicros = 10 * kMicrosPerMs; // 10 ms.
29 class WaitingThread : public base::SimpleThread {
31 explicit WaitingThread(MojoDeadline deadline)
32 : base::SimpleThread("waiting_thread"),
35 result_(MOJO_RESULT_UNKNOWN),
36 context_(static_cast<uint32_t>(-1)) {
40 ~WaitingThread() override { Join(); }
42 void WaitUntilDone(MojoResult* result,
44 base::TimeDelta* elapsed) {
47 base::AutoLock locker(lock_);
56 base::PlatformThread::Sleep(
57 base::TimeDelta::FromMicroseconds(kPollTimeMicros));
61 Waiter* waiter() { return &waiter_; }
65 test::Stopwatch stopwatch;
67 uint32_t context = static_cast<uint32_t>(-1);
68 base::TimeDelta elapsed;
71 result = waiter_.Wait(deadline_, &context);
72 elapsed = stopwatch.Elapsed();
75 base::AutoLock locker(lock_);
83 const MojoDeadline deadline_;
84 Waiter waiter_; // Thread-safe.
86 base::Lock lock_; // Protects the following members.
90 base::TimeDelta elapsed_;
92 DISALLOW_COPY_AND_ASSIGN(WaitingThread);
95 TEST(WaiterTest, Basic) {
98 base::TimeDelta elapsed;
102 // Awake immediately after thread start.
104 WaitingThread thread(10 * test::EpsilonTimeout().InMicroseconds());
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());
113 // Awake before after thread start.
115 WaitingThread thread(10 * test::EpsilonTimeout().InMicroseconds());
116 thread.waiter()->Awake(MOJO_RESULT_CANCELLED, 2);
118 thread.WaitUntilDone(&result, &context, &elapsed);
119 EXPECT_EQ(MOJO_RESULT_CANCELLED, result);
120 EXPECT_EQ(2u, context);
121 EXPECT_LT(elapsed, test::EpsilonTimeout());
124 // Awake some time after thread start.
126 WaitingThread thread(10 * test::EpsilonTimeout().InMicroseconds());
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());
137 // Awake some longer time after thread start.
139 WaitingThread thread(10 * test::EpsilonTimeout().InMicroseconds());
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());
150 // Don't awake -- time out (on another thread).
152 WaitingThread thread(2 * test::EpsilonTimeout().InMicroseconds());
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());
161 // No (indefinite) deadline.
163 // Awake immediately after thread start.
165 WaitingThread thread(MOJO_DEADLINE_INDEFINITE);
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());
174 // Awake before after thread start.
176 WaitingThread thread(MOJO_DEADLINE_INDEFINITE);
177 thread.waiter()->Awake(MOJO_RESULT_CANCELLED, 6);
179 thread.WaitUntilDone(&result, &context, &elapsed);
180 EXPECT_EQ(MOJO_RESULT_CANCELLED, result);
181 EXPECT_EQ(6u, context);
182 EXPECT_LT(elapsed, test::EpsilonTimeout());
185 // Awake some time after thread start.
187 WaitingThread thread(MOJO_DEADLINE_INDEFINITE);
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());
198 // Awake some longer time after thread start.
200 WaitingThread thread(MOJO_DEADLINE_INDEFINITE);
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());
212 TEST(WaiterTest, TimeOut) {
213 test::Stopwatch stopwatch;
214 base::TimeDelta elapsed;
217 uint32_t context = 123;
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);
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);
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);
245 // The first |Awake()| should always win.
246 TEST(WaiterTest, MultipleAwakes) {
249 base::TimeDelta elapsed;
252 WaitingThread thread(MOJO_DEADLINE_INDEFINITE);
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());
263 WaitingThread thread(MOJO_DEADLINE_INDEFINITE);
264 thread.waiter()->Awake(1, 3);
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());
274 WaitingThread thread(MOJO_DEADLINE_INDEFINITE);
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());
286 WaitingThread thread(10 * test::EpsilonTimeout().InMicroseconds());
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());
301 } // namespace system