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/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/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:
WaitingThread(MojoDeadline deadline)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
~WaitingThread()40 virtual ~WaitingThread() { Join(); }
41
WaitUntilDone(MojoResult * result,uint32_t * context,base::TimeDelta * elapsed)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
waiter()61 Waiter* waiter() { return &waiter_; }
62
63 private:
Run()64 virtual 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
TEST(WaiterTest,Basic)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
TEST(WaiterTest,TimeOut)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.
TEST(WaiterTest,MultipleAwakes)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
303