• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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