• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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