Index: mojo/system/remote_message_pipe_unittest.cc |
diff --git a/mojo/system/remote_message_pipe_unittest.cc b/mojo/system/remote_message_pipe_unittest.cc |
index 1d22d13409f3af7f4286d156b5e0e09dff483418..406700680e775d7b365076326daea11562a232d6 100644 |
--- a/mojo/system/remote_message_pipe_unittest.cc |
+++ b/mojo/system/remote_message_pipe_unittest.cc |
@@ -939,6 +939,231 @@ TEST_F(RemoteMessagePipeTest, RacingClosesStress) { |
} |
} |
+// Tests passing an end of a message pipe over a remote message pipe, and then |
+// passing that end back. |
+// TODO(vtl): Also test passing a message pipe across two remote message pipes. |
+TEST_F(RemoteMessagePipeTest, PassMessagePipeHandleAcrossAndBack) { |
+ static const char kHello[] = "hello"; |
+ static const char kWorld[] = "world"; |
+ Waiter waiter; |
+ HandleSignalsState hss; |
+ uint32_t context = 0; |
+ |
+ scoped_refptr<MessagePipe> mp0(MessagePipe::CreateLocalProxy()); |
+ scoped_refptr<MessagePipe> mp1(MessagePipe::CreateProxyLocal()); |
+ ConnectMessagePipes(mp0, mp1); |
+ |
+ // We'll try to pass this dispatcher. |
+ scoped_refptr<MessagePipeDispatcher> dispatcher( |
+ new MessagePipeDispatcher(MessagePipeDispatcher::kDefaultCreateOptions)); |
+ scoped_refptr<MessagePipe> local_mp(MessagePipe::CreateLocalLocal()); |
+ dispatcher->Init(local_mp, 0); |
+ |
+ // Prepare to wait on MP 1, port 1. (Add the waiter now. Otherwise, if we do |
+ // it later, it might already be readable.) |
+ waiter.Init(); |
+ ASSERT_EQ(MOJO_RESULT_OK, |
+ mp1->AddWaiter(1, &waiter, MOJO_HANDLE_SIGNAL_READABLE, 123, NULL)); |
+ |
+ // Write to MP 0, port 0. |
+ { |
+ DispatcherTransport transport( |
+ test::DispatcherTryStartTransport(dispatcher.get())); |
+ EXPECT_TRUE(transport.is_valid()); |
+ |
+ std::vector<DispatcherTransport> transports; |
+ transports.push_back(transport); |
+ EXPECT_EQ(MOJO_RESULT_OK, |
+ mp0->WriteMessage(0, |
+ UserPointer<const void>(kHello), |
+ sizeof(kHello), |
+ &transports, |
+ MOJO_WRITE_MESSAGE_FLAG_NONE)); |
+ transport.End(); |
+ |
+ // |dispatcher| should have been closed. This is |DCHECK()|ed when the |
+ // |dispatcher| is destroyed. |
+ EXPECT_TRUE(dispatcher->HasOneRef()); |
+ dispatcher = NULL; |
+ } |
+ |
+ // Wait. |
+ EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(MOJO_DEADLINE_INDEFINITE, &context)); |
+ EXPECT_EQ(123u, context); |
+ hss = HandleSignalsState(); |
+ mp1->RemoveWaiter(1, &waiter, &hss); |
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, |
+ hss.satisfied_signals); |
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, |
+ hss.satisfiable_signals); |
+ |
+ // Read from MP 1, port 1. |
+ char read_buffer[100] = {0}; |
+ uint32_t read_buffer_size = static_cast<uint32_t>(sizeof(read_buffer)); |
+ DispatcherVector read_dispatchers; |
+ uint32_t read_num_dispatchers = 10; // Maximum to get. |
+ EXPECT_EQ(MOJO_RESULT_OK, |
+ mp1->ReadMessage(1, |
+ UserPointer<void>(read_buffer), |
+ MakeUserPointer(&read_buffer_size), |
+ &read_dispatchers, |
+ &read_num_dispatchers, |
+ MOJO_READ_MESSAGE_FLAG_NONE)); |
+ EXPECT_EQ(sizeof(kHello), static_cast<size_t>(read_buffer_size)); |
+ EXPECT_STREQ(kHello, read_buffer); |
+ EXPECT_EQ(1u, read_dispatchers.size()); |
+ EXPECT_EQ(1u, read_num_dispatchers); |
+ ASSERT_TRUE(read_dispatchers[0].get()); |
+ EXPECT_TRUE(read_dispatchers[0]->HasOneRef()); |
+ |
+ EXPECT_EQ(Dispatcher::kTypeMessagePipe, read_dispatchers[0]->GetType()); |
+ dispatcher = static_cast<MessagePipeDispatcher*>(read_dispatchers[0].get()); |
+ read_dispatchers.clear(); |
+ |
+ // Now pass it back. |
+ |
+ // Prepare to wait on MP 0, port 0. (Add the waiter now. Otherwise, if we do |
+ // it later, it might already be readable.) |
+ waiter.Init(); |
+ ASSERT_EQ(MOJO_RESULT_OK, |
+ mp0->AddWaiter(0, &waiter, MOJO_HANDLE_SIGNAL_READABLE, 456, NULL)); |
+ |
+ // Write to MP 1, port 1. |
+ { |
+ DispatcherTransport transport( |
+ test::DispatcherTryStartTransport(dispatcher.get())); |
+ EXPECT_TRUE(transport.is_valid()); |
+ |
+ std::vector<DispatcherTransport> transports; |
+ transports.push_back(transport); |
+ EXPECT_EQ(MOJO_RESULT_OK, |
+ mp1->WriteMessage(1, |
+ UserPointer<const void>(kWorld), |
+ sizeof(kWorld), |
+ &transports, |
+ MOJO_WRITE_MESSAGE_FLAG_NONE)); |
+ transport.End(); |
+ |
+ // |dispatcher| should have been closed. This is |DCHECK()|ed when the |
+ // |dispatcher| is destroyed. |
+ EXPECT_TRUE(dispatcher->HasOneRef()); |
+ dispatcher = NULL; |
+ } |
+ |
+ // Wait. |
+ EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(MOJO_DEADLINE_INDEFINITE, &context)); |
+ EXPECT_EQ(456u, context); |
+ hss = HandleSignalsState(); |
+ mp0->RemoveWaiter(0, &waiter, &hss); |
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, |
+ hss.satisfied_signals); |
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, |
+ hss.satisfiable_signals); |
+ |
+ // Read from MP 0, port 0. |
+ read_buffer_size = static_cast<uint32_t>(sizeof(read_buffer)); |
+ read_num_dispatchers = 10; // Maximum to get. |
+ EXPECT_EQ(MOJO_RESULT_OK, |
+ mp0->ReadMessage(0, |
+ UserPointer<void>(read_buffer), |
+ MakeUserPointer(&read_buffer_size), |
+ &read_dispatchers, |
+ &read_num_dispatchers, |
+ MOJO_READ_MESSAGE_FLAG_NONE)); |
+ EXPECT_EQ(sizeof(kWorld), static_cast<size_t>(read_buffer_size)); |
+ EXPECT_STREQ(kWorld, read_buffer); |
+ EXPECT_EQ(1u, read_dispatchers.size()); |
+ EXPECT_EQ(1u, read_num_dispatchers); |
+ ASSERT_TRUE(read_dispatchers[0].get()); |
+ EXPECT_TRUE(read_dispatchers[0]->HasOneRef()); |
+ |
+ EXPECT_EQ(Dispatcher::kTypeMessagePipe, read_dispatchers[0]->GetType()); |
+ dispatcher = static_cast<MessagePipeDispatcher*>(read_dispatchers[0].get()); |
+ read_dispatchers.clear(); |
+ |
+ // Add the waiter now, before it becomes readable to avoid a race. |
+ waiter.Init(); |
+ ASSERT_EQ( |
+ MOJO_RESULT_OK, |
+ dispatcher->AddWaiter(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 789, NULL)); |
+ |
+ // Write to "local_mp", port 1. |
+ EXPECT_EQ(MOJO_RESULT_OK, |
+ local_mp->WriteMessage(1, |
+ UserPointer<const void>(kHello), |
+ sizeof(kHello), |
+ NULL, |
+ MOJO_WRITE_MESSAGE_FLAG_NONE)); |
+ |
+ // Wait for the dispatcher to become readable. |
+ EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(MOJO_DEADLINE_INDEFINITE, &context)); |
+ EXPECT_EQ(789u, context); |
+ hss = HandleSignalsState(); |
+ dispatcher->RemoveWaiter(&waiter, &hss); |
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, |
+ hss.satisfied_signals); |
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, |
+ hss.satisfiable_signals); |
+ |
+ // Read from the dispatcher. |
+ memset(read_buffer, 0, sizeof(read_buffer)); |
+ read_buffer_size = static_cast<uint32_t>(sizeof(read_buffer)); |
+ EXPECT_EQ(MOJO_RESULT_OK, |
+ dispatcher->ReadMessage(UserPointer<void>(read_buffer), |
+ MakeUserPointer(&read_buffer_size), |
+ 0, |
+ NULL, |
+ MOJO_READ_MESSAGE_FLAG_NONE)); |
+ EXPECT_EQ(sizeof(kHello), static_cast<size_t>(read_buffer_size)); |
+ EXPECT_STREQ(kHello, read_buffer); |
+ |
+ // Prepare to wait on "local_mp", port 1. |
+ waiter.Init(); |
+ ASSERT_EQ( |
+ MOJO_RESULT_OK, |
+ local_mp->AddWaiter(1, &waiter, MOJO_HANDLE_SIGNAL_READABLE, 789, NULL)); |
+ |
+ // Write to the dispatcher. |
+ EXPECT_EQ(MOJO_RESULT_OK, |
+ dispatcher->WriteMessage(UserPointer<const void>(kHello), |
+ sizeof(kHello), |
+ NULL, |
+ MOJO_WRITE_MESSAGE_FLAG_NONE)); |
+ |
+ // Wait. |
+ EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(MOJO_DEADLINE_INDEFINITE, &context)); |
+ EXPECT_EQ(789u, context); |
+ hss = HandleSignalsState(); |
+ local_mp->RemoveWaiter(1, &waiter, &hss); |
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, |
+ hss.satisfied_signals); |
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, |
+ hss.satisfiable_signals); |
+ |
+ // Read from "local_mp", port 1. |
+ memset(read_buffer, 0, sizeof(read_buffer)); |
+ read_buffer_size = static_cast<uint32_t>(sizeof(read_buffer)); |
+ EXPECT_EQ(MOJO_RESULT_OK, |
+ local_mp->ReadMessage(1, |
+ UserPointer<void>(read_buffer), |
+ MakeUserPointer(&read_buffer_size), |
+ NULL, |
+ NULL, |
+ MOJO_READ_MESSAGE_FLAG_NONE)); |
+ EXPECT_EQ(sizeof(kHello), static_cast<size_t>(read_buffer_size)); |
+ EXPECT_STREQ(kHello, read_buffer); |
+ |
+ // TODO(vtl): Also test the cases where messages are written and read (at |
+ // various points) on the message pipe being passed around. |
+ |
+ // Close everything that belongs to us. |
+ mp0->Close(0); |
+ mp1->Close(1); |
+ EXPECT_EQ(MOJO_RESULT_OK, dispatcher->Close()); |
+ // Note that |local_mp|'s port 0 belong to |dispatcher|, which was closed. |
+ local_mp->Close(1); |
+} |
+ |
} // namespace |
} // namespace system |
} // namespace mojo |