• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
WaitSetDispatcherTest()29   WaitSetDispatcherTest() {}
~WaitSetDispatcherTest()30   ~WaitSetDispatcherTest() override {}
31 
SetUp()32   void SetUp() override {
33     CreateMessagePipe(&dispatcher0_, &dispatcher1_);
34   }
35 
TearDown()36   void TearDown() override {
37     for (auto& d : dispatchers_to_close_)
38       d->Close();
39   }
40 
GetOneReadyDispatcher(const scoped_refptr<WaitSetDispatcher> & wait_set,scoped_refptr<Dispatcher> * ready_dispatcher,uintptr_t * context)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 
CreateMessagePipe(scoped_refptr<MessagePipeDispatcher> * d0,scoped_refptr<MessagePipeDispatcher> * d1)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 
CloseOnShutdown(const scoped_refptr<Dispatcher> & dispatcher)74   void CloseOnShutdown(const scoped_refptr<Dispatcher>& dispatcher) {
75     dispatchers_to_close_.push_back(dispatcher);
76   }
77 
WriteMessage(MessagePipeDispatcher * dispatcher,const void * bytes,size_t num_bytes)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 
ReadMessage(MessagePipeDispatcher * dispatcher,void * bytes,uint32_t * num_bytes)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 
TEST_F(WaitSetDispatcherTest,Basic)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 
TEST_F(WaitSetDispatcherTest,HandleWithoutRemoving)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 
TEST_F(WaitSetDispatcherTest,MultipleReady)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 
TEST_F(WaitSetDispatcherTest,InvalidParams)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 
TEST_F(WaitSetDispatcherTest,NotSatisfiable)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 
TEST_F(WaitSetDispatcherTest,ClosedDispatchers)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 
TEST_F(WaitSetDispatcherTest,NestedSets)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