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