OLD | NEW |
| (Empty) |
1 // Copyright 2015 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/edk/system/wait_set_dispatcher.h" | |
6 | |
7 #include <stddef.h> | |
8 #include <stdint.h> | |
9 | |
10 #include <algorithm> | |
11 | |
12 #include "base/macros.h" | |
13 #include "base/memory/ref_counted.h" | |
14 #include "mojo/edk/embedder/embedder_internal.h" | |
15 #include "mojo/edk/system/core.h" | |
16 #include "mojo/edk/system/message_for_transit.h" | |
17 #include "mojo/edk/system/message_pipe_dispatcher.h" | |
18 #include "mojo/edk/system/request_context.h" | |
19 #include "mojo/edk/system/test_utils.h" | |
20 #include "mojo/edk/system/waiter.h" | |
21 #include "testing/gtest/include/gtest/gtest.h" | |
22 | |
23 namespace mojo { | |
24 namespace edk { | |
25 namespace { | |
26 | |
27 class WaitSetDispatcherTest : public ::testing::Test { | |
28 public: | |
29 WaitSetDispatcherTest() {} | |
30 ~WaitSetDispatcherTest() override {} | |
31 | |
32 void SetUp() override { | |
33 CreateMessagePipe(&dispatcher0_, &dispatcher1_); | |
34 } | |
35 | |
36 void TearDown() override { | |
37 for (auto& d : dispatchers_to_close_) | |
38 d->Close(); | |
39 } | |
40 | |
41 MojoResult GetOneReadyDispatcher( | |
42 const scoped_refptr<WaitSetDispatcher>& wait_set, | |
43 scoped_refptr<Dispatcher>* ready_dispatcher, | |
44 uintptr_t* context) { | |
45 uint32_t count = 1; | |
46 MojoResult dispatcher_result = MOJO_RESULT_UNKNOWN; | |
47 DispatcherVector dispatchers; | |
48 MojoResult result = wait_set->GetReadyDispatchers( | |
49 &count, &dispatchers, &dispatcher_result, context); | |
50 if (result == MOJO_RESULT_OK) { | |
51 CHECK_EQ(1u, dispatchers.size()); | |
52 *ready_dispatcher = dispatchers[0]; | |
53 return dispatcher_result; | |
54 } | |
55 return result; | |
56 } | |
57 | |
58 void CreateMessagePipe(scoped_refptr<MessagePipeDispatcher>* d0, | |
59 scoped_refptr<MessagePipeDispatcher>* d1) { | |
60 MojoHandle h0, h1; | |
61 EXPECT_EQ(MOJO_RESULT_OK, MojoCreateMessagePipe(nullptr, &h0, &h1)); | |
62 | |
63 Core* core = mojo::edk::internal::g_core; | |
64 *d0 = scoped_refptr<MessagePipeDispatcher>( | |
65 static_cast<MessagePipeDispatcher*>(core->GetDispatcher(h0).get())); | |
66 *d1 = scoped_refptr<MessagePipeDispatcher>( | |
67 static_cast<MessagePipeDispatcher*>(core->GetDispatcher(h1).get())); | |
68 pipe_id_generator_++; | |
69 | |
70 dispatchers_to_close_.push_back(*d0); | |
71 dispatchers_to_close_.push_back(*d1); | |
72 } | |
73 | |
74 void CloseOnShutdown(const scoped_refptr<Dispatcher>& dispatcher) { | |
75 dispatchers_to_close_.push_back(dispatcher); | |
76 } | |
77 | |
78 void WriteMessage(MessagePipeDispatcher* dispatcher, | |
79 const void* bytes, | |
80 size_t num_bytes) { | |
81 Core* core = mojo::edk::internal::g_core; | |
82 MojoMessageHandle msg; | |
83 ASSERT_EQ(MOJO_RESULT_OK, | |
84 core->AllocMessage(static_cast<uint32_t>(num_bytes), nullptr, 0, | |
85 MOJO_ALLOC_MESSAGE_FLAG_NONE, &msg)); | |
86 void* buffer; | |
87 ASSERT_EQ(MOJO_RESULT_OK, core->GetMessageBuffer(msg, &buffer)); | |
88 memcpy(buffer, bytes, num_bytes); | |
89 | |
90 std::unique_ptr<MessageForTransit> message( | |
91 reinterpret_cast<MessageForTransit*>(msg)); | |
92 ASSERT_EQ(MOJO_RESULT_OK, | |
93 dispatcher->WriteMessage(std::move(message), | |
94 MOJO_WRITE_MESSAGE_FLAG_NONE)); | |
95 } | |
96 | |
97 void ReadMessage(MessagePipeDispatcher* dispatcher, | |
98 void* bytes, | |
99 uint32_t* num_bytes) { | |
100 std::unique_ptr<MessageForTransit> message; | |
101 ASSERT_EQ(MOJO_RESULT_OK, | |
102 dispatcher->ReadMessage(&message, num_bytes, nullptr, 0, | |
103 MOJO_READ_MESSAGE_FLAG_NONE, false)); | |
104 memcpy(bytes, message->bytes(), *num_bytes); | |
105 } | |
106 | |
107 protected: | |
108 scoped_refptr<MessagePipeDispatcher> dispatcher0_; | |
109 scoped_refptr<MessagePipeDispatcher> dispatcher1_; | |
110 | |
111 private: | |
112 // We keep an active RequestContext for the duration of each test. It's unused | |
113 // since these tests don't rely on the MojoWatch API. | |
114 const RequestContext request_context_; | |
115 | |
116 static uint64_t pipe_id_generator_; | |
117 DispatcherVector dispatchers_to_close_; | |
118 | |
119 DISALLOW_COPY_AND_ASSIGN(WaitSetDispatcherTest); | |
120 }; | |
121 | |
122 // static | |
123 uint64_t WaitSetDispatcherTest::pipe_id_generator_ = 1; | |
124 | |
125 TEST_F(WaitSetDispatcherTest, Basic) { | |
126 scoped_refptr<WaitSetDispatcher> wait_set = new WaitSetDispatcher(); | |
127 CloseOnShutdown(wait_set); | |
128 ASSERT_EQ(MOJO_RESULT_OK, | |
129 wait_set->AddWaitingDispatcher(dispatcher0_, | |
130 MOJO_HANDLE_SIGNAL_READABLE, 1)); | |
131 ASSERT_EQ(MOJO_RESULT_OK, | |
132 wait_set->AddWaitingDispatcher(dispatcher1_, | |
133 MOJO_HANDLE_SIGNAL_WRITABLE, 2)); | |
134 | |
135 Waiter w; | |
136 uintptr_t context = 0; | |
137 w.Init(); | |
138 HandleSignalsState hss; | |
139 // |dispatcher1_| should already be writable. | |
140 EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, | |
141 wait_set->AddAwakable(&w, MOJO_HANDLE_SIGNAL_READABLE, 0, &hss)); | |
142 EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); | |
143 EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); | |
144 | |
145 scoped_refptr<Dispatcher> woken_dispatcher; | |
146 EXPECT_EQ(MOJO_RESULT_OK, | |
147 GetOneReadyDispatcher(wait_set, &woken_dispatcher, &context)); | |
148 EXPECT_EQ(dispatcher1_, woken_dispatcher); | |
149 EXPECT_EQ(2u, context); | |
150 // If a ready dispatcher isn't removed, it will continue to be returned. | |
151 EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, | |
152 wait_set->AddAwakable(&w, MOJO_HANDLE_SIGNAL_READABLE, 0, &hss)); | |
153 woken_dispatcher = nullptr; | |
154 context = 0; | |
155 EXPECT_EQ(MOJO_RESULT_OK, | |
156 GetOneReadyDispatcher(wait_set, &woken_dispatcher, &context)); | |
157 EXPECT_EQ(dispatcher1_, woken_dispatcher); | |
158 EXPECT_EQ(2u, context); | |
159 ASSERT_EQ(MOJO_RESULT_OK, wait_set->RemoveWaitingDispatcher(dispatcher1_)); | |
160 | |
161 // No ready dispatcher. | |
162 hss = HandleSignalsState(); | |
163 EXPECT_EQ(MOJO_RESULT_OK, | |
164 wait_set->AddAwakable(&w, MOJO_HANDLE_SIGNAL_READABLE, 0, &hss)); | |
165 EXPECT_FALSE(hss.satisfies(MOJO_HANDLE_SIGNAL_READABLE)); | |
166 EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, w.Wait(0, nullptr)); | |
167 EXPECT_EQ(MOJO_RESULT_SHOULD_WAIT, | |
168 GetOneReadyDispatcher(wait_set, &woken_dispatcher, nullptr)); | |
169 | |
170 // Write to |dispatcher1_|, which should make |dispatcher0_| readable. | |
171 char buffer[] = "abcd"; | |
172 w.Init(); | |
173 WriteMessage(dispatcher1_.get(), buffer, sizeof(buffer)); | |
174 EXPECT_EQ(MOJO_RESULT_OK, w.Wait(MOJO_DEADLINE_INDEFINITE, nullptr)); | |
175 woken_dispatcher = nullptr; | |
176 context = 0; | |
177 EXPECT_EQ(MOJO_RESULT_OK, | |
178 GetOneReadyDispatcher(wait_set, &woken_dispatcher, &context)); | |
179 EXPECT_EQ(dispatcher0_, woken_dispatcher); | |
180 EXPECT_EQ(1u, context); | |
181 | |
182 // Again, if a ready dispatcher isn't removed, it will continue to be | |
183 // returned. | |
184 woken_dispatcher = nullptr; | |
185 EXPECT_EQ(MOJO_RESULT_OK, | |
186 GetOneReadyDispatcher(wait_set, &woken_dispatcher, nullptr)); | |
187 EXPECT_EQ(dispatcher0_, woken_dispatcher); | |
188 | |
189 wait_set->RemoveAwakable(&w, nullptr); | |
190 } | |
191 | |
192 TEST_F(WaitSetDispatcherTest, HandleWithoutRemoving) { | |
193 scoped_refptr<WaitSetDispatcher> wait_set = new WaitSetDispatcher(); | |
194 CloseOnShutdown(wait_set); | |
195 ASSERT_EQ(MOJO_RESULT_OK, | |
196 wait_set->AddWaitingDispatcher(dispatcher0_, | |
197 MOJO_HANDLE_SIGNAL_READABLE, 1)); | |
198 | |
199 Waiter w; | |
200 uintptr_t context = 0; | |
201 w.Init(); | |
202 HandleSignalsState hss; | |
203 // No ready dispatcher. | |
204 hss = HandleSignalsState(); | |
205 EXPECT_EQ(MOJO_RESULT_OK, | |
206 wait_set->AddAwakable(&w, MOJO_HANDLE_SIGNAL_READABLE, 0, &hss)); | |
207 EXPECT_FALSE(hss.satisfies(MOJO_HANDLE_SIGNAL_READABLE)); | |
208 EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, w.Wait(0, nullptr)); | |
209 scoped_refptr<Dispatcher> woken_dispatcher; | |
210 EXPECT_EQ(MOJO_RESULT_SHOULD_WAIT, | |
211 GetOneReadyDispatcher(wait_set, &woken_dispatcher, nullptr)); | |
212 | |
213 // The tested behaviour below should be repeatable. | |
214 for (size_t i = 0; i < 3; i++) { | |
215 // Write to |dispatcher1_|, which should make |dispatcher0_| readable. | |
216 char buffer[] = "abcd"; | |
217 w.Init(); | |
218 WriteMessage(dispatcher1_.get(), buffer, sizeof(buffer)); | |
219 EXPECT_EQ(MOJO_RESULT_OK, w.Wait(MOJO_DEADLINE_INDEFINITE, nullptr)); | |
220 woken_dispatcher = nullptr; | |
221 context = 0; | |
222 EXPECT_EQ(MOJO_RESULT_OK, | |
223 GetOneReadyDispatcher(wait_set, &woken_dispatcher, &context)); | |
224 EXPECT_EQ(dispatcher0_, woken_dispatcher); | |
225 EXPECT_EQ(1u, context); | |
226 | |
227 // Read from |dispatcher0_| which should change it's state to non-readable. | |
228 char read_buffer[sizeof(buffer) + 5]; | |
229 uint32_t num_bytes = sizeof(read_buffer); | |
230 ReadMessage(dispatcher0_.get(), read_buffer, &num_bytes); | |
231 EXPECT_EQ(sizeof(buffer), num_bytes); | |
232 | |
233 // No dispatchers are ready. | |
234 w.Init(); | |
235 woken_dispatcher = nullptr; | |
236 context = 0; | |
237 EXPECT_EQ(MOJO_RESULT_SHOULD_WAIT, | |
238 GetOneReadyDispatcher(wait_set, &woken_dispatcher, &context)); | |
239 EXPECT_FALSE(woken_dispatcher); | |
240 EXPECT_EQ(0u, context); | |
241 EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, w.Wait(0, nullptr)); | |
242 } | |
243 | |
244 wait_set->RemoveAwakable(&w, nullptr); | |
245 } | |
246 | |
247 TEST_F(WaitSetDispatcherTest, MultipleReady) { | |
248 scoped_refptr<WaitSetDispatcher> wait_set = new WaitSetDispatcher(); | |
249 CloseOnShutdown(wait_set); | |
250 | |
251 scoped_refptr<MessagePipeDispatcher> mp1_dispatcher0; | |
252 scoped_refptr<MessagePipeDispatcher> mp1_dispatcher1; | |
253 CreateMessagePipe(&mp1_dispatcher0, &mp1_dispatcher1); | |
254 | |
255 ASSERT_EQ(MOJO_RESULT_OK, | |
256 wait_set->AddWaitingDispatcher(dispatcher0_, | |
257 MOJO_HANDLE_SIGNAL_READABLE, 0)); | |
258 ASSERT_EQ(MOJO_RESULT_OK, | |
259 wait_set->AddWaitingDispatcher(dispatcher1_, | |
260 MOJO_HANDLE_SIGNAL_WRITABLE, 0)); | |
261 ASSERT_EQ(MOJO_RESULT_OK, | |
262 wait_set->AddWaitingDispatcher(mp1_dispatcher0, | |
263 MOJO_HANDLE_SIGNAL_WRITABLE, 0)); | |
264 ASSERT_EQ(MOJO_RESULT_OK, | |
265 wait_set->AddWaitingDispatcher(mp1_dispatcher1, | |
266 MOJO_HANDLE_SIGNAL_WRITABLE, 0)); | |
267 | |
268 Waiter w; | |
269 w.Init(); | |
270 HandleSignalsState hss; | |
271 // The three writable dispatchers should be ready. | |
272 EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, | |
273 wait_set->AddAwakable(&w, MOJO_HANDLE_SIGNAL_READABLE, 0, &hss)); | |
274 EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); | |
275 EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); | |
276 | |
277 scoped_refptr<Dispatcher> woken_dispatcher; | |
278 EXPECT_EQ(MOJO_RESULT_OK, | |
279 GetOneReadyDispatcher(wait_set, &woken_dispatcher, nullptr)); | |
280 // Don't know which dispatcher was returned, just that it was one of the | |
281 // writable ones. | |
282 EXPECT_TRUE(woken_dispatcher == dispatcher1_ || | |
283 woken_dispatcher == mp1_dispatcher0 || | |
284 woken_dispatcher == mp1_dispatcher1); | |
285 | |
286 DispatcherVector dispatchers_vector; | |
287 uint32_t count = 4; | |
288 MojoResult results[4]; | |
289 EXPECT_EQ(MOJO_RESULT_OK, | |
290 wait_set->GetReadyDispatchers(&count, | |
291 &dispatchers_vector, | |
292 results, | |
293 nullptr)); | |
294 EXPECT_EQ(3u, count); | |
295 std::sort(dispatchers_vector.begin(), dispatchers_vector.end()); | |
296 DispatcherVector expected_dispatchers; | |
297 expected_dispatchers.push_back(dispatcher1_); | |
298 expected_dispatchers.push_back(mp1_dispatcher0); | |
299 expected_dispatchers.push_back(mp1_dispatcher1); | |
300 std::sort(expected_dispatchers.begin(), expected_dispatchers.end()); | |
301 EXPECT_EQ(expected_dispatchers, dispatchers_vector); | |
302 | |
303 // If a ready dispatcher isn't removed, it will continue to be returned. | |
304 EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, | |
305 wait_set->AddAwakable(&w, MOJO_HANDLE_SIGNAL_READABLE, 0, &hss)); | |
306 EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); | |
307 EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); | |
308 count = 4; | |
309 dispatchers_vector.clear(); | |
310 EXPECT_EQ(MOJO_RESULT_OK, | |
311 wait_set->GetReadyDispatchers(&count, | |
312 &dispatchers_vector, | |
313 results, | |
314 nullptr)); | |
315 EXPECT_EQ(3u, count); | |
316 std::sort(dispatchers_vector.begin(), dispatchers_vector.end()); | |
317 EXPECT_EQ(expected_dispatchers, dispatchers_vector); | |
318 | |
319 // Remove one. It shouldn't be returned any longer. | |
320 ASSERT_EQ(MOJO_RESULT_OK, | |
321 wait_set->RemoveWaitingDispatcher(expected_dispatchers.back())); | |
322 expected_dispatchers.pop_back(); | |
323 EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, | |
324 wait_set->AddAwakable(&w, MOJO_HANDLE_SIGNAL_READABLE, 0, &hss)); | |
325 EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); | |
326 EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); | |
327 count = 4; | |
328 dispatchers_vector.clear(); | |
329 EXPECT_EQ(MOJO_RESULT_OK, | |
330 wait_set->GetReadyDispatchers(&count, | |
331 &dispatchers_vector, | |
332 results, | |
333 nullptr)); | |
334 EXPECT_EQ(2u, count); | |
335 std::sort(dispatchers_vector.begin(), dispatchers_vector.end()); | |
336 EXPECT_EQ(expected_dispatchers, dispatchers_vector); | |
337 | |
338 // Write to |dispatcher1_|, which should make |dispatcher0_| readable. | |
339 char buffer[] = "abcd"; | |
340 w.Init(); | |
341 WriteMessage(dispatcher1_.get(), buffer, sizeof(buffer)); | |
342 { | |
343 Waiter mp_w; | |
344 mp_w.Init(); | |
345 // Wait for |dispatcher0_| to be readable. | |
346 if (dispatcher0_->AddAwakable(&mp_w, MOJO_HANDLE_SIGNAL_READABLE, 0, | |
347 nullptr) == MOJO_RESULT_OK) { | |
348 EXPECT_EQ(MOJO_RESULT_OK, mp_w.Wait(MOJO_DEADLINE_INDEFINITE, 0)); | |
349 dispatcher0_->RemoveAwakable(&mp_w, nullptr); | |
350 } | |
351 } | |
352 expected_dispatchers.push_back(dispatcher0_); | |
353 std::sort(expected_dispatchers.begin(), expected_dispatchers.end()); | |
354 EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, | |
355 wait_set->AddAwakable(&w, MOJO_HANDLE_SIGNAL_READABLE, 0, &hss)); | |
356 EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); | |
357 EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); | |
358 count = 4; | |
359 dispatchers_vector.clear(); | |
360 EXPECT_EQ(MOJO_RESULT_OK, | |
361 wait_set->GetReadyDispatchers(&count, | |
362 &dispatchers_vector, | |
363 results, | |
364 nullptr)); | |
365 EXPECT_EQ(3u, count); | |
366 std::sort(dispatchers_vector.begin(), dispatchers_vector.end()); | |
367 EXPECT_EQ(expected_dispatchers, dispatchers_vector); | |
368 } | |
369 | |
370 TEST_F(WaitSetDispatcherTest, InvalidParams) { | |
371 scoped_refptr<WaitSetDispatcher> wait_set = new WaitSetDispatcher(); | |
372 | |
373 // Can't add a wait set to itself. | |
374 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, | |
375 wait_set->AddWaitingDispatcher(wait_set, | |
376 MOJO_HANDLE_SIGNAL_READABLE, 0)); | |
377 | |
378 // Can't add twice. | |
379 EXPECT_EQ(MOJO_RESULT_OK, | |
380 wait_set->AddWaitingDispatcher(dispatcher0_, | |
381 MOJO_HANDLE_SIGNAL_READABLE, 0)); | |
382 EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, | |
383 wait_set->AddWaitingDispatcher(dispatcher0_, | |
384 MOJO_HANDLE_SIGNAL_READABLE, 0)); | |
385 | |
386 // Remove a dispatcher that wasn't added. | |
387 EXPECT_EQ(MOJO_RESULT_NOT_FOUND, | |
388 wait_set->RemoveWaitingDispatcher(dispatcher1_)); | |
389 | |
390 // Add to a closed wait set. | |
391 wait_set->Close(); | |
392 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, | |
393 wait_set->AddWaitingDispatcher(dispatcher0_, | |
394 MOJO_HANDLE_SIGNAL_READABLE, 0)); | |
395 } | |
396 | |
397 TEST_F(WaitSetDispatcherTest, NotSatisfiable) { | |
398 scoped_refptr<WaitSetDispatcher> wait_set = new WaitSetDispatcher(); | |
399 CloseOnShutdown(wait_set); | |
400 | |
401 // Wait sets can only satisfy MOJO_HANDLE_SIGNAL_READABLE. | |
402 Waiter w; | |
403 w.Init(); | |
404 HandleSignalsState hss; | |
405 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, | |
406 wait_set->AddAwakable(&w, MOJO_HANDLE_SIGNAL_WRITABLE, 0, &hss)); | |
407 EXPECT_EQ(MOJO_HANDLE_SIGNAL_NONE, hss.satisfied_signals); | |
408 EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); | |
409 | |
410 hss = HandleSignalsState(); | |
411 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, | |
412 wait_set->AddAwakable(&w, MOJO_HANDLE_SIGNAL_PEER_CLOSED, 0, &hss)); | |
413 EXPECT_EQ(MOJO_HANDLE_SIGNAL_NONE, hss.satisfied_signals); | |
414 EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); | |
415 } | |
416 | |
417 TEST_F(WaitSetDispatcherTest, ClosedDispatchers) { | |
418 scoped_refptr<WaitSetDispatcher> wait_set = new WaitSetDispatcher(); | |
419 CloseOnShutdown(wait_set); | |
420 | |
421 Waiter w; | |
422 w.Init(); | |
423 HandleSignalsState hss; | |
424 // A dispatcher that was added and then closed will be cancelled. | |
425 ASSERT_EQ(MOJO_RESULT_OK, | |
426 wait_set->AddWaitingDispatcher(dispatcher0_, | |
427 MOJO_HANDLE_SIGNAL_READABLE, 0)); | |
428 EXPECT_EQ(MOJO_RESULT_OK, | |
429 wait_set->AddAwakable(&w, MOJO_HANDLE_SIGNAL_READABLE, 0, &hss)); | |
430 dispatcher0_->Close(); | |
431 EXPECT_EQ(MOJO_RESULT_OK, w.Wait(MOJO_DEADLINE_INDEFINITE, nullptr)); | |
432 EXPECT_TRUE( | |
433 wait_set->GetHandleSignalsState().satisfies(MOJO_HANDLE_SIGNAL_READABLE)); | |
434 scoped_refptr<Dispatcher> woken_dispatcher; | |
435 EXPECT_EQ(MOJO_RESULT_CANCELLED, | |
436 GetOneReadyDispatcher(wait_set, &woken_dispatcher, nullptr)); | |
437 EXPECT_EQ(dispatcher0_, woken_dispatcher); | |
438 | |
439 // Dispatcher will be implicitly removed because it may be impossible to | |
440 // remove explicitly. | |
441 woken_dispatcher = nullptr; | |
442 EXPECT_EQ(MOJO_RESULT_SHOULD_WAIT, | |
443 GetOneReadyDispatcher(wait_set, &woken_dispatcher, nullptr)); | |
444 EXPECT_EQ(MOJO_RESULT_NOT_FOUND, | |
445 wait_set->RemoveWaitingDispatcher(dispatcher0_)); | |
446 | |
447 // A dispatcher that's not satisfiable should give an error. | |
448 w.Init(); | |
449 EXPECT_EQ(MOJO_RESULT_OK, | |
450 wait_set->AddWaitingDispatcher(dispatcher1_, | |
451 MOJO_HANDLE_SIGNAL_READABLE, 0)); | |
452 EXPECT_EQ(MOJO_RESULT_OK, w.Wait(MOJO_DEADLINE_INDEFINITE, nullptr)); | |
453 EXPECT_TRUE( | |
454 wait_set->GetHandleSignalsState().satisfies(MOJO_HANDLE_SIGNAL_READABLE)); | |
455 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, | |
456 GetOneReadyDispatcher(wait_set, &woken_dispatcher, nullptr)); | |
457 EXPECT_EQ(dispatcher1_, woken_dispatcher); | |
458 | |
459 wait_set->RemoveAwakable(&w, nullptr); | |
460 } | |
461 | |
462 TEST_F(WaitSetDispatcherTest, NestedSets) { | |
463 scoped_refptr<WaitSetDispatcher> wait_set = new WaitSetDispatcher(); | |
464 CloseOnShutdown(wait_set); | |
465 scoped_refptr<WaitSetDispatcher> nested_wait_set = new WaitSetDispatcher(); | |
466 CloseOnShutdown(nested_wait_set); | |
467 | |
468 Waiter w; | |
469 w.Init(); | |
470 EXPECT_EQ(MOJO_RESULT_OK, | |
471 wait_set->AddWaitingDispatcher(nested_wait_set, | |
472 MOJO_HANDLE_SIGNAL_READABLE, 0)); | |
473 EXPECT_EQ(MOJO_RESULT_OK, | |
474 wait_set->AddAwakable(&w, MOJO_HANDLE_SIGNAL_READABLE, 0, nullptr)); | |
475 EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, w.Wait(0, nullptr)); | |
476 | |
477 // Writable signal is immediately satisfied by the message pipe. | |
478 w.Init(); | |
479 EXPECT_EQ(MOJO_RESULT_OK, | |
480 nested_wait_set->AddWaitingDispatcher( | |
481 dispatcher0_, MOJO_HANDLE_SIGNAL_WRITABLE, 0)); | |
482 EXPECT_EQ(MOJO_RESULT_OK, w.Wait(0, nullptr)); | |
483 scoped_refptr<Dispatcher> woken_dispatcher; | |
484 EXPECT_EQ(MOJO_RESULT_OK, | |
485 GetOneReadyDispatcher(wait_set, &woken_dispatcher, nullptr)); | |
486 EXPECT_EQ(nested_wait_set, woken_dispatcher); | |
487 | |
488 wait_set->RemoveAwakable(&w, nullptr); | |
489 } | |
490 | |
491 } // namespace | |
492 } // namespace edk | |
493 } // namespace mojo | |
OLD | NEW |