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