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