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