OLD | NEW |
(Empty) | |
| 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_set.h" |
| 6 |
| 7 #include "base/bind.h" |
| 8 #include "base/callback.h" |
| 9 #include "base/threading/platform_thread.h" |
| 10 #include "base/threading/simple_thread.h" |
| 11 #include "mojo/public/cpp/system/message_pipe.h" |
| 12 #include "testing/gtest/include/gtest/gtest.h" |
| 13 |
| 14 namespace mojo { |
| 15 namespace { |
| 16 |
| 17 using WaitSetTest = testing::Test; |
| 18 |
| 19 void WriteMessage(const ScopedMessagePipeHandle& handle, |
| 20 const base::StringPiece& message) { |
| 21 MojoResult rv = WriteMessageRaw(handle.get(), message.data(), |
| 22 static_cast<uint32_t>(message.size()), |
| 23 nullptr, 0, MOJO_WRITE_MESSAGE_FLAG_NONE); |
| 24 CHECK_EQ(MOJO_RESULT_OK, rv); |
| 25 } |
| 26 |
| 27 std::string ReadMessage(const ScopedMessagePipeHandle& handle) { |
| 28 uint32_t num_bytes = 0; |
| 29 uint32_t num_handles = 0; |
| 30 MojoResult rv = ReadMessageRaw(handle.get(), nullptr, &num_bytes, nullptr, |
| 31 &num_handles, MOJO_READ_MESSAGE_FLAG_NONE); |
| 32 CHECK_EQ(MOJO_RESULT_RESOURCE_EXHAUSTED, rv); |
| 33 CHECK_EQ(0u, num_handles); |
| 34 |
| 35 std::vector<char> buffer(num_bytes); |
| 36 rv = ReadMessageRaw(handle.get(), buffer.data(), &num_bytes, nullptr, |
| 37 &num_handles, MOJO_READ_MESSAGE_FLAG_NONE); |
| 38 CHECK_EQ(MOJO_RESULT_OK, rv); |
| 39 return std::string(buffer.data(), buffer.size()); |
| 40 } |
| 41 |
| 42 class ThreadedRunner : public base::SimpleThread { |
| 43 public: |
| 44 explicit ThreadedRunner(const base::Closure& callback) |
| 45 : SimpleThread("ThreadedRunner"), callback_(callback) {} |
| 46 ~ThreadedRunner() override { Join(); } |
| 47 |
| 48 void Run() override { callback_.Run(); } |
| 49 |
| 50 private: |
| 51 const base::Closure callback_; |
| 52 |
| 53 DISALLOW_COPY_AND_ASSIGN(ThreadedRunner); |
| 54 }; |
| 55 |
| 56 TEST_F(WaitSetTest, Satisfied) { |
| 57 WaitSet wait_set; |
| 58 MessagePipe p; |
| 59 |
| 60 const char kTestMessage1[] = "hello wake up"; |
| 61 |
| 62 // Watch only one handle and write to the other. |
| 63 |
| 64 wait_set.AddHandle(p.handle1.get(), MOJO_HANDLE_SIGNAL_READABLE); |
| 65 WriteMessage(p.handle0, kTestMessage1); |
| 66 |
| 67 size_t num_ready_handles = 2; |
| 68 Handle ready_handles[2]; |
| 69 MojoResult ready_results[2] = {MOJO_RESULT_UNKNOWN, MOJO_RESULT_UNKNOWN}; |
| 70 HandleSignalsState hss[2]; |
| 71 wait_set.Wait(&num_ready_handles, ready_handles, ready_results, hss); |
| 72 |
| 73 EXPECT_EQ(1u, num_ready_handles); |
| 74 EXPECT_EQ(p.handle1.get(), ready_handles[0]); |
| 75 EXPECT_EQ(MOJO_RESULT_OK, ready_results[0]); |
| 76 EXPECT_TRUE(hss[0].readable() && hss[0].writable() && !hss[0].peer_closed()); |
| 77 |
| 78 wait_set.RemoveHandle(p.handle1.get()); |
| 79 |
| 80 // Now watch only the other handle and write to the first one. |
| 81 |
| 82 wait_set.AddHandle(p.handle0.get(), MOJO_HANDLE_SIGNAL_READABLE); |
| 83 WriteMessage(p.handle1, kTestMessage1); |
| 84 |
| 85 num_ready_handles = 2; |
| 86 ready_results[0] = MOJO_RESULT_UNKNOWN; |
| 87 ready_results[1] = MOJO_RESULT_UNKNOWN; |
| 88 wait_set.Wait(&num_ready_handles, ready_handles, ready_results, hss); |
| 89 |
| 90 EXPECT_EQ(1u, num_ready_handles); |
| 91 EXPECT_EQ(p.handle0.get(), ready_handles[0]); |
| 92 EXPECT_EQ(MOJO_RESULT_OK, ready_results[0]); |
| 93 EXPECT_TRUE(hss[0].readable() && hss[0].writable() && !hss[0].peer_closed()); |
| 94 |
| 95 // Now wait on both of them. |
| 96 wait_set.AddHandle(p.handle1.get(), MOJO_HANDLE_SIGNAL_READABLE); |
| 97 |
| 98 num_ready_handles = 2; |
| 99 ready_results[0] = MOJO_RESULT_UNKNOWN; |
| 100 ready_results[1] = MOJO_RESULT_UNKNOWN; |
| 101 wait_set.Wait(&num_ready_handles, ready_handles, ready_results, hss); |
| 102 EXPECT_EQ(2u, num_ready_handles); |
| 103 EXPECT_TRUE((ready_handles[0] == p.handle0.get() && |
| 104 ready_handles[1] == p.handle1.get()) || |
| 105 (ready_handles[0] == p.handle1.get() && |
| 106 ready_handles[1] == p.handle0.get())); |
| 107 EXPECT_EQ(MOJO_RESULT_OK, ready_results[0]); |
| 108 EXPECT_EQ(MOJO_RESULT_OK, ready_results[1]); |
| 109 EXPECT_TRUE(hss[0].readable() && hss[0].writable() && !hss[0].peer_closed()); |
| 110 EXPECT_TRUE(hss[1].readable() && hss[1].writable() && !hss[1].peer_closed()); |
| 111 |
| 112 // Wait on both again, but with only enough output space for one result. |
| 113 num_ready_handles = 1; |
| 114 ready_results[0] = MOJO_RESULT_UNKNOWN; |
| 115 wait_set.Wait(&num_ready_handles, ready_handles, ready_results, hss); |
| 116 EXPECT_EQ(1u, num_ready_handles); |
| 117 EXPECT_TRUE(ready_handles[0] == p.handle0.get() || |
| 118 ready_handles[0] == p.handle1.get()); |
| 119 EXPECT_EQ(MOJO_RESULT_OK, ready_results[0]); |
| 120 |
| 121 // Remove the ready handle from the set and wait one more time. |
| 122 EXPECT_EQ(MOJO_RESULT_OK, wait_set.RemoveHandle(ready_handles[0])); |
| 123 |
| 124 num_ready_handles = 1; |
| 125 ready_results[0] = MOJO_RESULT_UNKNOWN; |
| 126 wait_set.Wait(&num_ready_handles, ready_handles, ready_results, hss); |
| 127 EXPECT_EQ(1u, num_ready_handles); |
| 128 EXPECT_TRUE(ready_handles[0] == p.handle0.get() || |
| 129 ready_handles[0] == p.handle1.get()); |
| 130 EXPECT_EQ(MOJO_RESULT_OK, ready_results[0]); |
| 131 |
| 132 EXPECT_EQ(MOJO_RESULT_OK, wait_set.RemoveHandle(ready_handles[0])); |
| 133 |
| 134 // The wait set should be empty now. Nothing to wait on. |
| 135 num_ready_handles = 2; |
| 136 wait_set.Wait(&num_ready_handles, ready_handles, ready_results); |
| 137 EXPECT_EQ(0u, num_ready_handles); |
| 138 } |
| 139 |
| 140 TEST_F(WaitSetTest, Unsatisfiable) { |
| 141 MessagePipe p, q; |
| 142 WaitSet wait_set; |
| 143 |
| 144 wait_set.AddHandle(q.handle0.get(), MOJO_HANDLE_SIGNAL_READABLE); |
| 145 wait_set.AddHandle(q.handle1.get(), MOJO_HANDLE_SIGNAL_READABLE); |
| 146 wait_set.AddHandle(p.handle0.get(), MOJO_HANDLE_SIGNAL_READABLE); |
| 147 |
| 148 size_t num_ready_handles = 2; |
| 149 Handle ready_handles[2]; |
| 150 MojoResult ready_results[2] = {MOJO_RESULT_UNKNOWN, MOJO_RESULT_UNKNOWN}; |
| 151 |
| 152 p.handle1.reset(); |
| 153 wait_set.Wait(&num_ready_handles, ready_handles, ready_results); |
| 154 EXPECT_EQ(1u, num_ready_handles); |
| 155 EXPECT_EQ(p.handle0.get(), ready_handles[0]); |
| 156 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, ready_results[0]); |
| 157 } |
| 158 |
| 159 TEST_F(WaitSetTest, CloseWhileWaiting) { |
| 160 MessagePipe p; |
| 161 WaitSet wait_set; |
| 162 |
| 163 wait_set.AddHandle(p.handle0.get(), MOJO_HANDLE_SIGNAL_READABLE); |
| 164 |
| 165 const Handle handle0_value = p.handle0.get(); |
| 166 ThreadedRunner close_after_delay(base::Bind( |
| 167 [](ScopedMessagePipeHandle* handle) { |
| 168 // Wait a little while, then close the handle. |
| 169 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(200)); |
| 170 handle->reset(); |
| 171 }, |
| 172 &p.handle0)); |
| 173 close_after_delay.Start(); |
| 174 |
| 175 size_t num_ready_handles = 2; |
| 176 Handle ready_handles[2]; |
| 177 MojoResult ready_results[2] = {MOJO_RESULT_UNKNOWN, MOJO_RESULT_UNKNOWN}; |
| 178 wait_set.Wait(&num_ready_handles, ready_handles, ready_results); |
| 179 EXPECT_EQ(1u, num_ready_handles); |
| 180 EXPECT_EQ(handle0_value, ready_handles[0]); |
| 181 EXPECT_EQ(MOJO_RESULT_CANCELLED, ready_results[0]); |
| 182 |
| 183 EXPECT_EQ(MOJO_RESULT_NOT_FOUND, wait_set.RemoveHandle(handle0_value)); |
| 184 } |
| 185 |
| 186 TEST_F(WaitSetTest, CloseBeforeWaiting) { |
| 187 MessagePipe p; |
| 188 WaitSet wait_set; |
| 189 |
| 190 wait_set.AddHandle(p.handle0.get(), MOJO_HANDLE_SIGNAL_READABLE); |
| 191 wait_set.AddHandle(p.handle1.get(), MOJO_HANDLE_SIGNAL_READABLE); |
| 192 |
| 193 Handle handle0_value = p.handle0.get(); |
| 194 Handle handle1_value = p.handle1.get(); |
| 195 |
| 196 p.handle0.reset(); |
| 197 p.handle1.reset(); |
| 198 |
| 199 // Ensure that the WaitSet user is always made aware of all cancellations even |
| 200 // if they happen while not waiting, or they have to be returned over the span |
| 201 // of multiple Wait() calls due to insufficient output storage. |
| 202 |
| 203 size_t num_ready_handles = 1; |
| 204 Handle ready_handle; |
| 205 MojoResult ready_result = MOJO_RESULT_UNKNOWN; |
| 206 wait_set.Wait(&num_ready_handles, &ready_handle, &ready_result); |
| 207 EXPECT_EQ(1u, num_ready_handles); |
| 208 EXPECT_TRUE(ready_handle == handle0_value || ready_handle == handle1_value); |
| 209 EXPECT_EQ(MOJO_RESULT_CANCELLED, ready_result); |
| 210 EXPECT_EQ(MOJO_RESULT_NOT_FOUND, wait_set.RemoveHandle(handle0_value)); |
| 211 |
| 212 wait_set.Wait(&num_ready_handles, &ready_handle, &ready_result); |
| 213 EXPECT_EQ(1u, num_ready_handles); |
| 214 EXPECT_TRUE(ready_handle == handle0_value || ready_handle == handle1_value); |
| 215 EXPECT_EQ(MOJO_RESULT_CANCELLED, ready_result); |
| 216 EXPECT_EQ(MOJO_RESULT_NOT_FOUND, wait_set.RemoveHandle(handle0_value)); |
| 217 |
| 218 // Nothing more to wait on. |
| 219 wait_set.Wait(&num_ready_handles, &ready_handle, &ready_result); |
| 220 EXPECT_EQ(0u, num_ready_handles); |
| 221 } |
| 222 |
| 223 TEST_F(WaitSetTest, SatisfiedThenUnsatisfied) { |
| 224 MessagePipe p; |
| 225 WaitSet wait_set; |
| 226 |
| 227 wait_set.AddHandle(p.handle0.get(), MOJO_HANDLE_SIGNAL_READABLE); |
| 228 wait_set.AddHandle(p.handle1.get(), MOJO_HANDLE_SIGNAL_READABLE); |
| 229 |
| 230 const char kTestMessage1[] = "testing testing testing"; |
| 231 WriteMessage(p.handle0, kTestMessage1); |
| 232 |
| 233 size_t num_ready_handles = 2; |
| 234 Handle ready_handles[2]; |
| 235 MojoResult ready_results[2] = {MOJO_RESULT_UNKNOWN, MOJO_RESULT_UNKNOWN}; |
| 236 wait_set.Wait(&num_ready_handles, ready_handles, ready_results); |
| 237 EXPECT_EQ(1u, num_ready_handles); |
| 238 EXPECT_EQ(p.handle1.get(), ready_handles[0]); |
| 239 EXPECT_EQ(MOJO_RESULT_OK, ready_results[0]); |
| 240 |
| 241 EXPECT_EQ(kTestMessage1, ReadMessage(p.handle1)); |
| 242 |
| 243 ThreadedRunner write_after_delay(base::Bind( |
| 244 [](ScopedMessagePipeHandle* handle) { |
| 245 // Wait a little while, then write a message. |
| 246 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(200)); |
| 247 WriteMessage(*handle, "wakey wakey"); |
| 248 }, |
| 249 &p.handle1)); |
| 250 write_after_delay.Start(); |
| 251 |
| 252 num_ready_handles = 2; |
| 253 wait_set.Wait(&num_ready_handles, ready_handles, ready_results); |
| 254 EXPECT_EQ(1u, num_ready_handles); |
| 255 EXPECT_EQ(p.handle0.get(), ready_handles[0]); |
| 256 EXPECT_EQ(MOJO_RESULT_OK, ready_results[0]); |
| 257 } |
| 258 |
| 259 } // namespace |
| 260 } // namespace mojo |
OLD | NEW |