Home | History | Annotate | Download | only in system
      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:
     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 
     37   ~WaitingThread() override { Join(); }
     38 
     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 
     57   Waiter* waiter() { return &waiter_; }
     58 
     59  private:
     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 
     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 
    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.
    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