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
WriteMessage(const ScopedMessagePipeHandle & handle,const base::StringPiece & message)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
ReadMessage(const ScopedMessagePipeHandle & handle)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:
ThreadedRunner(const base::Closure & callback)45 explicit ThreadedRunner(const base::Closure& callback)
46 : SimpleThread("ThreadedRunner"), callback_(callback) {}
~ThreadedRunner()47 ~ThreadedRunner() override { Join(); }
48
Run()49 void Run() override { callback_.Run(); }
50
51 private:
52 const base::Closure callback_;
53
54 DISALLOW_COPY_AND_ASSIGN(ThreadedRunner);
55 };
56
TEST_F(WaitTest,InvalidArguments)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
TEST_F(WaitTest,Basic)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
TEST_F(WaitTest,DelayedWrite)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
TEST_F(WaitTest,DelayedPeerClosure)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
TEST_F(WaitTest,CloseWhileWaiting)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
TEST_F(WaitManyTest,Basic)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
TEST_F(WaitManyTest,CloseWhileWaiting)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
TEST_F(WaitManyTest,DelayedWrite)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
TEST_F(WaitManyTest,DelayedPeerClosure)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