Home | History | Annotate | Download | only in system
      1 // Copyright 2015 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 #include "mojo/edk/system/wait_set_dispatcher.h"
      6 
      7 #include <stddef.h>
      8 #include <stdint.h>
      9 
     10 #include <algorithm>
     11 
     12 #include "base/macros.h"
     13 #include "base/memory/ref_counted.h"
     14 #include "mojo/edk/embedder/embedder_internal.h"
     15 #include "mojo/edk/system/core.h"
     16 #include "mojo/edk/system/message_for_transit.h"
     17 #include "mojo/edk/system/message_pipe_dispatcher.h"
     18 #include "mojo/edk/system/request_context.h"
     19 #include "mojo/edk/system/test_utils.h"
     20 #include "mojo/edk/system/waiter.h"
     21 #include "testing/gtest/include/gtest/gtest.h"
     22 
     23 namespace mojo {
     24 namespace edk {
     25 namespace {
     26 
     27 class WaitSetDispatcherTest : public ::testing::Test {
     28  public:
     29   WaitSetDispatcherTest() {}
     30   ~WaitSetDispatcherTest() override {}
     31 
     32   void SetUp() override {
     33     CreateMessagePipe(&dispatcher0_, &dispatcher1_);
     34   }
     35 
     36   void TearDown() override {
     37     for (auto& d : dispatchers_to_close_)
     38       d->Close();
     39   }
     40 
     41   MojoResult GetOneReadyDispatcher(
     42       const scoped_refptr<WaitSetDispatcher>& wait_set,
     43       scoped_refptr<Dispatcher>* ready_dispatcher,
     44       uintptr_t* context) {
     45     uint32_t count = 1;
     46     MojoResult dispatcher_result = MOJO_RESULT_UNKNOWN;
     47     DispatcherVector dispatchers;
     48     MojoResult result = wait_set->GetReadyDispatchers(
     49         &count, &dispatchers, &dispatcher_result, context);
     50     if (result == MOJO_RESULT_OK) {
     51       CHECK_EQ(1u, dispatchers.size());
     52       *ready_dispatcher = dispatchers[0];
     53       return dispatcher_result;
     54     }
     55     return result;
     56   }
     57 
     58   void CreateMessagePipe(scoped_refptr<MessagePipeDispatcher>* d0,
     59                          scoped_refptr<MessagePipeDispatcher>* d1) {
     60     MojoHandle h0, h1;
     61     EXPECT_EQ(MOJO_RESULT_OK, MojoCreateMessagePipe(nullptr, &h0, &h1));
     62 
     63     Core* core = mojo::edk::internal::g_core;
     64     *d0 = scoped_refptr<MessagePipeDispatcher>(
     65         static_cast<MessagePipeDispatcher*>(core->GetDispatcher(h0).get()));
     66     *d1 = scoped_refptr<MessagePipeDispatcher>(
     67         static_cast<MessagePipeDispatcher*>(core->GetDispatcher(h1).get()));
     68     pipe_id_generator_++;
     69 
     70     dispatchers_to_close_.push_back(*d0);
     71     dispatchers_to_close_.push_back(*d1);
     72   }
     73 
     74   void CloseOnShutdown(const scoped_refptr<Dispatcher>& dispatcher) {
     75     dispatchers_to_close_.push_back(dispatcher);
     76   }
     77 
     78   void WriteMessage(MessagePipeDispatcher* dispatcher,
     79                     const void* bytes,
     80                     size_t num_bytes) {
     81     Core* core = mojo::edk::internal::g_core;
     82     MojoMessageHandle msg;
     83     ASSERT_EQ(MOJO_RESULT_OK,
     84               core->AllocMessage(static_cast<uint32_t>(num_bytes), nullptr, 0,
     85                                  MOJO_ALLOC_MESSAGE_FLAG_NONE, &msg));
     86     void* buffer;
     87     ASSERT_EQ(MOJO_RESULT_OK, core->GetMessageBuffer(msg, &buffer));
     88     memcpy(buffer, bytes, num_bytes);
     89 
     90     std::unique_ptr<MessageForTransit> message(
     91         reinterpret_cast<MessageForTransit*>(msg));
     92     ASSERT_EQ(MOJO_RESULT_OK,
     93               dispatcher->WriteMessage(std::move(message),
     94                                        MOJO_WRITE_MESSAGE_FLAG_NONE));
     95   }
     96 
     97   void ReadMessage(MessagePipeDispatcher* dispatcher,
     98                    void* bytes,
     99                    uint32_t* num_bytes) {
    100     std::unique_ptr<MessageForTransit> message;
    101     ASSERT_EQ(MOJO_RESULT_OK,
    102               dispatcher->ReadMessage(&message, num_bytes, nullptr, 0,
    103                                       MOJO_READ_MESSAGE_FLAG_NONE, false));
    104     memcpy(bytes, message->bytes(), *num_bytes);
    105   }
    106 
    107  protected:
    108   scoped_refptr<MessagePipeDispatcher> dispatcher0_;
    109   scoped_refptr<MessagePipeDispatcher> dispatcher1_;
    110 
    111  private:
    112   // We keep an active RequestContext for the duration of each test. It's unused
    113   // since these tests don't rely on the MojoWatch API.
    114   const RequestContext request_context_;
    115 
    116   static uint64_t pipe_id_generator_;
    117   DispatcherVector dispatchers_to_close_;
    118 
    119   DISALLOW_COPY_AND_ASSIGN(WaitSetDispatcherTest);
    120 };
    121 
    122 // static
    123 uint64_t WaitSetDispatcherTest::pipe_id_generator_ = 1;
    124 
    125 TEST_F(WaitSetDispatcherTest, Basic) {
    126   scoped_refptr<WaitSetDispatcher> wait_set = new WaitSetDispatcher();
    127   CloseOnShutdown(wait_set);
    128   ASSERT_EQ(MOJO_RESULT_OK,
    129             wait_set->AddWaitingDispatcher(dispatcher0_,
    130                                            MOJO_HANDLE_SIGNAL_READABLE, 1));
    131   ASSERT_EQ(MOJO_RESULT_OK,
    132             wait_set->AddWaitingDispatcher(dispatcher1_,
    133                                            MOJO_HANDLE_SIGNAL_WRITABLE, 2));
    134 
    135   Waiter w;
    136   uintptr_t context = 0;
    137   w.Init();
    138   HandleSignalsState hss;
    139   // |dispatcher1_| should already be writable.
    140   EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS,
    141             wait_set->AddAwakable(&w, MOJO_HANDLE_SIGNAL_READABLE, 0, &hss));
    142   EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
    143   EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals);
    144 
    145   scoped_refptr<Dispatcher> woken_dispatcher;
    146   EXPECT_EQ(MOJO_RESULT_OK,
    147             GetOneReadyDispatcher(wait_set, &woken_dispatcher, &context));
    148   EXPECT_EQ(dispatcher1_, woken_dispatcher);
    149   EXPECT_EQ(2u, context);
    150   // If a ready dispatcher isn't removed, it will continue to be returned.
    151   EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS,
    152             wait_set->AddAwakable(&w, MOJO_HANDLE_SIGNAL_READABLE, 0, &hss));
    153   woken_dispatcher = nullptr;
    154   context = 0;
    155   EXPECT_EQ(MOJO_RESULT_OK,
    156             GetOneReadyDispatcher(wait_set, &woken_dispatcher, &context));
    157   EXPECT_EQ(dispatcher1_, woken_dispatcher);
    158   EXPECT_EQ(2u, context);
    159   ASSERT_EQ(MOJO_RESULT_OK, wait_set->RemoveWaitingDispatcher(dispatcher1_));
    160 
    161   // No ready dispatcher.
    162   hss = HandleSignalsState();
    163   EXPECT_EQ(MOJO_RESULT_OK,
    164             wait_set->AddAwakable(&w, MOJO_HANDLE_SIGNAL_READABLE, 0, &hss));
    165   EXPECT_FALSE(hss.satisfies(MOJO_HANDLE_SIGNAL_READABLE));
    166   EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, w.Wait(0, nullptr));
    167   EXPECT_EQ(MOJO_RESULT_SHOULD_WAIT,
    168             GetOneReadyDispatcher(wait_set, &woken_dispatcher, nullptr));
    169 
    170   // Write to |dispatcher1_|, which should make |dispatcher0_| readable.
    171   char buffer[] = "abcd";
    172   w.Init();
    173   WriteMessage(dispatcher1_.get(), buffer, sizeof(buffer));
    174   EXPECT_EQ(MOJO_RESULT_OK, w.Wait(MOJO_DEADLINE_INDEFINITE, nullptr));
    175   woken_dispatcher = nullptr;
    176   context = 0;
    177   EXPECT_EQ(MOJO_RESULT_OK,
    178             GetOneReadyDispatcher(wait_set, &woken_dispatcher, &context));
    179   EXPECT_EQ(dispatcher0_, woken_dispatcher);
    180   EXPECT_EQ(1u, context);
    181 
    182   // Again, if a ready dispatcher isn't removed, it will continue to be
    183   // returned.
    184   woken_dispatcher = nullptr;
    185   EXPECT_EQ(MOJO_RESULT_OK,
    186             GetOneReadyDispatcher(wait_set, &woken_dispatcher, nullptr));
    187   EXPECT_EQ(dispatcher0_, woken_dispatcher);
    188 
    189   wait_set->RemoveAwakable(&w, nullptr);
    190 }
    191 
    192 TEST_F(WaitSetDispatcherTest, HandleWithoutRemoving) {
    193   scoped_refptr<WaitSetDispatcher> wait_set = new WaitSetDispatcher();
    194   CloseOnShutdown(wait_set);
    195   ASSERT_EQ(MOJO_RESULT_OK,
    196             wait_set->AddWaitingDispatcher(dispatcher0_,
    197                                            MOJO_HANDLE_SIGNAL_READABLE, 1));
    198 
    199   Waiter w;
    200   uintptr_t context = 0;
    201   w.Init();
    202   HandleSignalsState hss;
    203   // No ready dispatcher.
    204   hss = HandleSignalsState();
    205   EXPECT_EQ(MOJO_RESULT_OK,
    206             wait_set->AddAwakable(&w, MOJO_HANDLE_SIGNAL_READABLE, 0, &hss));
    207   EXPECT_FALSE(hss.satisfies(MOJO_HANDLE_SIGNAL_READABLE));
    208   EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, w.Wait(0, nullptr));
    209   scoped_refptr<Dispatcher> woken_dispatcher;
    210   EXPECT_EQ(MOJO_RESULT_SHOULD_WAIT,
    211             GetOneReadyDispatcher(wait_set, &woken_dispatcher, nullptr));
    212 
    213   // The tested behaviour below should be repeatable.
    214   for (size_t i = 0; i < 3; i++) {
    215     // Write to |dispatcher1_|, which should make |dispatcher0_| readable.
    216     char buffer[] = "abcd";
    217     w.Init();
    218     WriteMessage(dispatcher1_.get(), buffer, sizeof(buffer));
    219     EXPECT_EQ(MOJO_RESULT_OK, w.Wait(MOJO_DEADLINE_INDEFINITE, nullptr));
    220     woken_dispatcher = nullptr;
    221     context = 0;
    222     EXPECT_EQ(MOJO_RESULT_OK,
    223               GetOneReadyDispatcher(wait_set, &woken_dispatcher, &context));
    224     EXPECT_EQ(dispatcher0_, woken_dispatcher);
    225     EXPECT_EQ(1u, context);
    226 
    227     // Read from |dispatcher0_| which should change it's state to non-readable.
    228     char read_buffer[sizeof(buffer) + 5];
    229     uint32_t num_bytes = sizeof(read_buffer);
    230     ReadMessage(dispatcher0_.get(), read_buffer, &num_bytes);
    231     EXPECT_EQ(sizeof(buffer), num_bytes);
    232 
    233     // No dispatchers are ready.
    234     w.Init();
    235     woken_dispatcher = nullptr;
    236     context = 0;
    237     EXPECT_EQ(MOJO_RESULT_SHOULD_WAIT,
    238               GetOneReadyDispatcher(wait_set, &woken_dispatcher, &context));
    239     EXPECT_FALSE(woken_dispatcher);
    240     EXPECT_EQ(0u, context);
    241     EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, w.Wait(0, nullptr));
    242   }
    243 
    244   wait_set->RemoveAwakable(&w, nullptr);
    245 }
    246 
    247 TEST_F(WaitSetDispatcherTest, MultipleReady) {
    248   scoped_refptr<WaitSetDispatcher> wait_set = new WaitSetDispatcher();
    249   CloseOnShutdown(wait_set);
    250 
    251   scoped_refptr<MessagePipeDispatcher> mp1_dispatcher0;
    252   scoped_refptr<MessagePipeDispatcher> mp1_dispatcher1;
    253   CreateMessagePipe(&mp1_dispatcher0, &mp1_dispatcher1);
    254 
    255   ASSERT_EQ(MOJO_RESULT_OK,
    256             wait_set->AddWaitingDispatcher(dispatcher0_,
    257                                            MOJO_HANDLE_SIGNAL_READABLE, 0));
    258   ASSERT_EQ(MOJO_RESULT_OK,
    259             wait_set->AddWaitingDispatcher(dispatcher1_,
    260                                            MOJO_HANDLE_SIGNAL_WRITABLE, 0));
    261   ASSERT_EQ(MOJO_RESULT_OK,
    262             wait_set->AddWaitingDispatcher(mp1_dispatcher0,
    263                                            MOJO_HANDLE_SIGNAL_WRITABLE, 0));
    264   ASSERT_EQ(MOJO_RESULT_OK,
    265             wait_set->AddWaitingDispatcher(mp1_dispatcher1,
    266                                            MOJO_HANDLE_SIGNAL_WRITABLE, 0));
    267 
    268   Waiter w;
    269   w.Init();
    270   HandleSignalsState hss;
    271   // The three writable dispatchers should be ready.
    272   EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS,
    273             wait_set->AddAwakable(&w, MOJO_HANDLE_SIGNAL_READABLE, 0, &hss));
    274   EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
    275   EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals);
    276 
    277   scoped_refptr<Dispatcher> woken_dispatcher;
    278   EXPECT_EQ(MOJO_RESULT_OK,
    279             GetOneReadyDispatcher(wait_set, &woken_dispatcher, nullptr));
    280   // Don't know which dispatcher was returned, just that it was one of the
    281   // writable ones.
    282   EXPECT_TRUE(woken_dispatcher == dispatcher1_ ||
    283               woken_dispatcher == mp1_dispatcher0 ||
    284               woken_dispatcher == mp1_dispatcher1);
    285 
    286   DispatcherVector dispatchers_vector;
    287   uint32_t count = 4;
    288   MojoResult results[4];
    289   EXPECT_EQ(MOJO_RESULT_OK,
    290             wait_set->GetReadyDispatchers(&count,
    291                                           &dispatchers_vector,
    292                                           results,
    293                                           nullptr));
    294   EXPECT_EQ(3u, count);
    295   std::sort(dispatchers_vector.begin(), dispatchers_vector.end());
    296   DispatcherVector expected_dispatchers;
    297   expected_dispatchers.push_back(dispatcher1_);
    298   expected_dispatchers.push_back(mp1_dispatcher0);
    299   expected_dispatchers.push_back(mp1_dispatcher1);
    300   std::sort(expected_dispatchers.begin(), expected_dispatchers.end());
    301   EXPECT_EQ(expected_dispatchers, dispatchers_vector);
    302 
    303   // If a ready dispatcher isn't removed, it will continue to be returned.
    304   EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS,
    305             wait_set->AddAwakable(&w, MOJO_HANDLE_SIGNAL_READABLE, 0, &hss));
    306   EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
    307   EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals);
    308   count = 4;
    309   dispatchers_vector.clear();
    310   EXPECT_EQ(MOJO_RESULT_OK,
    311             wait_set->GetReadyDispatchers(&count,
    312                                           &dispatchers_vector,
    313                                           results,
    314                                           nullptr));
    315   EXPECT_EQ(3u, count);
    316   std::sort(dispatchers_vector.begin(), dispatchers_vector.end());
    317   EXPECT_EQ(expected_dispatchers, dispatchers_vector);
    318 
    319   // Remove one. It shouldn't be returned any longer.
    320   ASSERT_EQ(MOJO_RESULT_OK,
    321             wait_set->RemoveWaitingDispatcher(expected_dispatchers.back()));
    322   expected_dispatchers.pop_back();
    323   EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS,
    324             wait_set->AddAwakable(&w, MOJO_HANDLE_SIGNAL_READABLE, 0, &hss));
    325   EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
    326   EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals);
    327   count = 4;
    328   dispatchers_vector.clear();
    329   EXPECT_EQ(MOJO_RESULT_OK,
    330             wait_set->GetReadyDispatchers(&count,
    331                                           &dispatchers_vector,
    332                                           results,
    333                                           nullptr));
    334   EXPECT_EQ(2u, count);
    335   std::sort(dispatchers_vector.begin(), dispatchers_vector.end());
    336   EXPECT_EQ(expected_dispatchers, dispatchers_vector);
    337 
    338   // Write to |dispatcher1_|, which should make |dispatcher0_| readable.
    339   char buffer[] = "abcd";
    340   w.Init();
    341   WriteMessage(dispatcher1_.get(), buffer, sizeof(buffer));
    342   {
    343     Waiter mp_w;
    344     mp_w.Init();
    345     // Wait for |dispatcher0_| to be readable.
    346     if (dispatcher0_->AddAwakable(&mp_w, MOJO_HANDLE_SIGNAL_READABLE, 0,
    347                                   nullptr) == MOJO_RESULT_OK) {
    348       EXPECT_EQ(MOJO_RESULT_OK, mp_w.Wait(MOJO_DEADLINE_INDEFINITE, 0));
    349       dispatcher0_->RemoveAwakable(&mp_w, nullptr);
    350     }
    351   }
    352   expected_dispatchers.push_back(dispatcher0_);
    353   std::sort(expected_dispatchers.begin(), expected_dispatchers.end());
    354   EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS,
    355             wait_set->AddAwakable(&w, MOJO_HANDLE_SIGNAL_READABLE, 0, &hss));
    356   EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
    357   EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals);
    358   count = 4;
    359   dispatchers_vector.clear();
    360   EXPECT_EQ(MOJO_RESULT_OK,
    361             wait_set->GetReadyDispatchers(&count,
    362                                           &dispatchers_vector,
    363                                           results,
    364                                           nullptr));
    365   EXPECT_EQ(3u, count);
    366   std::sort(dispatchers_vector.begin(), dispatchers_vector.end());
    367   EXPECT_EQ(expected_dispatchers, dispatchers_vector);
    368 }
    369 
    370 TEST_F(WaitSetDispatcherTest, InvalidParams) {
    371   scoped_refptr<WaitSetDispatcher> wait_set = new WaitSetDispatcher();
    372 
    373   // Can't add a wait set to itself.
    374   EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
    375             wait_set->AddWaitingDispatcher(wait_set,
    376                                            MOJO_HANDLE_SIGNAL_READABLE, 0));
    377 
    378   // Can't add twice.
    379   EXPECT_EQ(MOJO_RESULT_OK,
    380             wait_set->AddWaitingDispatcher(dispatcher0_,
    381                                            MOJO_HANDLE_SIGNAL_READABLE, 0));
    382   EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS,
    383             wait_set->AddWaitingDispatcher(dispatcher0_,
    384                                            MOJO_HANDLE_SIGNAL_READABLE, 0));
    385 
    386   // Remove a dispatcher that wasn't added.
    387   EXPECT_EQ(MOJO_RESULT_NOT_FOUND,
    388             wait_set->RemoveWaitingDispatcher(dispatcher1_));
    389 
    390   // Add to a closed wait set.
    391   wait_set->Close();
    392   EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
    393             wait_set->AddWaitingDispatcher(dispatcher0_,
    394                                            MOJO_HANDLE_SIGNAL_READABLE, 0));
    395 }
    396 
    397 TEST_F(WaitSetDispatcherTest, NotSatisfiable) {
    398   scoped_refptr<WaitSetDispatcher> wait_set = new WaitSetDispatcher();
    399   CloseOnShutdown(wait_set);
    400 
    401   // Wait sets can only satisfy MOJO_HANDLE_SIGNAL_READABLE.
    402   Waiter w;
    403   w.Init();
    404   HandleSignalsState hss;
    405   EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
    406             wait_set->AddAwakable(&w, MOJO_HANDLE_SIGNAL_WRITABLE, 0, &hss));
    407   EXPECT_EQ(MOJO_HANDLE_SIGNAL_NONE, hss.satisfied_signals);
    408   EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals);
    409 
    410   hss = HandleSignalsState();
    411   EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
    412             wait_set->AddAwakable(&w, MOJO_HANDLE_SIGNAL_PEER_CLOSED, 0, &hss));
    413   EXPECT_EQ(MOJO_HANDLE_SIGNAL_NONE, hss.satisfied_signals);
    414   EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals);
    415 }
    416 
    417 TEST_F(WaitSetDispatcherTest, ClosedDispatchers) {
    418   scoped_refptr<WaitSetDispatcher> wait_set = new WaitSetDispatcher();
    419   CloseOnShutdown(wait_set);
    420 
    421   Waiter w;
    422   w.Init();
    423   HandleSignalsState hss;
    424   // A dispatcher that was added and then closed will be cancelled.
    425   ASSERT_EQ(MOJO_RESULT_OK,
    426             wait_set->AddWaitingDispatcher(dispatcher0_,
    427                                            MOJO_HANDLE_SIGNAL_READABLE, 0));
    428   EXPECT_EQ(MOJO_RESULT_OK,
    429             wait_set->AddAwakable(&w, MOJO_HANDLE_SIGNAL_READABLE, 0, &hss));
    430   dispatcher0_->Close();
    431   EXPECT_EQ(MOJO_RESULT_OK, w.Wait(MOJO_DEADLINE_INDEFINITE, nullptr));
    432   EXPECT_TRUE(
    433       wait_set->GetHandleSignalsState().satisfies(MOJO_HANDLE_SIGNAL_READABLE));
    434   scoped_refptr<Dispatcher> woken_dispatcher;
    435   EXPECT_EQ(MOJO_RESULT_CANCELLED,
    436             GetOneReadyDispatcher(wait_set, &woken_dispatcher, nullptr));
    437   EXPECT_EQ(dispatcher0_, woken_dispatcher);
    438 
    439   // Dispatcher will be implicitly removed because it may be impossible to
    440   // remove explicitly.
    441   woken_dispatcher = nullptr;
    442   EXPECT_EQ(MOJO_RESULT_SHOULD_WAIT,
    443             GetOneReadyDispatcher(wait_set, &woken_dispatcher, nullptr));
    444   EXPECT_EQ(MOJO_RESULT_NOT_FOUND,
    445             wait_set->RemoveWaitingDispatcher(dispatcher0_));
    446 
    447   // A dispatcher that's not satisfiable should give an error.
    448   w.Init();
    449   EXPECT_EQ(MOJO_RESULT_OK,
    450             wait_set->AddWaitingDispatcher(dispatcher1_,
    451                                            MOJO_HANDLE_SIGNAL_READABLE, 0));
    452   EXPECT_EQ(MOJO_RESULT_OK, w.Wait(MOJO_DEADLINE_INDEFINITE, nullptr));
    453   EXPECT_TRUE(
    454       wait_set->GetHandleSignalsState().satisfies(MOJO_HANDLE_SIGNAL_READABLE));
    455   EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
    456             GetOneReadyDispatcher(wait_set, &woken_dispatcher, nullptr));
    457   EXPECT_EQ(dispatcher1_, woken_dispatcher);
    458 
    459   wait_set->RemoveAwakable(&w, nullptr);
    460 }
    461 
    462 TEST_F(WaitSetDispatcherTest, NestedSets) {
    463   scoped_refptr<WaitSetDispatcher> wait_set = new WaitSetDispatcher();
    464   CloseOnShutdown(wait_set);
    465   scoped_refptr<WaitSetDispatcher> nested_wait_set = new WaitSetDispatcher();
    466   CloseOnShutdown(nested_wait_set);
    467 
    468   Waiter w;
    469   w.Init();
    470   EXPECT_EQ(MOJO_RESULT_OK,
    471             wait_set->AddWaitingDispatcher(nested_wait_set,
    472                                            MOJO_HANDLE_SIGNAL_READABLE, 0));
    473   EXPECT_EQ(MOJO_RESULT_OK,
    474             wait_set->AddAwakable(&w, MOJO_HANDLE_SIGNAL_READABLE, 0, nullptr));
    475   EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, w.Wait(0, nullptr));
    476 
    477   // Writable signal is immediately satisfied by the message pipe.
    478   w.Init();
    479   EXPECT_EQ(MOJO_RESULT_OK,
    480             nested_wait_set->AddWaitingDispatcher(
    481                 dispatcher0_, MOJO_HANDLE_SIGNAL_WRITABLE, 0));
    482   EXPECT_EQ(MOJO_RESULT_OK, w.Wait(0, nullptr));
    483   scoped_refptr<Dispatcher> woken_dispatcher;
    484   EXPECT_EQ(MOJO_RESULT_OK,
    485             GetOneReadyDispatcher(wait_set, &woken_dispatcher, nullptr));
    486   EXPECT_EQ(nested_wait_set, woken_dispatcher);
    487 
    488   wait_set->RemoveAwakable(&w, nullptr);
    489 }
    490 
    491 }  // namespace
    492 }  // namespace edk
    493 }  // namespace mojo
    494