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. |kEpsilonMicros| may be increased to increase
7 // tolerance and reduce observed flakiness.
8
9 #include "mojo/system/simple_dispatcher.h"
10
11 #include "base/basictypes.h"
12 #include "base/logging.h"
13 #include "base/memory/ref_counted.h"
14 #include "base/memory/scoped_vector.h"
15 #include "base/synchronization/lock.h"
16 #include "base/threading/platform_thread.h" // For |Sleep()|.
17 #include "base/time/time.h"
18 #include "mojo/system/test_utils.h"
19 #include "mojo/system/waiter.h"
20 #include "mojo/system/waiter_test_utils.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22
23 namespace mojo {
24 namespace system {
25 namespace {
26
27 const int64_t kMicrosPerMs = 1000;
28 const int64_t kEpsilonMicros = 15 * kMicrosPerMs; // 15 ms.
29
30 class MockSimpleDispatcher : public SimpleDispatcher {
31 public:
MockSimpleDispatcher()32 MockSimpleDispatcher()
33 : satisfied_flags_(MOJO_WAIT_FLAG_NONE),
34 satisfiable_flags_(MOJO_WAIT_FLAG_READABLE | MOJO_WAIT_FLAG_WRITABLE) {}
35
SetSatisfiedFlags(MojoWaitFlags new_satisfied_flags)36 void SetSatisfiedFlags(MojoWaitFlags new_satisfied_flags) {
37 base::AutoLock locker(lock());
38
39 // Any new flags that are set should be satisfiable.
40 CHECK_EQ(new_satisfied_flags & ~satisfied_flags_,
41 new_satisfied_flags & ~satisfied_flags_ & satisfiable_flags_);
42
43 if (new_satisfied_flags == satisfied_flags_)
44 return;
45
46 satisfied_flags_ = new_satisfied_flags;
47 StateChangedNoLock();
48 }
49
SetSatisfiableFlags(MojoWaitFlags new_satisfiable_flags)50 void SetSatisfiableFlags(MojoWaitFlags new_satisfiable_flags) {
51 base::AutoLock locker(lock());
52
53 if (new_satisfiable_flags == satisfiable_flags_)
54 return;
55
56 satisfiable_flags_ = new_satisfiable_flags;
57 StateChangedNoLock();
58 }
59
60 private:
61 friend class base::RefCountedThreadSafe<MockSimpleDispatcher>;
~MockSimpleDispatcher()62 virtual ~MockSimpleDispatcher() {}
63
64 virtual scoped_refptr<Dispatcher>
CreateEquivalentDispatcherAndCloseImplNoLock()65 CreateEquivalentDispatcherAndCloseImplNoLock() OVERRIDE {
66 scoped_refptr<MockSimpleDispatcher> rv(new MockSimpleDispatcher());
67 rv->satisfied_flags_ = satisfied_flags_;
68 rv->satisfiable_flags_ = satisfiable_flags_;
69 return scoped_refptr<Dispatcher>(rv.get());
70 }
71
72 // |SimpleDispatcher| implementation:
SatisfiedFlagsNoLock() const73 virtual MojoWaitFlags SatisfiedFlagsNoLock() const OVERRIDE {
74 lock().AssertAcquired();
75 return satisfied_flags_;
76 }
77
SatisfiableFlagsNoLock() const78 virtual MojoWaitFlags SatisfiableFlagsNoLock() const OVERRIDE {
79 lock().AssertAcquired();
80 return satisfiable_flags_;
81 }
82
83 // Protected by |lock()|:
84 MojoWaitFlags satisfied_flags_;
85 MojoWaitFlags satisfiable_flags_;
86
87 DISALLOW_COPY_AND_ASSIGN(MockSimpleDispatcher);
88 };
89
TEST(SimpleDispatcherTest,Basic)90 TEST(SimpleDispatcherTest, Basic) {
91 test::Stopwatch stopwatch;
92 int64_t elapsed_micros;
93
94 scoped_refptr<MockSimpleDispatcher> d(new MockSimpleDispatcher());
95 Waiter w;
96
97 // Try adding a readable waiter when already readable.
98 w.Init();
99 d->SetSatisfiedFlags(MOJO_WAIT_FLAG_READABLE);
100 EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS,
101 d->AddWaiter(&w, MOJO_WAIT_FLAG_READABLE, 0));
102 // Shouldn't need to remove the waiter (it was not added).
103
104 // Wait (forever) for writable when already writable.
105 w.Init();
106 d->SetSatisfiedFlags(MOJO_WAIT_FLAG_READABLE);
107 EXPECT_EQ(MOJO_RESULT_OK, d->AddWaiter(&w, MOJO_WAIT_FLAG_WRITABLE, 1));
108 d->SetSatisfiedFlags(MOJO_WAIT_FLAG_WRITABLE);
109 stopwatch.Start();
110 EXPECT_EQ(1, w.Wait(MOJO_DEADLINE_INDEFINITE));
111 elapsed_micros = stopwatch.Elapsed();
112 EXPECT_LT(elapsed_micros, kEpsilonMicros);
113 d->RemoveWaiter(&w);
114
115 // Wait for zero time for writable when already writable.
116 w.Init();
117 d->SetSatisfiedFlags(MOJO_WAIT_FLAG_READABLE);
118 EXPECT_EQ(MOJO_RESULT_OK, d->AddWaiter(&w, MOJO_WAIT_FLAG_WRITABLE, 2));
119 d->SetSatisfiedFlags(MOJO_WAIT_FLAG_WRITABLE);
120 stopwatch.Start();
121 EXPECT_EQ(2, w.Wait(0));
122 elapsed_micros = stopwatch.Elapsed();
123 EXPECT_LT(elapsed_micros, kEpsilonMicros);
124 d->RemoveWaiter(&w);
125
126 // Wait for non-zero, finite time for writable when already writable.
127 w.Init();
128 d->SetSatisfiedFlags(MOJO_WAIT_FLAG_READABLE);
129 EXPECT_EQ(MOJO_RESULT_OK, d->AddWaiter(&w, MOJO_WAIT_FLAG_WRITABLE, 3));
130 d->SetSatisfiedFlags(MOJO_WAIT_FLAG_WRITABLE);
131 stopwatch.Start();
132 EXPECT_EQ(3, w.Wait(2 * kEpsilonMicros));
133 elapsed_micros = stopwatch.Elapsed();
134 EXPECT_LT(elapsed_micros, kEpsilonMicros);
135 d->RemoveWaiter(&w);
136
137 // Wait for zero time for writable when not writable (will time out).
138 w.Init();
139 d->SetSatisfiedFlags(MOJO_WAIT_FLAG_READABLE);
140 EXPECT_EQ(MOJO_RESULT_OK, d->AddWaiter(&w, MOJO_WAIT_FLAG_WRITABLE, 4));
141 stopwatch.Start();
142 EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, w.Wait(0));
143 elapsed_micros = stopwatch.Elapsed();
144 EXPECT_LT(elapsed_micros, kEpsilonMicros);
145 d->RemoveWaiter(&w);
146
147 // Wait for non-zero, finite time for writable when not writable (will time
148 // out).
149 w.Init();
150 d->SetSatisfiedFlags(MOJO_WAIT_FLAG_READABLE);
151 EXPECT_EQ(MOJO_RESULT_OK, d->AddWaiter(&w, MOJO_WAIT_FLAG_WRITABLE, 4));
152 stopwatch.Start();
153 EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, w.Wait(2 * kEpsilonMicros));
154 elapsed_micros = stopwatch.Elapsed();
155 EXPECT_GT(elapsed_micros, (2-1) * kEpsilonMicros);
156 EXPECT_LT(elapsed_micros, (2+1) * kEpsilonMicros);
157 d->RemoveWaiter(&w);
158
159 EXPECT_EQ(MOJO_RESULT_OK, d->Close());
160 }
161
TEST(SimpleDispatcherTest,BasicUnsatisfiable)162 TEST(SimpleDispatcherTest, BasicUnsatisfiable) {
163 test::Stopwatch stopwatch;
164 int64_t elapsed_micros;
165
166 scoped_refptr<MockSimpleDispatcher> d(new MockSimpleDispatcher());
167 Waiter w;
168
169 // Try adding a writable waiter when it can never be writable.
170 w.Init();
171 d->SetSatisfiableFlags(MOJO_WAIT_FLAG_READABLE);
172 d->SetSatisfiedFlags(0);
173 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
174 d->AddWaiter(&w, MOJO_WAIT_FLAG_WRITABLE, 5));
175 // Shouldn't need to remove the waiter (it was not added).
176
177 // Wait (forever) for writable and then it becomes never writable.
178 w.Init();
179 d->SetSatisfiableFlags(MOJO_WAIT_FLAG_READABLE | MOJO_WAIT_FLAG_WRITABLE);
180 EXPECT_EQ(MOJO_RESULT_OK, d->AddWaiter(&w, MOJO_WAIT_FLAG_WRITABLE, 6));
181 d->SetSatisfiableFlags(MOJO_WAIT_FLAG_READABLE);
182 stopwatch.Start();
183 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, w.Wait(MOJO_DEADLINE_INDEFINITE));
184 elapsed_micros = stopwatch.Elapsed();
185 EXPECT_LT(elapsed_micros, kEpsilonMicros);
186 d->RemoveWaiter(&w);
187
188 // Wait for zero time for writable and then it becomes never writable.
189 w.Init();
190 d->SetSatisfiableFlags(MOJO_WAIT_FLAG_READABLE | MOJO_WAIT_FLAG_WRITABLE);
191 EXPECT_EQ(MOJO_RESULT_OK, d->AddWaiter(&w, MOJO_WAIT_FLAG_WRITABLE, 6));
192 d->SetSatisfiableFlags(MOJO_WAIT_FLAG_READABLE);
193 stopwatch.Start();
194 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, w.Wait(0));
195 elapsed_micros = stopwatch.Elapsed();
196 EXPECT_LT(elapsed_micros, kEpsilonMicros);
197 d->RemoveWaiter(&w);
198
199 // Wait for non-zero, finite time for writable and then it becomes never
200 // writable.
201 w.Init();
202 d->SetSatisfiableFlags(MOJO_WAIT_FLAG_READABLE | MOJO_WAIT_FLAG_WRITABLE);
203 EXPECT_EQ(MOJO_RESULT_OK, d->AddWaiter(&w, MOJO_WAIT_FLAG_WRITABLE, 7));
204 d->SetSatisfiableFlags(MOJO_WAIT_FLAG_READABLE);
205 stopwatch.Start();
206 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, w.Wait(2 * kEpsilonMicros));
207 elapsed_micros = stopwatch.Elapsed();
208 EXPECT_LT(elapsed_micros, kEpsilonMicros);
209 d->RemoveWaiter(&w);
210
211 EXPECT_EQ(MOJO_RESULT_OK, d->Close());
212 }
213
TEST(SimpleDispatcherTest,BasicClosed)214 TEST(SimpleDispatcherTest, BasicClosed) {
215 test::Stopwatch stopwatch;
216 int64_t elapsed_micros;
217
218 scoped_refptr<MockSimpleDispatcher> d;
219 Waiter w;
220
221 // Try adding a writable waiter when the dispatcher has been closed.
222 d = new MockSimpleDispatcher();
223 w.Init();
224 EXPECT_EQ(MOJO_RESULT_OK, d->Close());
225 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
226 d->AddWaiter(&w, MOJO_WAIT_FLAG_WRITABLE, 8));
227 // Shouldn't need to remove the waiter (it was not added).
228
229 // Wait (forever) for writable and then the dispatcher is closed.
230 d = new MockSimpleDispatcher();
231 w.Init();
232 EXPECT_EQ(MOJO_RESULT_OK, d->AddWaiter(&w, MOJO_WAIT_FLAG_WRITABLE, 9));
233 EXPECT_EQ(MOJO_RESULT_OK, d->Close());
234 stopwatch.Start();
235 EXPECT_EQ(MOJO_RESULT_CANCELLED, w.Wait(MOJO_DEADLINE_INDEFINITE));
236 elapsed_micros = stopwatch.Elapsed();
237 EXPECT_LT(elapsed_micros, kEpsilonMicros);
238 // Don't need to remove waiters from closed dispatchers.
239
240 // Wait for zero time for writable and then the dispatcher is closed.
241 d = new MockSimpleDispatcher();
242 w.Init();
243 EXPECT_EQ(MOJO_RESULT_OK, d->AddWaiter(&w, MOJO_WAIT_FLAG_WRITABLE, 10));
244 EXPECT_EQ(MOJO_RESULT_OK, d->Close());
245 stopwatch.Start();
246 EXPECT_EQ(MOJO_RESULT_CANCELLED, w.Wait(0));
247 elapsed_micros = stopwatch.Elapsed();
248 EXPECT_LT(elapsed_micros, kEpsilonMicros);
249 // Don't need to remove waiters from closed dispatchers.
250
251 // Wait for non-zero, finite time for writable and then the dispatcher is
252 // closed.
253 d = new MockSimpleDispatcher();
254 w.Init();
255 EXPECT_EQ(MOJO_RESULT_OK, d->AddWaiter(&w, MOJO_WAIT_FLAG_WRITABLE, 11));
256 EXPECT_EQ(MOJO_RESULT_OK, d->Close());
257 stopwatch.Start();
258 EXPECT_EQ(MOJO_RESULT_CANCELLED, w.Wait(2 * kEpsilonMicros));
259 elapsed_micros = stopwatch.Elapsed();
260 EXPECT_LT(elapsed_micros, kEpsilonMicros);
261 // Don't need to remove waiters from closed dispatchers.
262 }
263
TEST(SimpleDispatcherTest,BasicThreaded)264 TEST(SimpleDispatcherTest, BasicThreaded) {
265 test::Stopwatch stopwatch;
266 bool did_wait;
267 MojoResult result;
268 int64_t elapsed_micros;
269
270 // Wait for readable (already readable).
271 {
272 scoped_refptr<MockSimpleDispatcher> d(new MockSimpleDispatcher());
273 {
274 d->SetSatisfiedFlags(MOJO_WAIT_FLAG_READABLE);
275 test::WaiterThread thread(d,
276 MOJO_WAIT_FLAG_READABLE,
277 MOJO_DEADLINE_INDEFINITE,
278 0,
279 &did_wait, &result);
280 stopwatch.Start();
281 thread.Start();
282 } // Joins the thread.
283 // If we closed earlier, then probably we'd get a |MOJO_RESULT_CANCELLED|.
284 EXPECT_EQ(MOJO_RESULT_OK, d->Close());
285 }
286 elapsed_micros = stopwatch.Elapsed();
287 EXPECT_FALSE(did_wait);
288 EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, result);
289 EXPECT_LT(elapsed_micros, kEpsilonMicros);
290
291 // Wait for readable and becomes readable after some time.
292 {
293 scoped_refptr<MockSimpleDispatcher> d(new MockSimpleDispatcher());
294 test::WaiterThread thread(d,
295 MOJO_WAIT_FLAG_READABLE,
296 MOJO_DEADLINE_INDEFINITE,
297 1,
298 &did_wait, &result);
299 stopwatch.Start();
300 thread.Start();
301 base::PlatformThread::Sleep(
302 base::TimeDelta::FromMicroseconds(2 * kEpsilonMicros));
303 d->SetSatisfiedFlags(MOJO_WAIT_FLAG_READABLE);
304 EXPECT_EQ(MOJO_RESULT_OK, d->Close());
305 } // Joins the thread.
306 elapsed_micros = stopwatch.Elapsed();
307 EXPECT_TRUE(did_wait);
308 EXPECT_EQ(1, result);
309 EXPECT_GT(elapsed_micros, (2-1) * kEpsilonMicros);
310 EXPECT_LT(elapsed_micros, (2+1) * kEpsilonMicros);
311
312 // Wait for readable and becomes never-readable after some time.
313 {
314 scoped_refptr<MockSimpleDispatcher> d(new MockSimpleDispatcher());
315 test::WaiterThread thread(d,
316 MOJO_WAIT_FLAG_READABLE,
317 MOJO_DEADLINE_INDEFINITE,
318 2,
319 &did_wait, &result);
320 stopwatch.Start();
321 thread.Start();
322 base::PlatformThread::Sleep(
323 base::TimeDelta::FromMicroseconds(2 * kEpsilonMicros));
324 d->SetSatisfiableFlags(MOJO_WAIT_FLAG_NONE);
325 EXPECT_EQ(MOJO_RESULT_OK, d->Close());
326 } // Joins the thread.
327 elapsed_micros = stopwatch.Elapsed();
328 EXPECT_TRUE(did_wait);
329 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result);
330 EXPECT_GT(elapsed_micros, (2-1) * kEpsilonMicros);
331 EXPECT_LT(elapsed_micros, (2+1) * kEpsilonMicros);
332
333 // Wait for readable and dispatcher gets closed.
334 {
335 scoped_refptr<MockSimpleDispatcher> d(new MockSimpleDispatcher());
336 test::WaiterThread thread(d,
337 MOJO_WAIT_FLAG_READABLE,
338 MOJO_DEADLINE_INDEFINITE,
339 3,
340 &did_wait, &result);
341 stopwatch.Start();
342 thread.Start();
343 base::PlatformThread::Sleep(
344 base::TimeDelta::FromMicroseconds(2 * kEpsilonMicros));
345 EXPECT_EQ(MOJO_RESULT_OK, d->Close());
346 } // Joins the thread.
347 elapsed_micros = stopwatch.Elapsed();
348 EXPECT_TRUE(did_wait);
349 EXPECT_EQ(MOJO_RESULT_CANCELLED, result);
350 EXPECT_GT(elapsed_micros, (2-1) * kEpsilonMicros);
351 EXPECT_LT(elapsed_micros, (2+1) * kEpsilonMicros);
352
353 // Wait for readable and times out.
354 {
355 scoped_refptr<MockSimpleDispatcher> d(new MockSimpleDispatcher());
356 {
357 test::WaiterThread thread(d,
358 MOJO_WAIT_FLAG_READABLE,
359 2 * kEpsilonMicros,
360 4,
361 &did_wait, &result);
362 stopwatch.Start();
363 thread.Start();
364 base::PlatformThread::Sleep(
365 base::TimeDelta::FromMicroseconds(1 * kEpsilonMicros));
366 // Not what we're waiting for.
367 d->SetSatisfiedFlags(MOJO_WAIT_FLAG_WRITABLE);
368 } // Joins the thread (after its wait times out).
369 // If we closed earlier, then probably we'd get a |MOJO_RESULT_CANCELLED|.
370 EXPECT_EQ(MOJO_RESULT_OK, d->Close());
371 }
372 elapsed_micros = stopwatch.Elapsed();
373 EXPECT_TRUE(did_wait);
374 EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, result);
375 EXPECT_GT(elapsed_micros, (2-1) * kEpsilonMicros);
376 EXPECT_LT(elapsed_micros, (2+1) * kEpsilonMicros);
377 }
378
TEST(SimpleDispatcherTest,MultipleWaiters)379 TEST(SimpleDispatcherTest, MultipleWaiters) {
380 static const size_t kNumWaiters = 20;
381
382 bool did_wait[kNumWaiters];
383 MojoResult result[kNumWaiters];
384
385 // All wait for readable and becomes readable after some time.
386 {
387 scoped_refptr<MockSimpleDispatcher> d(new MockSimpleDispatcher());
388 ScopedVector<test::WaiterThread> threads;
389 for (size_t i = 0; i < kNumWaiters; i++) {
390 threads.push_back(new test::WaiterThread(d,
391 MOJO_WAIT_FLAG_READABLE,
392 MOJO_DEADLINE_INDEFINITE,
393 static_cast<MojoResult>(i),
394 &did_wait[i], &result[i]));
395 threads.back()->Start();
396 }
397 base::PlatformThread::Sleep(
398 base::TimeDelta::FromMicroseconds(2 * kEpsilonMicros));
399 d->SetSatisfiedFlags(MOJO_WAIT_FLAG_READABLE);
400 EXPECT_EQ(MOJO_RESULT_OK, d->Close());
401 } // Joins the threads.
402 for (size_t i = 0; i < kNumWaiters; i++) {
403 EXPECT_TRUE(did_wait[i]);
404 EXPECT_EQ(static_cast<MojoResult>(i), result[i]);
405 }
406
407 // Some wait for readable, some for writable, and becomes readable after some
408 // time.
409 {
410 scoped_refptr<MockSimpleDispatcher> d(new MockSimpleDispatcher());
411 ScopedVector<test::WaiterThread> threads;
412 for (size_t i = 0; i < kNumWaiters / 2; i++) {
413 threads.push_back(new test::WaiterThread(d,
414 MOJO_WAIT_FLAG_READABLE,
415 MOJO_DEADLINE_INDEFINITE,
416 static_cast<MojoResult>(i),
417 &did_wait[i], &result[i]));
418 threads.back()->Start();
419 }
420 for (size_t i = kNumWaiters / 2; i < kNumWaiters; i++) {
421 threads.push_back(new test::WaiterThread(d,
422 MOJO_WAIT_FLAG_WRITABLE,
423 MOJO_DEADLINE_INDEFINITE,
424 static_cast<MojoResult>(i),
425 &did_wait[i], &result[i]));
426 threads.back()->Start();
427 }
428 base::PlatformThread::Sleep(
429 base::TimeDelta::FromMicroseconds(2 * kEpsilonMicros));
430 d->SetSatisfiedFlags(MOJO_WAIT_FLAG_READABLE);
431 // This will wake up the ones waiting to write.
432 EXPECT_EQ(MOJO_RESULT_OK, d->Close());
433 } // Joins the threads.
434 for (size_t i = 0; i < kNumWaiters / 2; i++) {
435 EXPECT_TRUE(did_wait[i]);
436 EXPECT_EQ(static_cast<MojoResult>(i), result[i]);
437 }
438 for (size_t i = kNumWaiters / 2; i < kNumWaiters; i++) {
439 EXPECT_TRUE(did_wait[i]);
440 EXPECT_EQ(MOJO_RESULT_CANCELLED, result[i]);
441 }
442
443 // Some wait for readable, some for writable, and becomes readable and
444 // never-writable after some time.
445 {
446 scoped_refptr<MockSimpleDispatcher> d(new MockSimpleDispatcher());
447 ScopedVector<test::WaiterThread> threads;
448 for (size_t i = 0; i < kNumWaiters / 2; i++) {
449 threads.push_back(new test::WaiterThread(d,
450 MOJO_WAIT_FLAG_READABLE,
451 MOJO_DEADLINE_INDEFINITE,
452 static_cast<MojoResult>(i),
453 &did_wait[i], &result[i]));
454 threads.back()->Start();
455 }
456 for (size_t i = kNumWaiters / 2; i < kNumWaiters; i++) {
457 threads.push_back(new test::WaiterThread(d,
458 MOJO_WAIT_FLAG_WRITABLE,
459 MOJO_DEADLINE_INDEFINITE,
460 static_cast<MojoResult>(i),
461 &did_wait[i], &result[i]));
462 threads.back()->Start();
463 }
464 base::PlatformThread::Sleep(
465 base::TimeDelta::FromMicroseconds(1 * kEpsilonMicros));
466 d->SetSatisfiableFlags(MOJO_WAIT_FLAG_READABLE);
467 base::PlatformThread::Sleep(
468 base::TimeDelta::FromMicroseconds(1 * kEpsilonMicros));
469 d->SetSatisfiedFlags(MOJO_WAIT_FLAG_READABLE);
470 EXPECT_EQ(MOJO_RESULT_OK, d->Close());
471 } // Joins the threads.
472 for (size_t i = 0; i < kNumWaiters / 2; i++) {
473 EXPECT_TRUE(did_wait[i]);
474 EXPECT_EQ(static_cast<MojoResult>(i), result[i]);
475 }
476 for (size_t i = kNumWaiters / 2; i < kNumWaiters; i++) {
477 EXPECT_TRUE(did_wait[i]);
478 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result[i]);
479 }
480
481 // Some wait for readable, some for writable, and becomes readable after some
482 // time.
483 {
484 scoped_refptr<MockSimpleDispatcher> d(new MockSimpleDispatcher());
485 ScopedVector<test::WaiterThread> threads;
486 for (size_t i = 0; i < kNumWaiters / 2; i++) {
487 threads.push_back(new test::WaiterThread(d,
488 MOJO_WAIT_FLAG_READABLE,
489 3 * kEpsilonMicros,
490 static_cast<MojoResult>(i),
491 &did_wait[i], &result[i]));
492 threads.back()->Start();
493 }
494 for (size_t i = kNumWaiters / 2; i < kNumWaiters; i++) {
495 threads.push_back(new test::WaiterThread(d,
496 MOJO_WAIT_FLAG_WRITABLE,
497 1 * kEpsilonMicros,
498 static_cast<MojoResult>(i),
499 &did_wait[i], &result[i]));
500 threads.back()->Start();
501 }
502 base::PlatformThread::Sleep(
503 base::TimeDelta::FromMicroseconds(2 * kEpsilonMicros));
504 d->SetSatisfiedFlags(MOJO_WAIT_FLAG_READABLE);
505 // All those waiting for writable should have timed out.
506 EXPECT_EQ(MOJO_RESULT_OK, d->Close());
507 } // Joins the threads.
508 for (size_t i = 0; i < kNumWaiters / 2; i++) {
509 EXPECT_TRUE(did_wait[i]);
510 EXPECT_EQ(static_cast<MojoResult>(i), result[i]);
511 }
512 for (size_t i = kNumWaiters / 2; i < kNumWaiters; i++) {
513 EXPECT_TRUE(did_wait[i]);
514 EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, result[i]);
515 }
516 }
517
518 // TODO(vtl): Stress test?
519
520 } // namespace
521 } // namespace system
522 } // namespace mojo
523