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/awakable_list.h"
     11 
     12 #include "mojo/edk/system/handle_signals_state.h"
     13 #include "mojo/edk/system/test_utils.h"
     14 #include "mojo/edk/system/waiter.h"
     15 #include "mojo/edk/system/waiter_test_utils.h"
     16 #include "testing/gtest/include/gtest/gtest.h"
     17 
     18 namespace mojo {
     19 namespace edk {
     20 namespace {
     21 
     22 TEST(AwakableListTest, BasicCancel) {
     23   MojoResult result;
     24   uintptr_t context;
     25 
     26   // Cancel immediately after thread start.
     27   {
     28     AwakableList awakable_list;
     29     test::SimpleWaiterThread thread(&result, &context);
     30     awakable_list.Add(thread.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 1);
     31     thread.Start();
     32     awakable_list.CancelAll();
     33     // Double-remove okay:
     34     awakable_list.Remove(thread.waiter());
     35   }  // Join |thread|.
     36   EXPECT_EQ(MOJO_RESULT_CANCELLED, result);
     37   EXPECT_EQ(1u, context);
     38 
     39   // Cancel before after thread start.
     40   {
     41     AwakableList awakable_list;
     42     test::SimpleWaiterThread thread(&result, &context);
     43     awakable_list.Add(thread.waiter(), MOJO_HANDLE_SIGNAL_WRITABLE, 2);
     44     awakable_list.CancelAll();
     45     thread.Start();
     46   }  // Join |thread|.
     47   EXPECT_EQ(MOJO_RESULT_CANCELLED, result);
     48   EXPECT_EQ(2u, context);
     49 
     50   // Cancel some time after thread start.
     51   {
     52     AwakableList awakable_list;
     53     test::SimpleWaiterThread thread(&result, &context);
     54     awakable_list.Add(thread.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 3);
     55     thread.Start();
     56     test::Sleep(2 * test::EpsilonDeadline());
     57     awakable_list.CancelAll();
     58   }  // Join |thread|.
     59   EXPECT_EQ(MOJO_RESULT_CANCELLED, result);
     60   EXPECT_EQ(3u, context);
     61 }
     62 
     63 TEST(AwakableListTest, BasicAwakeSatisfied) {
     64   MojoResult result;
     65   uintptr_t context;
     66 
     67   // Awake immediately after thread start.
     68   {
     69     AwakableList awakable_list;
     70     test::SimpleWaiterThread thread(&result, &context);
     71     awakable_list.Add(thread.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 1);
     72     thread.Start();
     73     awakable_list.AwakeForStateChange(HandleSignalsState(
     74         MOJO_HANDLE_SIGNAL_READABLE,
     75         MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE));
     76     awakable_list.Remove(thread.waiter());
     77   }  // Join |thread|.
     78   EXPECT_EQ(MOJO_RESULT_OK, result);
     79   EXPECT_EQ(1u, context);
     80 
     81   // Awake before after thread start.
     82   {
     83     AwakableList awakable_list;
     84     test::SimpleWaiterThread thread(&result, &context);
     85     awakable_list.Add(thread.waiter(), MOJO_HANDLE_SIGNAL_WRITABLE, 2);
     86     awakable_list.AwakeForStateChange(HandleSignalsState(
     87         MOJO_HANDLE_SIGNAL_WRITABLE,
     88         MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE));
     89     awakable_list.Remove(thread.waiter());
     90     // Double-remove okay:
     91     awakable_list.Remove(thread.waiter());
     92     thread.Start();
     93   }  // Join |thread|.
     94   EXPECT_EQ(MOJO_RESULT_OK, result);
     95   EXPECT_EQ(2u, context);
     96 
     97   // Awake some time after thread start.
     98   {
     99     AwakableList awakable_list;
    100     test::SimpleWaiterThread thread(&result, &context);
    101     awakable_list.Add(thread.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 3);
    102     thread.Start();
    103     test::Sleep(2 * test::EpsilonDeadline());
    104     awakable_list.AwakeForStateChange(HandleSignalsState(
    105         MOJO_HANDLE_SIGNAL_READABLE,
    106         MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE));
    107     awakable_list.Remove(thread.waiter());
    108   }  // Join |thread|.
    109   EXPECT_EQ(MOJO_RESULT_OK, result);
    110   EXPECT_EQ(3u, context);
    111 }
    112 
    113 TEST(AwakableListTest, BasicAwakeUnsatisfiable) {
    114   MojoResult result;
    115   uintptr_t context;
    116 
    117   // Awake (for unsatisfiability) immediately after thread start.
    118   {
    119     AwakableList awakable_list;
    120     test::SimpleWaiterThread thread(&result, &context);
    121     awakable_list.Add(thread.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 1);
    122     thread.Start();
    123     awakable_list.AwakeForStateChange(HandleSignalsState(
    124         MOJO_HANDLE_SIGNAL_NONE, MOJO_HANDLE_SIGNAL_WRITABLE));
    125     awakable_list.Remove(thread.waiter());
    126   }  // Join |thread|.
    127   EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result);
    128   EXPECT_EQ(1u, context);
    129 
    130   // Awake (for unsatisfiability) before after thread start.
    131   {
    132     AwakableList awakable_list;
    133     test::SimpleWaiterThread thread(&result, &context);
    134     awakable_list.Add(thread.waiter(), MOJO_HANDLE_SIGNAL_WRITABLE, 2);
    135     awakable_list.AwakeForStateChange(HandleSignalsState(
    136         MOJO_HANDLE_SIGNAL_READABLE, MOJO_HANDLE_SIGNAL_READABLE));
    137     awakable_list.Remove(thread.waiter());
    138     thread.Start();
    139   }  // Join |thread|.
    140   EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result);
    141   EXPECT_EQ(2u, context);
    142 
    143   // Awake (for unsatisfiability) some time after thread start.
    144   {
    145     AwakableList awakable_list;
    146     test::SimpleWaiterThread thread(&result, &context);
    147     awakable_list.Add(thread.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 3);
    148     thread.Start();
    149     test::Sleep(2 * test::EpsilonDeadline());
    150     awakable_list.AwakeForStateChange(HandleSignalsState(
    151         MOJO_HANDLE_SIGNAL_NONE, MOJO_HANDLE_SIGNAL_WRITABLE));
    152     awakable_list.Remove(thread.waiter());
    153     // Double-remove okay:
    154     awakable_list.Remove(thread.waiter());
    155   }  // Join |thread|.
    156   EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result);
    157   EXPECT_EQ(3u, context);
    158 }
    159 
    160 TEST(AwakableListTest, MultipleAwakables) {
    161   MojoResult result1;
    162   MojoResult result2;
    163   MojoResult result3;
    164   MojoResult result4;
    165   uintptr_t context1;
    166   uintptr_t context2;
    167   uintptr_t context3;
    168   uintptr_t context4;
    169 
    170   // Cancel two awakables.
    171   {
    172     AwakableList awakable_list;
    173     test::SimpleWaiterThread thread1(&result1, &context1);
    174     awakable_list.Add(thread1.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 1);
    175     thread1.Start();
    176     test::SimpleWaiterThread thread2(&result2, &context2);
    177     awakable_list.Add(thread2.waiter(), MOJO_HANDLE_SIGNAL_WRITABLE, 2);
    178     thread2.Start();
    179     test::Sleep(2 * test::EpsilonDeadline());
    180     awakable_list.CancelAll();
    181   }  // Join threads.
    182   EXPECT_EQ(MOJO_RESULT_CANCELLED, result1);
    183   EXPECT_EQ(1u, context1);
    184   EXPECT_EQ(MOJO_RESULT_CANCELLED, result2);
    185   EXPECT_EQ(2u, context2);
    186 
    187   // Awake one awakable, cancel other.
    188   {
    189     AwakableList awakable_list;
    190     test::SimpleWaiterThread thread1(&result1, &context1);
    191     awakable_list.Add(thread1.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 3);
    192     thread1.Start();
    193     test::SimpleWaiterThread thread2(&result2, &context2);
    194     awakable_list.Add(thread2.waiter(), MOJO_HANDLE_SIGNAL_WRITABLE, 4);
    195     thread2.Start();
    196     test::Sleep(2 * test::EpsilonDeadline());
    197     awakable_list.AwakeForStateChange(HandleSignalsState(
    198         MOJO_HANDLE_SIGNAL_READABLE,
    199         MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE));
    200     awakable_list.Remove(thread1.waiter());
    201     awakable_list.CancelAll();
    202   }  // Join threads.
    203   EXPECT_EQ(MOJO_RESULT_OK, result1);
    204   EXPECT_EQ(3u, context1);
    205   EXPECT_EQ(MOJO_RESULT_CANCELLED, result2);
    206   EXPECT_EQ(4u, context2);
    207 
    208   // Cancel one awakable, awake other for unsatisfiability.
    209   {
    210     AwakableList awakable_list;
    211     test::SimpleWaiterThread thread1(&result1, &context1);
    212     awakable_list.Add(thread1.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 5);
    213     thread1.Start();
    214     test::SimpleWaiterThread thread2(&result2, &context2);
    215     awakable_list.Add(thread2.waiter(), MOJO_HANDLE_SIGNAL_WRITABLE, 6);
    216     thread2.Start();
    217     test::Sleep(2 * test::EpsilonDeadline());
    218     awakable_list.AwakeForStateChange(HandleSignalsState(
    219         MOJO_HANDLE_SIGNAL_NONE, MOJO_HANDLE_SIGNAL_READABLE));
    220     awakable_list.Remove(thread2.waiter());
    221     awakable_list.CancelAll();
    222   }  // Join threads.
    223   EXPECT_EQ(MOJO_RESULT_CANCELLED, result1);
    224   EXPECT_EQ(5u, context1);
    225   EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result2);
    226   EXPECT_EQ(6u, context2);
    227 
    228   // Cancel one awakable, awake other for unsatisfiability.
    229   {
    230     AwakableList awakable_list;
    231     test::SimpleWaiterThread thread1(&result1, &context1);
    232     awakable_list.Add(thread1.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 7);
    233     thread1.Start();
    234 
    235     test::Sleep(1 * test::EpsilonDeadline());
    236 
    237     // Should do nothing.
    238     awakable_list.AwakeForStateChange(HandleSignalsState(
    239         MOJO_HANDLE_SIGNAL_NONE,
    240         MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE));
    241 
    242     test::SimpleWaiterThread thread2(&result2, &context2);
    243     awakable_list.Add(thread2.waiter(), MOJO_HANDLE_SIGNAL_WRITABLE, 8);
    244     thread2.Start();
    245 
    246     test::Sleep(1 * test::EpsilonDeadline());
    247 
    248     // Awake #1.
    249     awakable_list.AwakeForStateChange(HandleSignalsState(
    250         MOJO_HANDLE_SIGNAL_READABLE,
    251         MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE));
    252     awakable_list.Remove(thread1.waiter());
    253 
    254     test::Sleep(1 * test::EpsilonDeadline());
    255 
    256     test::SimpleWaiterThread thread3(&result3, &context3);
    257     awakable_list.Add(thread3.waiter(), MOJO_HANDLE_SIGNAL_WRITABLE, 9);
    258     thread3.Start();
    259 
    260     test::SimpleWaiterThread thread4(&result4, &context4);
    261     awakable_list.Add(thread4.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 10);
    262     thread4.Start();
    263 
    264     test::Sleep(1 * test::EpsilonDeadline());
    265 
    266     // Awake #2 and #3 for unsatisfiability.
    267     awakable_list.AwakeForStateChange(HandleSignalsState(
    268         MOJO_HANDLE_SIGNAL_NONE, MOJO_HANDLE_SIGNAL_READABLE));
    269     awakable_list.Remove(thread2.waiter());
    270     awakable_list.Remove(thread3.waiter());
    271 
    272     // Cancel #4.
    273     awakable_list.CancelAll();
    274   }  // Join threads.
    275   EXPECT_EQ(MOJO_RESULT_OK, result1);
    276   EXPECT_EQ(7u, context1);
    277   EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result2);
    278   EXPECT_EQ(8u, context2);
    279   EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result3);
    280   EXPECT_EQ(9u, context3);
    281   EXPECT_EQ(MOJO_RESULT_CANCELLED, result4);
    282   EXPECT_EQ(10u, context4);
    283 }
    284 
    285 class KeepAwakable : public Awakable {
    286  public:
    287   KeepAwakable() : awake_count(0) {}
    288 
    289   bool Awake(MojoResult result, uintptr_t context) override {
    290     awake_count++;
    291     return true;
    292   }
    293 
    294   int awake_count;
    295 
    296   DISALLOW_COPY_AND_ASSIGN(KeepAwakable);
    297 };
    298 
    299 class RemoveAwakable : public Awakable {
    300  public:
    301   RemoveAwakable() : awake_count(0) {}
    302 
    303   bool Awake(MojoResult result, uintptr_t context) override {
    304     awake_count++;
    305     return false;
    306   }
    307 
    308   int awake_count;
    309 
    310   DISALLOW_COPY_AND_ASSIGN(RemoveAwakable);
    311 };
    312 
    313 TEST(AwakableListTest, KeepAwakablesReturningTrue) {
    314   KeepAwakable keep0;
    315   KeepAwakable keep1;
    316   RemoveAwakable remove0;
    317   RemoveAwakable remove1;
    318   RemoveAwakable remove2;
    319 
    320   HandleSignalsState hss(MOJO_HANDLE_SIGNAL_WRITABLE,
    321                          MOJO_HANDLE_SIGNAL_WRITABLE);
    322 
    323   AwakableList remove_all;
    324   remove_all.Add(&remove0, MOJO_HANDLE_SIGNAL_WRITABLE, 0);
    325   remove_all.Add(&remove1, MOJO_HANDLE_SIGNAL_WRITABLE, 0);
    326 
    327   remove_all.AwakeForStateChange(hss);
    328   EXPECT_EQ(remove0.awake_count, 1);
    329   EXPECT_EQ(remove1.awake_count, 1);
    330 
    331   remove_all.AwakeForStateChange(hss);
    332   EXPECT_EQ(remove0.awake_count, 1);
    333   EXPECT_EQ(remove1.awake_count, 1);
    334 
    335   AwakableList remove_first;
    336   remove_first.Add(&remove2, MOJO_HANDLE_SIGNAL_WRITABLE, 0);
    337   remove_first.Add(&keep0, MOJO_HANDLE_SIGNAL_WRITABLE, 0);
    338   remove_first.Add(&keep1, MOJO_HANDLE_SIGNAL_WRITABLE, 0);
    339 
    340   remove_first.AwakeForStateChange(hss);
    341   EXPECT_EQ(keep0.awake_count, 1);
    342   EXPECT_EQ(keep1.awake_count, 1);
    343   EXPECT_EQ(remove2.awake_count, 1);
    344 
    345   remove_first.AwakeForStateChange(hss);
    346   EXPECT_EQ(keep0.awake_count, 2);
    347   EXPECT_EQ(keep1.awake_count, 2);
    348   EXPECT_EQ(remove2.awake_count, 1);
    349 
    350   remove_first.Remove(&keep0);
    351   remove_first.Remove(&keep1);
    352 }
    353 
    354 }  // namespace
    355 }  // namespace edk
    356 }  // namespace mojo
    357