1 // Copyright 2017 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/public/cpp/system/wait.h" 6 7 #include <string> 8 #include <vector> 9 10 #include "base/bind.h" 11 #include "base/callback.h" 12 #include "base/strings/string_piece.h" 13 #include "base/threading/platform_thread.h" 14 #include "base/threading/simple_thread.h" 15 #include "base/time/time.h" 16 #include "mojo/public/c/system/types.h" 17 #include "mojo/public/cpp/system/handle_signals_state.h" 18 #include "mojo/public/cpp/system/message_pipe.h" 19 #include "testing/gtest/include/gtest/gtest.h" 20 21 namespace mojo { 22 namespace { 23 24 using WaitTest = testing::Test; 25 using WaitManyTest = testing::Test; 26 27 void WriteMessage(const ScopedMessagePipeHandle& handle, 28 const base::StringPiece& message) { 29 MojoResult rv = WriteMessageRaw(handle.get(), message.data(), 30 static_cast<uint32_t>(message.size()), 31 nullptr, 0, MOJO_WRITE_MESSAGE_FLAG_NONE); 32 CHECK_EQ(MOJO_RESULT_OK, rv); 33 } 34 35 std::string ReadMessage(const ScopedMessagePipeHandle& handle) { 36 std::vector<uint8_t> bytes; 37 MojoResult rv = ReadMessageRaw(handle.get(), &bytes, nullptr, 38 MOJO_READ_MESSAGE_FLAG_NONE); 39 CHECK_EQ(MOJO_RESULT_OK, rv); 40 return std::string(bytes.begin(), bytes.end()); 41 } 42 43 class ThreadedRunner : public base::SimpleThread { 44 public: 45 explicit ThreadedRunner(const base::Closure& callback) 46 : SimpleThread("ThreadedRunner"), callback_(callback) {} 47 ~ThreadedRunner() override { Join(); } 48 49 void Run() override { callback_.Run(); } 50 51 private: 52 const base::Closure callback_; 53 54 DISALLOW_COPY_AND_ASSIGN(ThreadedRunner); 55 }; 56 57 TEST_F(WaitTest, InvalidArguments) { 58 Handle invalid_handle; 59 60 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, 61 Wait(invalid_handle, MOJO_HANDLE_SIGNAL_READABLE)); 62 63 MessagePipe p; 64 Handle valid_handles[2] = {p.handle0.get(), p.handle1.get()}; 65 Handle invalid_handles[2]; 66 MojoHandleSignals signals[2] = {MOJO_HANDLE_SIGNAL_NONE, 67 MOJO_HANDLE_SIGNAL_NONE}; 68 size_t result_index = 0; 69 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, 70 WaitMany(invalid_handles, signals, 2, &result_index)); 71 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, 72 WaitMany(nullptr, signals, 2, &result_index)); 73 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, 74 WaitMany(valid_handles, nullptr, 2, &result_index)); 75 } 76 77 TEST_F(WaitTest, Basic) { 78 MessagePipe p; 79 80 // Write to one end of the pipe and wait on the other. 81 const char kTestMessage1[] = "how about a nice game of chess?"; 82 WriteMessage(p.handle0, kTestMessage1); 83 EXPECT_EQ(MOJO_RESULT_OK, Wait(p.handle1.get(), MOJO_HANDLE_SIGNAL_READABLE)); 84 85 // And make sure we can also grab the handle signals state (with both the C 86 // and C++ library structs.) 87 88 MojoHandleSignalsState c_hss = {0, 0}; 89 EXPECT_EQ(MOJO_RESULT_OK, 90 Wait(p.handle1.get(), MOJO_HANDLE_SIGNAL_READABLE, &c_hss)); 91 EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, 92 c_hss.satisfied_signals); 93 94 HandleSignalsState hss; 95 EXPECT_EQ(MOJO_RESULT_OK, 96 Wait(p.handle1.get(), MOJO_HANDLE_SIGNAL_READABLE, &hss)); 97 EXPECT_TRUE(hss.readable() && hss.writable() && !hss.peer_closed()); 98 EXPECT_FALSE(hss.never_readable() || hss.never_writable() || 99 hss.never_peer_closed()); 100 101 // Now close the writing end and wait for peer closure. 102 103 p.handle0.reset(); 104 EXPECT_EQ(MOJO_RESULT_OK, 105 Wait(p.handle1.get(), MOJO_HANDLE_SIGNAL_PEER_CLOSED, &hss)); 106 107 // Still readable as there's still a message queued. No longer writable as 108 // peer closure has been detected. 109 EXPECT_TRUE(hss.readable() && hss.peer_closed() && !hss.writable()); 110 EXPECT_TRUE(hss.never_writable() && !hss.never_readable() && 111 !hss.never_peer_closed()); 112 113 // Read the message and wait for readable again. Waiting should fail since 114 // there are no more messages and the peer is closed. 115 EXPECT_EQ(kTestMessage1, ReadMessage(p.handle1)); 116 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, 117 Wait(p.handle1.get(), MOJO_HANDLE_SIGNAL_READABLE, &hss)); 118 119 // Sanity check the signals state again. 120 EXPECT_TRUE(hss.peer_closed() && !hss.readable() && !hss.writable()); 121 EXPECT_TRUE(hss.never_readable() && hss.never_writable() && 122 !hss.never_peer_closed()); 123 } 124 125 TEST_F(WaitTest, DelayedWrite) { 126 MessagePipe p; 127 128 ThreadedRunner write_after_delay(base::Bind( 129 [](ScopedMessagePipeHandle* handle) { 130 // Wait a little while, then write a message. 131 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(200)); 132 WriteMessage(*handle, "wakey wakey"); 133 }, 134 &p.handle0)); 135 write_after_delay.Start(); 136 137 HandleSignalsState hss; 138 EXPECT_EQ(MOJO_RESULT_OK, 139 Wait(p.handle1.get(), MOJO_HANDLE_SIGNAL_READABLE, &hss)); 140 EXPECT_TRUE(hss.readable() && hss.writable() && !hss.peer_closed()); 141 EXPECT_TRUE(!hss.never_readable() && !hss.never_writable() && 142 !hss.never_peer_closed()); 143 } 144 145 TEST_F(WaitTest, DelayedPeerClosure) { 146 MessagePipe p; 147 148 ThreadedRunner close_after_delay(base::Bind( 149 [](ScopedMessagePipeHandle* handle) { 150 // Wait a little while, then close the handle. 151 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(200)); 152 handle->reset(); 153 }, 154 &p.handle0)); 155 close_after_delay.Start(); 156 157 HandleSignalsState hss; 158 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, 159 Wait(p.handle1.get(), MOJO_HANDLE_SIGNAL_READABLE, &hss)); 160 EXPECT_TRUE(!hss.readable() && !hss.writable() && hss.peer_closed()); 161 EXPECT_TRUE(hss.never_readable() && hss.never_writable() && 162 !hss.never_peer_closed()); 163 } 164 165 TEST_F(WaitTest, CloseWhileWaiting) { 166 MessagePipe p; 167 ThreadedRunner close_after_delay(base::Bind( 168 [](ScopedMessagePipeHandle* handle) { 169 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(200)); 170 handle->reset(); 171 }, 172 &p.handle0)); 173 close_after_delay.Start(); 174 EXPECT_EQ(MOJO_RESULT_CANCELLED, 175 Wait(p.handle0.get(), MOJO_HANDLE_SIGNAL_READABLE)); 176 } 177 178 TEST_F(WaitManyTest, Basic) { 179 MessagePipe p; 180 181 const char kTestMessage1[] = "hello"; 182 WriteMessage(p.handle0, kTestMessage1); 183 184 // Wait for either handle to become readable. Wait twice, just to verify that 185 // we can use either the C or C++ signaling state structure for the last 186 // argument. 187 188 Handle handles[2] = {p.handle0.get(), p.handle1.get()}; 189 MojoHandleSignals signals[2] = {MOJO_HANDLE_SIGNAL_READABLE, 190 MOJO_HANDLE_SIGNAL_READABLE}; 191 size_t result_index = 0; 192 MojoHandleSignalsState c_hss[2]; 193 HandleSignalsState hss[2]; 194 195 EXPECT_EQ(MOJO_RESULT_OK, 196 WaitMany(handles, signals, 2, &result_index, c_hss)); 197 EXPECT_EQ(1u, result_index); 198 EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, c_hss[0].satisfied_signals); 199 EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, 200 c_hss[1].satisfied_signals); 201 202 EXPECT_EQ(MOJO_RESULT_OK, WaitMany(handles, signals, 2, &result_index, hss)); 203 EXPECT_EQ(1u, result_index); 204 EXPECT_TRUE(!hss[0].readable() && hss[0].writable() && !hss[0].peer_closed()); 205 EXPECT_TRUE(!hss[0].never_readable() && !hss[0].never_writable() && 206 !hss[0].never_peer_closed()); 207 EXPECT_TRUE(hss[1].readable() && hss[1].writable() && !hss[1].peer_closed()); 208 EXPECT_TRUE(!hss[1].never_readable() && !hss[1].never_writable() && 209 !hss[1].never_peer_closed()); 210 211 // Close the writer and read the message. Try to wait again, and it should 212 // fail due to the conditions being unsatisfiable. 213 214 EXPECT_EQ(kTestMessage1, ReadMessage(p.handle1)); 215 p.handle0.reset(); 216 217 // handles[0] is invalid. 218 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, 219 WaitMany(handles, signals, 2, &result_index, hss)); 220 handles[0] = handles[1]; 221 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, 222 WaitMany(handles, signals, 1, &result_index, hss)); 223 EXPECT_EQ(0u, result_index); 224 EXPECT_TRUE(!hss[0].readable() && !hss[0].writable() && hss[0].peer_closed()); 225 EXPECT_TRUE(hss[0].never_readable() && hss[0].never_writable() && 226 !hss[0].never_peer_closed()); 227 } 228 229 TEST_F(WaitManyTest, CloseWhileWaiting) { 230 MessagePipe p, q; 231 232 Handle handles[3] = {q.handle0.get(), q.handle1.get(), p.handle1.get()}; 233 MojoHandleSignals signals[3] = {MOJO_HANDLE_SIGNAL_READABLE, 234 MOJO_HANDLE_SIGNAL_READABLE, 235 MOJO_HANDLE_SIGNAL_READABLE}; 236 237 ThreadedRunner close_after_delay(base::Bind( 238 [](ScopedMessagePipeHandle* handle) { 239 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(200)); 240 handle->reset(); 241 }, 242 &p.handle1)); 243 close_after_delay.Start(); 244 245 size_t result_index = 0; 246 EXPECT_EQ(MOJO_RESULT_CANCELLED, 247 WaitMany(handles, signals, 3, &result_index)); 248 EXPECT_EQ(2u, result_index); 249 } 250 251 TEST_F(WaitManyTest, DelayedWrite) { 252 MessagePipe p; 253 254 ThreadedRunner write_after_delay(base::Bind( 255 [](ScopedMessagePipeHandle* handle) { 256 // Wait a little while, then write a message. 257 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(200)); 258 WriteMessage(*handle, "wakey wakey"); 259 }, 260 &p.handle0)); 261 write_after_delay.Start(); 262 263 Handle handles[2] = {p.handle0.get(), p.handle1.get()}; 264 MojoHandleSignals signals[2] = {MOJO_HANDLE_SIGNAL_READABLE, 265 MOJO_HANDLE_SIGNAL_READABLE}; 266 size_t result_index = 0; 267 HandleSignalsState hss[2]; 268 EXPECT_EQ(MOJO_RESULT_OK, WaitMany(handles, signals, 2, &result_index, hss)); 269 EXPECT_EQ(1u, result_index); 270 EXPECT_TRUE(!hss[0].readable() && hss[0].writable() && !hss[0].peer_closed()); 271 EXPECT_TRUE(!hss[0].never_readable() && !hss[0].never_writable() && 272 !hss[0].never_peer_closed()); 273 EXPECT_TRUE(hss[1].readable() && hss[1].writable() && !hss[1].peer_closed()); 274 EXPECT_TRUE(!hss[1].never_readable() && !hss[1].never_writable() && 275 !hss[1].never_peer_closed()); 276 } 277 278 TEST_F(WaitManyTest, DelayedPeerClosure) { 279 MessagePipe p, q; 280 281 ThreadedRunner close_after_delay(base::Bind( 282 [](ScopedMessagePipeHandle* handle) { 283 // Wait a little while, then close the handle. 284 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(200)); 285 handle->reset(); 286 }, 287 &p.handle0)); 288 close_after_delay.Start(); 289 290 Handle handles[3] = {q.handle0.get(), q.handle1.get(), p.handle1.get()}; 291 MojoHandleSignals signals[3] = {MOJO_HANDLE_SIGNAL_READABLE, 292 MOJO_HANDLE_SIGNAL_READABLE, 293 MOJO_HANDLE_SIGNAL_READABLE}; 294 size_t result_index = 0; 295 HandleSignalsState hss[3]; 296 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, 297 WaitMany(handles, signals, 3, &result_index, hss)); 298 EXPECT_EQ(2u, result_index); 299 EXPECT_TRUE(!hss[2].readable() && !hss[2].writable() && hss[2].peer_closed()); 300 EXPECT_TRUE(hss[2].never_readable() && hss[2].never_writable() && 301 !hss[2].never_peer_closed()); 302 } 303 304 } // namespace 305 } // namespace mojo 306