• 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. |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