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