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