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 <stdint.h>
6
7 #include <map>
8 #include <memory>
9 #include <set>
10
11 #include "base/bind.h"
12 #include "base/callback.h"
13 #include "base/macros.h"
14 #include "base/memory/ptr_util.h"
15 #include "base/rand_util.h"
16 #include "base/synchronization/waitable_event.h"
17 #include "base/test/bind_test_util.h"
18 #include "base/threading/platform_thread.h"
19 #include "base/threading/simple_thread.h"
20 #include "base/time/time.h"
21 #include "mojo/core/test/mojo_test_base.h"
22 #include "mojo/public/c/system/data_pipe.h"
23 #include "mojo/public/c/system/trap.h"
24 #include "mojo/public/c/system/types.h"
25 #include "testing/gtest/include/gtest/gtest.h"
26
27 namespace mojo {
28 namespace core {
29 namespace {
30
31 using TrapTest = test::MojoTestBase;
32
33 class TriggerHelper {
34 public:
35 using ContextCallback = base::RepeatingCallback<void(const MojoTrapEvent&)>;
36
TriggerHelper()37 TriggerHelper() {}
~TriggerHelper()38 ~TriggerHelper() {}
39
CreateTrap(MojoHandle * handle)40 MojoResult CreateTrap(MojoHandle* handle) {
41 return MojoCreateTrap(&Notify, nullptr, handle);
42 }
43
44 template <typename Handler>
CreateContext(Handler handler)45 uintptr_t CreateContext(Handler handler) {
46 return CreateContextWithCancel(handler, [] {});
47 }
48
49 template <typename Handler, typename CancelHandler>
CreateContextWithCancel(Handler handler,CancelHandler cancel_handler)50 uintptr_t CreateContextWithCancel(Handler handler,
51 CancelHandler cancel_handler) {
52 auto* context =
53 new NotificationContext(base::BindLambdaForTesting(handler));
54 context->SetCancelCallback(
55 base::BindOnce(base::BindLambdaForTesting([cancel_handler, context] {
56 cancel_handler();
57 delete context;
58 })));
59 return reinterpret_cast<uintptr_t>(context);
60 }
61
62 private:
63 class NotificationContext {
64 public:
NotificationContext(const ContextCallback & callback)65 explicit NotificationContext(const ContextCallback& callback)
66 : callback_(callback) {}
67
~NotificationContext()68 ~NotificationContext() {}
69
SetCancelCallback(base::OnceClosure cancel_callback)70 void SetCancelCallback(base::OnceClosure cancel_callback) {
71 cancel_callback_ = std::move(cancel_callback);
72 }
73
Notify(const MojoTrapEvent & event)74 void Notify(const MojoTrapEvent& event) {
75 if (event.result == MOJO_RESULT_CANCELLED && cancel_callback_)
76 std::move(cancel_callback_).Run();
77 else
78 callback_.Run(event);
79 }
80
81 private:
82 const ContextCallback callback_;
83 base::OnceClosure cancel_callback_;
84
85 DISALLOW_COPY_AND_ASSIGN(NotificationContext);
86 };
87
Notify(const MojoTrapEvent * event)88 static void Notify(const MojoTrapEvent* event) {
89 reinterpret_cast<NotificationContext*>(event->trigger_context)
90 ->Notify(*event);
91 }
92
93 DISALLOW_COPY_AND_ASSIGN(TriggerHelper);
94 };
95
96 class ThreadedRunner : public base::SimpleThread {
97 public:
ThreadedRunner(base::OnceClosure callback)98 explicit ThreadedRunner(base::OnceClosure callback)
99 : SimpleThread("ThreadedRunner"), callback_(std::move(callback)) {}
~ThreadedRunner()100 ~ThreadedRunner() override {}
101
Run()102 void Run() override { std::move(callback_).Run(); }
103
104 private:
105 base::OnceClosure callback_;
106
107 DISALLOW_COPY_AND_ASSIGN(ThreadedRunner);
108 };
109
ExpectNoNotification(const MojoTrapEvent * event)110 void ExpectNoNotification(const MojoTrapEvent* event) {
111 NOTREACHED();
112 }
113
ExpectOnlyCancel(const MojoTrapEvent * event)114 void ExpectOnlyCancel(const MojoTrapEvent* event) {
115 EXPECT_EQ(event->result, MOJO_RESULT_CANCELLED);
116 }
117
TEST_F(TrapTest,InvalidArguments)118 TEST_F(TrapTest, InvalidArguments) {
119 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
120 MojoCreateTrap(&ExpectNoNotification, nullptr, nullptr));
121 MojoHandle t;
122 EXPECT_EQ(MOJO_RESULT_OK, MojoCreateTrap(&ExpectNoNotification, nullptr, &t));
123
124 // Try to add triggers for handles which don't raise trappable signals.
125 EXPECT_EQ(
126 MOJO_RESULT_INVALID_ARGUMENT,
127 MojoAddTrigger(t, t, MOJO_HANDLE_SIGNAL_READABLE,
128 MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, 0, nullptr));
129 MojoHandle buffer_handle = CreateBuffer(42);
130 EXPECT_EQ(
131 MOJO_RESULT_INVALID_ARGUMENT,
132 MojoAddTrigger(t, buffer_handle, MOJO_HANDLE_SIGNAL_READABLE,
133 MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, 0, nullptr));
134
135 // Try to remove a trigger on a non-trap handle.
136 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
137 MojoRemoveTrigger(buffer_handle, 0, nullptr));
138
139 // Try to arm an invalid or non-trap handle.
140 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
141 MojoArmTrap(MOJO_HANDLE_INVALID, nullptr, nullptr, nullptr));
142 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
143 MojoArmTrap(buffer_handle, nullptr, nullptr, nullptr));
144 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(buffer_handle));
145
146 // Try to arm with a non-null count but a null output buffer.
147 uint32_t num_blocking_events = 1;
148 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
149 MojoArmTrap(t, nullptr, &num_blocking_events, nullptr));
150
151 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(t));
152 }
153
TEST_F(TrapTest,TrapMessagePipeReadable)154 TEST_F(TrapTest, TrapMessagePipeReadable) {
155 MojoHandle a, b;
156 CreateMessagePipe(&a, &b);
157
158 base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::MANUAL,
159 base::WaitableEvent::InitialState::NOT_SIGNALED);
160 TriggerHelper helper;
161 int num_expected_notifications = 1;
162 const uintptr_t readable_a_context =
163 helper.CreateContext([&](const MojoTrapEvent& event) {
164 EXPECT_GT(num_expected_notifications, 0);
165 num_expected_notifications -= 1;
166
167 EXPECT_EQ(MOJO_RESULT_OK, event.result);
168 wait.Signal();
169 });
170
171 MojoHandle t;
172 EXPECT_EQ(MOJO_RESULT_OK, helper.CreateTrap(&t));
173 EXPECT_EQ(MOJO_RESULT_OK,
174 MojoAddTrigger(t, a, MOJO_HANDLE_SIGNAL_READABLE,
175 MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
176 readable_a_context, nullptr));
177 EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr));
178
179 const char kMessage1[] = "hey hey hey hey";
180 const char kMessage2[] = "i said hey";
181 const char kMessage3[] = "what's goin' on?";
182
183 // Writing to |b| multiple times should notify exactly once.
184 WriteMessage(b, kMessage1);
185 WriteMessage(b, kMessage2);
186 wait.Wait();
187
188 // This also shouldn't fire a notification; the trap is still disarmed.
189 WriteMessage(b, kMessage3);
190
191 // Arming should fail with relevant information.
192 constexpr size_t kMaxBlockingEvents = 3;
193 uint32_t num_blocking_events = kMaxBlockingEvents;
194 MojoTrapEvent blocking_events[kMaxBlockingEvents] = {
195 {sizeof(blocking_events[0])},
196 {sizeof(blocking_events[0])},
197 {sizeof(blocking_events[0])}};
198 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
199 MojoArmTrap(t, nullptr, &num_blocking_events, &blocking_events[0]));
200 EXPECT_EQ(1u, num_blocking_events);
201 EXPECT_EQ(readable_a_context, blocking_events[0].trigger_context);
202 EXPECT_EQ(MOJO_RESULT_OK, blocking_events[0].result);
203
204 // Flush the three messages from above.
205 EXPECT_EQ(kMessage1, ReadMessage(a));
206 EXPECT_EQ(kMessage2, ReadMessage(a));
207 EXPECT_EQ(kMessage3, ReadMessage(a));
208
209 // Now we can rearm the trap.
210 EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr));
211
212 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(t));
213 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
214 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
215 }
216
TEST_F(TrapTest,CloseWatchedMessagePipeHandle)217 TEST_F(TrapTest, CloseWatchedMessagePipeHandle) {
218 MojoHandle a, b;
219 CreateMessagePipe(&a, &b);
220
221 base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::MANUAL,
222 base::WaitableEvent::InitialState::NOT_SIGNALED);
223 TriggerHelper helper;
224 const uintptr_t readable_a_context = helper.CreateContextWithCancel(
225 [](const MojoTrapEvent&) {}, [&] { wait.Signal(); });
226
227 MojoHandle t;
228 EXPECT_EQ(MOJO_RESULT_OK, helper.CreateTrap(&t));
229 EXPECT_EQ(MOJO_RESULT_OK,
230 MojoAddTrigger(t, a, MOJO_HANDLE_SIGNAL_READABLE,
231 MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
232 readable_a_context, nullptr));
233
234 // Test that closing a watched handle fires an appropriate notification, even
235 // when the trap is unarmed.
236 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
237 wait.Wait();
238
239 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
240 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(t));
241 }
242
TEST_F(TrapTest,CloseWatchedMessagePipeHandlePeer)243 TEST_F(TrapTest, CloseWatchedMessagePipeHandlePeer) {
244 MojoHandle a, b;
245 CreateMessagePipe(&a, &b);
246
247 base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::MANUAL,
248 base::WaitableEvent::InitialState::NOT_SIGNALED);
249 TriggerHelper helper;
250 const uintptr_t readable_a_context =
251 helper.CreateContext([&](const MojoTrapEvent& event) {
252 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, event.result);
253 wait.Signal();
254 });
255
256 MojoHandle t;
257 EXPECT_EQ(MOJO_RESULT_OK, helper.CreateTrap(&t));
258 EXPECT_EQ(MOJO_RESULT_OK,
259 MojoAddTrigger(t, a, MOJO_HANDLE_SIGNAL_READABLE,
260 MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
261 readable_a_context, nullptr));
262
263 // Test that closing a watched handle's peer with an armed trap fires an
264 // appropriate notification.
265 EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr));
266 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
267 wait.Wait();
268
269 // And now arming should fail with correct information about |a|'s state.
270 constexpr size_t kMaxBlockingEvents = 3;
271 uint32_t num_blocking_events = kMaxBlockingEvents;
272 MojoTrapEvent blocking_events[kMaxBlockingEvents] = {
273 {sizeof(blocking_events[0])},
274 {sizeof(blocking_events[0])},
275 {sizeof(blocking_events[0])}};
276 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
277 MojoArmTrap(t, nullptr, &num_blocking_events, &blocking_events[0]));
278 EXPECT_EQ(1u, num_blocking_events);
279 EXPECT_EQ(readable_a_context, blocking_events[0].trigger_context);
280 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, blocking_events[0].result);
281 EXPECT_TRUE(blocking_events[0].signals_state.satisfied_signals &
282 MOJO_HANDLE_SIGNAL_PEER_CLOSED);
283 EXPECT_FALSE(blocking_events[0].signals_state.satisfiable_signals &
284 MOJO_HANDLE_SIGNAL_READABLE);
285
286 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(t));
287 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
288 }
289
TEST_F(TrapTest,TrapDataPipeConsumerReadable)290 TEST_F(TrapTest, TrapDataPipeConsumerReadable) {
291 constexpr size_t kTestPipeCapacity = 64;
292 MojoHandle producer, consumer;
293 CreateDataPipe(&producer, &consumer, kTestPipeCapacity);
294
295 base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::MANUAL,
296 base::WaitableEvent::InitialState::NOT_SIGNALED);
297 TriggerHelper helper;
298 int num_expected_notifications = 1;
299 const uintptr_t readable_consumer_context =
300 helper.CreateContext([&](const MojoTrapEvent& event) {
301 EXPECT_GT(num_expected_notifications, 0);
302 num_expected_notifications -= 1;
303
304 EXPECT_EQ(MOJO_RESULT_OK, event.result);
305 wait.Signal();
306 });
307
308 MojoHandle t;
309 EXPECT_EQ(MOJO_RESULT_OK, helper.CreateTrap(&t));
310 EXPECT_EQ(MOJO_RESULT_OK,
311 MojoAddTrigger(t, consumer, MOJO_HANDLE_SIGNAL_READABLE,
312 MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
313 readable_consumer_context, nullptr));
314 EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr));
315
316 const char kMessage1[] = "hey hey hey hey";
317 const char kMessage2[] = "i said hey";
318 const char kMessage3[] = "what's goin' on?";
319
320 // Writing to |producer| multiple times should notify exactly once.
321 WriteData(producer, kMessage1);
322 WriteData(producer, kMessage2);
323 wait.Wait();
324
325 // This also shouldn't fire a notification; the trap is still disarmed.
326 WriteData(producer, kMessage3);
327
328 // Arming should fail with relevant information.
329 constexpr size_t kMaxBlockingEvents = 3;
330 uint32_t num_blocking_events = kMaxBlockingEvents;
331 MojoTrapEvent blocking_events[kMaxBlockingEvents] = {
332 {sizeof(blocking_events[0])},
333 {sizeof(blocking_events[0])},
334 {sizeof(blocking_events[0])}};
335 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
336 MojoArmTrap(t, nullptr, &num_blocking_events, &blocking_events[0]));
337 EXPECT_EQ(1u, num_blocking_events);
338 EXPECT_EQ(readable_consumer_context, blocking_events[0].trigger_context);
339 EXPECT_EQ(MOJO_RESULT_OK, blocking_events[0].result);
340
341 // Flush the three messages from above.
342 EXPECT_EQ(kMessage1, ReadData(consumer, sizeof(kMessage1) - 1));
343 EXPECT_EQ(kMessage2, ReadData(consumer, sizeof(kMessage2) - 1));
344 EXPECT_EQ(kMessage3, ReadData(consumer, sizeof(kMessage3) - 1));
345
346 // Now we can rearm the trap.
347 EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr));
348
349 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(t));
350 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(producer));
351 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(consumer));
352 }
353
TEST_F(TrapTest,TrapDataPipeConsumerNewDataReadable)354 TEST_F(TrapTest, TrapDataPipeConsumerNewDataReadable) {
355 constexpr size_t kTestPipeCapacity = 64;
356 MojoHandle producer, consumer;
357 CreateDataPipe(&producer, &consumer, kTestPipeCapacity);
358
359 base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::MANUAL,
360 base::WaitableEvent::InitialState::NOT_SIGNALED);
361 TriggerHelper helper;
362 int num_new_data_notifications = 0;
363 const uintptr_t new_data_context =
364 helper.CreateContext([&](const MojoTrapEvent& event) {
365 num_new_data_notifications += 1;
366
367 EXPECT_EQ(MOJO_RESULT_OK, event.result);
368 wait.Signal();
369 });
370
371 MojoHandle t;
372 EXPECT_EQ(MOJO_RESULT_OK, helper.CreateTrap(&t));
373 EXPECT_EQ(MOJO_RESULT_OK,
374 MojoAddTrigger(t, consumer, MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
375 MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
376 new_data_context, nullptr));
377 EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr));
378
379 const char kMessage1[] = "hey hey hey hey";
380 const char kMessage2[] = "i said hey";
381 const char kMessage3[] = "what's goin' on?";
382
383 // Writing to |producer| multiple times should notify exactly once.
384 WriteData(producer, kMessage1);
385 WriteData(producer, kMessage2);
386 wait.Wait();
387
388 // This also shouldn't fire a notification; the trap is still disarmed.
389 WriteData(producer, kMessage3);
390
391 // Arming should fail with relevant information.
392 constexpr size_t kMaxBlockingEvents = 3;
393 uint32_t num_blocking_events = kMaxBlockingEvents;
394 MojoTrapEvent blocking_events[kMaxBlockingEvents] = {
395 {sizeof(blocking_events[0])},
396 {sizeof(blocking_events[0])},
397 {sizeof(blocking_events[0])}};
398 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
399 MojoArmTrap(t, nullptr, &num_blocking_events, &blocking_events[0]));
400 EXPECT_EQ(1u, num_blocking_events);
401 EXPECT_EQ(new_data_context, blocking_events[0].trigger_context);
402 EXPECT_EQ(MOJO_RESULT_OK, blocking_events[0].result);
403
404 // Attempt to read more data than is available. Should fail but clear the
405 // NEW_DATA_READABLE signal.
406 char large_buffer[512];
407 uint32_t large_read_size = 512;
408 MojoReadDataOptions options;
409 options.struct_size = sizeof(options);
410 options.flags = MOJO_READ_DATA_FLAG_ALL_OR_NONE;
411 EXPECT_EQ(MOJO_RESULT_OUT_OF_RANGE,
412 MojoReadData(consumer, &options, large_buffer, &large_read_size));
413
414 // Attempt to arm again. Should succeed.
415 EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr));
416
417 // Write more data. Should notify.
418 wait.Reset();
419 WriteData(producer, kMessage1);
420 wait.Wait();
421
422 // Reading some data should clear NEW_DATA_READABLE again so we can rearm.
423 EXPECT_EQ(kMessage1, ReadData(consumer, sizeof(kMessage1) - 1));
424
425 EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr));
426
427 EXPECT_EQ(2, num_new_data_notifications);
428
429 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(t));
430 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(producer));
431 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(consumer));
432 }
433
TEST_F(TrapTest,TrapDataPipeProducerWritable)434 TEST_F(TrapTest, TrapDataPipeProducerWritable) {
435 constexpr size_t kTestPipeCapacity = 8;
436 MojoHandle producer, consumer;
437 CreateDataPipe(&producer, &consumer, kTestPipeCapacity);
438
439 // Half the capacity of the data pipe.
440 const char kTestData[] = "aaaa";
441 static_assert((sizeof(kTestData) - 1) * 2 == kTestPipeCapacity,
442 "Invalid test data for this test.");
443
444 base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::MANUAL,
445 base::WaitableEvent::InitialState::NOT_SIGNALED);
446 TriggerHelper helper;
447 int num_expected_notifications = 1;
448 const uintptr_t writable_producer_context =
449 helper.CreateContext([&](const MojoTrapEvent& event) {
450 EXPECT_GT(num_expected_notifications, 0);
451 num_expected_notifications -= 1;
452
453 EXPECT_EQ(MOJO_RESULT_OK, event.result);
454 wait.Signal();
455 });
456
457 MojoHandle t;
458 EXPECT_EQ(MOJO_RESULT_OK, helper.CreateTrap(&t));
459 EXPECT_EQ(MOJO_RESULT_OK,
460 MojoAddTrigger(t, producer, MOJO_HANDLE_SIGNAL_WRITABLE,
461 MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
462 writable_producer_context, nullptr));
463
464 // The producer is already writable, so arming should fail with relevant
465 // information.
466 constexpr size_t kMaxBlockingEvents = 3;
467 uint32_t num_blocking_events = kMaxBlockingEvents;
468 MojoTrapEvent blocking_events[kMaxBlockingEvents] = {
469 {sizeof(blocking_events[0])},
470 {sizeof(blocking_events[0])},
471 {sizeof(blocking_events[0])}};
472 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
473 MojoArmTrap(t, nullptr, &num_blocking_events, &blocking_events[0]));
474 EXPECT_EQ(1u, num_blocking_events);
475 EXPECT_EQ(writable_producer_context, blocking_events[0].trigger_context);
476 EXPECT_EQ(MOJO_RESULT_OK, blocking_events[0].result);
477 EXPECT_TRUE(blocking_events[0].signals_state.satisfied_signals &
478 MOJO_HANDLE_SIGNAL_WRITABLE);
479
480 // Write some data, but don't fill the pipe yet. Arming should fail again.
481 WriteData(producer, kTestData);
482 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
483 MojoArmTrap(t, nullptr, &num_blocking_events, &blocking_events[0]));
484 EXPECT_EQ(1u, num_blocking_events);
485 EXPECT_EQ(writable_producer_context, blocking_events[0].trigger_context);
486 EXPECT_EQ(MOJO_RESULT_OK, blocking_events[0].result);
487 EXPECT_TRUE(blocking_events[0].signals_state.satisfied_signals &
488 MOJO_HANDLE_SIGNAL_WRITABLE);
489
490 // Write more data, filling the pipe to capacity. Arming should succeed now.
491 WriteData(producer, kTestData);
492 EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr));
493
494 // Now read from the pipe, making the producer writable again. Should notify.
495 EXPECT_EQ(kTestData, ReadData(consumer, sizeof(kTestData) - 1));
496 wait.Wait();
497
498 // Arming should fail again.
499 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
500 MojoArmTrap(t, nullptr, &num_blocking_events, &blocking_events[0]));
501 EXPECT_EQ(1u, num_blocking_events);
502 EXPECT_EQ(writable_producer_context, blocking_events[0].trigger_context);
503 EXPECT_EQ(MOJO_RESULT_OK, blocking_events[0].result);
504 EXPECT_TRUE(blocking_events[0].signals_state.satisfied_signals &
505 MOJO_HANDLE_SIGNAL_WRITABLE);
506
507 // Fill the pipe once more and arm the trap. Should succeed.
508 WriteData(producer, kTestData);
509 EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr));
510
511 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(t));
512 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(producer));
513 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(consumer));
514 };
515
TEST_F(TrapTest,CloseWatchedDataPipeConsumerHandle)516 TEST_F(TrapTest, CloseWatchedDataPipeConsumerHandle) {
517 constexpr size_t kTestPipeCapacity = 8;
518 MojoHandle producer, consumer;
519 CreateDataPipe(&producer, &consumer, kTestPipeCapacity);
520
521 base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::MANUAL,
522 base::WaitableEvent::InitialState::NOT_SIGNALED);
523 TriggerHelper helper;
524 const uintptr_t readable_consumer_context = helper.CreateContextWithCancel(
525 [](const MojoTrapEvent&) {}, [&] { wait.Signal(); });
526
527 MojoHandle t;
528 EXPECT_EQ(MOJO_RESULT_OK, helper.CreateTrap(&t));
529 EXPECT_EQ(MOJO_RESULT_OK,
530 MojoAddTrigger(t, consumer, MOJO_HANDLE_SIGNAL_READABLE,
531 MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
532 readable_consumer_context, nullptr));
533
534 // Closing the consumer should fire a cancellation notification.
535 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(consumer));
536 wait.Wait();
537
538 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(producer));
539 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(t));
540 }
541
TEST_F(TrapTest,CloseWatchedDataPipeConsumerHandlePeer)542 TEST_F(TrapTest, CloseWatchedDataPipeConsumerHandlePeer) {
543 constexpr size_t kTestPipeCapacity = 8;
544 MojoHandle producer, consumer;
545 CreateDataPipe(&producer, &consumer, kTestPipeCapacity);
546
547 base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::MANUAL,
548 base::WaitableEvent::InitialState::NOT_SIGNALED);
549 TriggerHelper helper;
550 const uintptr_t readable_consumer_context =
551 helper.CreateContext([&](const MojoTrapEvent& event) {
552 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, event.result);
553 wait.Signal();
554 });
555
556 MojoHandle t;
557 EXPECT_EQ(MOJO_RESULT_OK, helper.CreateTrap(&t));
558 EXPECT_EQ(MOJO_RESULT_OK,
559 MojoAddTrigger(t, consumer, MOJO_HANDLE_SIGNAL_READABLE,
560 MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
561 readable_consumer_context, nullptr));
562 EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr));
563
564 // Closing the producer should fire a notification for an unsatisfiable
565 // condition.
566 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(producer));
567 wait.Wait();
568
569 // Now attempt to rearm and expect appropriate error feedback.
570 constexpr size_t kMaxBlockingEvents = 3;
571 uint32_t num_blocking_events = kMaxBlockingEvents;
572 MojoTrapEvent blocking_events[kMaxBlockingEvents] = {
573 {sizeof(blocking_events[0])},
574 {sizeof(blocking_events[0])},
575 {sizeof(blocking_events[0])}};
576 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
577 MojoArmTrap(t, nullptr, &num_blocking_events, &blocking_events[0]));
578 EXPECT_EQ(1u, num_blocking_events);
579 EXPECT_EQ(readable_consumer_context, blocking_events[0].trigger_context);
580 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, blocking_events[0].result);
581 EXPECT_FALSE(blocking_events[0].signals_state.satisfiable_signals &
582 MOJO_HANDLE_SIGNAL_READABLE);
583
584 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(t));
585 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(consumer));
586 }
587
TEST_F(TrapTest,CloseWatchedDataPipeProducerHandle)588 TEST_F(TrapTest, CloseWatchedDataPipeProducerHandle) {
589 constexpr size_t kTestPipeCapacity = 8;
590 MojoHandle producer, consumer;
591 CreateDataPipe(&producer, &consumer, kTestPipeCapacity);
592
593 base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::MANUAL,
594 base::WaitableEvent::InitialState::NOT_SIGNALED);
595 TriggerHelper helper;
596 const uintptr_t writable_producer_context = helper.CreateContextWithCancel(
597 [](const MojoTrapEvent&) {}, [&] { wait.Signal(); });
598
599 MojoHandle t;
600 EXPECT_EQ(MOJO_RESULT_OK, helper.CreateTrap(&t));
601 EXPECT_EQ(MOJO_RESULT_OK,
602 MojoAddTrigger(t, producer, MOJO_HANDLE_SIGNAL_WRITABLE,
603 MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
604 writable_producer_context, nullptr));
605
606 // Closing the consumer should fire a cancellation notification.
607 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(producer));
608 wait.Wait();
609
610 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(consumer));
611 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(t));
612 }
613
TEST_F(TrapTest,CloseWatchedDataPipeProducerHandlePeer)614 TEST_F(TrapTest, CloseWatchedDataPipeProducerHandlePeer) {
615 constexpr size_t kTestPipeCapacity = 8;
616 MojoHandle producer, consumer;
617 CreateDataPipe(&producer, &consumer, kTestPipeCapacity);
618
619 const char kTestMessageFullCapacity[] = "xxxxxxxx";
620 static_assert(sizeof(kTestMessageFullCapacity) - 1 == kTestPipeCapacity,
621 "Invalid test message size for this test.");
622
623 // Make the pipe unwritable initially.
624 WriteData(producer, kTestMessageFullCapacity);
625
626 base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::MANUAL,
627 base::WaitableEvent::InitialState::NOT_SIGNALED);
628 TriggerHelper helper;
629 const uintptr_t writable_producer_context =
630 helper.CreateContext([&](const MojoTrapEvent& event) {
631 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, event.result);
632 wait.Signal();
633 });
634
635 MojoHandle t;
636 EXPECT_EQ(MOJO_RESULT_OK, helper.CreateTrap(&t));
637 EXPECT_EQ(MOJO_RESULT_OK,
638 MojoAddTrigger(t, producer, MOJO_HANDLE_SIGNAL_WRITABLE,
639 MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
640 writable_producer_context, nullptr));
641 EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr));
642
643 // Closing the consumer should fire a notification for an unsatisfiable
644 // condition, as the full data pipe can never be read from again and is
645 // therefore permanently full and unwritable.
646 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(consumer));
647 wait.Wait();
648
649 // Now attempt to rearm and expect appropriate error feedback.
650 constexpr size_t kMaxBlockingEvents = 3;
651 uint32_t num_blocking_events = kMaxBlockingEvents;
652 MojoTrapEvent blocking_events[kMaxBlockingEvents] = {
653 {sizeof(blocking_events[0])},
654 {sizeof(blocking_events[0])},
655 {sizeof(blocking_events[0])}};
656 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
657 MojoArmTrap(t, nullptr, &num_blocking_events, &blocking_events[0]));
658 EXPECT_EQ(1u, num_blocking_events);
659 EXPECT_EQ(writable_producer_context, blocking_events[0].trigger_context);
660 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, blocking_events[0].result);
661 EXPECT_FALSE(blocking_events[0].signals_state.satisfiable_signals &
662 MOJO_HANDLE_SIGNAL_WRITABLE);
663
664 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(t));
665 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(producer));
666 }
667
TEST_F(TrapTest,ArmWithNoTriggers)668 TEST_F(TrapTest, ArmWithNoTriggers) {
669 MojoHandle t;
670 EXPECT_EQ(MOJO_RESULT_OK, MojoCreateTrap(&ExpectNoNotification, nullptr, &t));
671 EXPECT_EQ(MOJO_RESULT_NOT_FOUND, MojoArmTrap(t, nullptr, nullptr, nullptr));
672 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(t));
673 }
674
TEST_F(TrapTest,DuplicateTriggerContext)675 TEST_F(TrapTest, DuplicateTriggerContext) {
676 MojoHandle a, b;
677 CreateMessagePipe(&a, &b);
678
679 MojoHandle t;
680 EXPECT_EQ(MOJO_RESULT_OK, MojoCreateTrap(&ExpectOnlyCancel, nullptr, &t));
681 EXPECT_EQ(
682 MOJO_RESULT_OK,
683 MojoAddTrigger(t, a, MOJO_HANDLE_SIGNAL_READABLE,
684 MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, 0, nullptr));
685 EXPECT_EQ(
686 MOJO_RESULT_ALREADY_EXISTS,
687 MojoAddTrigger(t, b, MOJO_HANDLE_SIGNAL_READABLE,
688 MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, 0, nullptr));
689
690 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(t));
691 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
692 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
693 }
694
TEST_F(TrapTest,RemoveUnknownTrigger)695 TEST_F(TrapTest, RemoveUnknownTrigger) {
696 MojoHandle t;
697 EXPECT_EQ(MOJO_RESULT_OK, MojoCreateTrap(&ExpectNoNotification, nullptr, &t));
698 EXPECT_EQ(MOJO_RESULT_NOT_FOUND, MojoRemoveTrigger(t, 1234, nullptr));
699 }
700
TEST_F(TrapTest,ArmWithTriggerConditionAlreadySatisfied)701 TEST_F(TrapTest, ArmWithTriggerConditionAlreadySatisfied) {
702 MojoHandle a, b;
703 CreateMessagePipe(&a, &b);
704
705 MojoHandle t;
706 EXPECT_EQ(MOJO_RESULT_OK, MojoCreateTrap(&ExpectOnlyCancel, nullptr, &t));
707 EXPECT_EQ(
708 MOJO_RESULT_OK,
709 MojoAddTrigger(t, a, MOJO_HANDLE_SIGNAL_WRITABLE,
710 MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, 0, nullptr));
711
712 // |a| is always writable, so we can never arm this trap.
713 constexpr size_t kMaxBlockingEvents = 3;
714 uint32_t num_blocking_events = kMaxBlockingEvents;
715 MojoTrapEvent blocking_events[kMaxBlockingEvents] = {
716 {sizeof(blocking_events[0])},
717 {sizeof(blocking_events[0])},
718 {sizeof(blocking_events[0])}};
719 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
720 MojoArmTrap(t, nullptr, &num_blocking_events, &blocking_events[0]));
721 EXPECT_EQ(1u, num_blocking_events);
722 EXPECT_EQ(0u, blocking_events[0].trigger_context);
723 EXPECT_EQ(MOJO_RESULT_OK, blocking_events[0].result);
724 EXPECT_TRUE(blocking_events[0].signals_state.satisfied_signals &
725 MOJO_HANDLE_SIGNAL_WRITABLE);
726
727 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(t));
728 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
729 }
730
TEST_F(TrapTest,ArmWithTriggerConditionAlreadyUnsatisfiable)731 TEST_F(TrapTest, ArmWithTriggerConditionAlreadyUnsatisfiable) {
732 MojoHandle a, b;
733 CreateMessagePipe(&a, &b);
734
735 MojoHandle t;
736 EXPECT_EQ(MOJO_RESULT_OK, MojoCreateTrap(&ExpectOnlyCancel, nullptr, &t));
737 EXPECT_EQ(
738 MOJO_RESULT_OK,
739 MojoAddTrigger(t, a, MOJO_HANDLE_SIGNAL_READABLE,
740 MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, 0, nullptr));
741
742 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
743
744 // |b| is closed and never wrote any messages, so |a| won't be readable again.
745 // MojoArmTrap() should fail, incidcating as much.
746 constexpr size_t kMaxBlockingEvents = 3;
747 uint32_t num_blocking_events = kMaxBlockingEvents;
748 MojoTrapEvent blocking_events[kMaxBlockingEvents] = {
749 {sizeof(blocking_events[0])},
750 {sizeof(blocking_events[0])},
751 {sizeof(blocking_events[0])}};
752 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
753 MojoArmTrap(t, nullptr, &num_blocking_events, &blocking_events[0]));
754 EXPECT_EQ(1u, num_blocking_events);
755 EXPECT_EQ(0u, blocking_events[0].trigger_context);
756 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, blocking_events[0].result);
757 EXPECT_TRUE(blocking_events[0].signals_state.satisfied_signals &
758 MOJO_HANDLE_SIGNAL_PEER_CLOSED);
759 EXPECT_FALSE(blocking_events[0].signals_state.satisfiable_signals &
760 MOJO_HANDLE_SIGNAL_READABLE);
761
762 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(t));
763 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
764 }
765
TEST_F(TrapTest,MultipleTriggers)766 TEST_F(TrapTest, MultipleTriggers) {
767 MojoHandle a, b;
768 CreateMessagePipe(&a, &b);
769
770 base::WaitableEvent a_wait(base::WaitableEvent::ResetPolicy::MANUAL,
771 base::WaitableEvent::InitialState::NOT_SIGNALED);
772 base::WaitableEvent b_wait(base::WaitableEvent::ResetPolicy::MANUAL,
773 base::WaitableEvent::InitialState::NOT_SIGNALED);
774 TriggerHelper helper;
775 int num_a_notifications = 0;
776 int num_b_notifications = 0;
777 uintptr_t readable_a_context =
778 helper.CreateContext([&](const MojoTrapEvent& event) {
779 num_a_notifications += 1;
780 EXPECT_EQ(MOJO_RESULT_OK, event.result);
781 a_wait.Signal();
782 });
783 uintptr_t readable_b_context =
784 helper.CreateContext([&](const MojoTrapEvent& event) {
785 num_b_notifications += 1;
786 EXPECT_EQ(MOJO_RESULT_OK, event.result);
787 b_wait.Signal();
788 });
789
790 MojoHandle t;
791 EXPECT_EQ(MOJO_RESULT_OK, helper.CreateTrap(&t));
792
793 // Add two independent triggers to trap |a| or |b| readability.
794 EXPECT_EQ(MOJO_RESULT_OK,
795 MojoAddTrigger(t, a, MOJO_HANDLE_SIGNAL_READABLE,
796 MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
797 readable_a_context, nullptr));
798 EXPECT_EQ(MOJO_RESULT_OK,
799 MojoAddTrigger(t, b, MOJO_HANDLE_SIGNAL_READABLE,
800 MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
801 readable_b_context, nullptr));
802
803 EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr));
804
805 const char kMessage1[] = "things are happening";
806 const char kMessage2[] = "ok. ok. ok. ok.";
807 const char kMessage3[] = "plz wake up";
808
809 // Writing to |b| should signal |a|'s watch.
810 WriteMessage(b, kMessage1);
811 a_wait.Wait();
812 a_wait.Reset();
813
814 // Subsequent messages on |b| should not trigger another notification.
815 WriteMessage(b, kMessage2);
816 WriteMessage(b, kMessage3);
817
818 // Messages on |a| also shouldn't trigger |b|'s notification, since the
819 // trap should be disarmed by now.
820 WriteMessage(a, kMessage1);
821 WriteMessage(a, kMessage2);
822 WriteMessage(a, kMessage3);
823
824 // Arming should fail. Since we only ask for at most one context's information
825 // that's all we should get back. Which one we get is unspecified.
826 constexpr size_t kMaxBlockingEvents = 3;
827 uint32_t num_blocking_events = 1;
828 MojoTrapEvent blocking_events[kMaxBlockingEvents] = {
829 {sizeof(blocking_events[0])},
830 {sizeof(blocking_events[0])},
831 {sizeof(blocking_events[0])}};
832 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
833 MojoArmTrap(t, nullptr, &num_blocking_events, &blocking_events[0]));
834 EXPECT_EQ(1u, num_blocking_events);
835 EXPECT_TRUE(blocking_events[0].trigger_context == readable_a_context ||
836 blocking_events[0].trigger_context == readable_b_context);
837 EXPECT_EQ(MOJO_RESULT_OK, blocking_events[0].result);
838 EXPECT_TRUE(blocking_events[0].signals_state.satisfied_signals &
839 MOJO_HANDLE_SIGNAL_WRITABLE);
840
841 // Now try arming again, verifying that both contexts are returned.
842 num_blocking_events = kMaxBlockingEvents;
843 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
844 MojoArmTrap(t, nullptr, &num_blocking_events, &blocking_events[0]));
845 EXPECT_EQ(2u, num_blocking_events);
846 EXPECT_EQ(MOJO_RESULT_OK, blocking_events[0].result);
847 EXPECT_EQ(MOJO_RESULT_OK, blocking_events[1].result);
848 EXPECT_TRUE(blocking_events[0].signals_state.satisfied_signals &
849 MOJO_HANDLE_SIGNAL_WRITABLE);
850 EXPECT_TRUE(blocking_events[1].signals_state.satisfied_signals &
851 MOJO_HANDLE_SIGNAL_WRITABLE);
852 EXPECT_TRUE((blocking_events[0].trigger_context == readable_a_context &&
853 blocking_events[1].trigger_context == readable_b_context) ||
854 (blocking_events[0].trigger_context == readable_b_context &&
855 blocking_events[1].trigger_context == readable_a_context));
856
857 // Flush out the test messages so we should be able to successfully rearm.
858 EXPECT_EQ(kMessage1, ReadMessage(a));
859 EXPECT_EQ(kMessage2, ReadMessage(a));
860 EXPECT_EQ(kMessage3, ReadMessage(a));
861 EXPECT_EQ(kMessage1, ReadMessage(b));
862 EXPECT_EQ(kMessage2, ReadMessage(b));
863 EXPECT_EQ(kMessage3, ReadMessage(b));
864
865 // Add a trigger whose condition is always satisfied so we can't arm. Arming
866 // should fail with only this new watch's information.
867 uintptr_t writable_c_context =
868 helper.CreateContext([](const MojoTrapEvent&) { NOTREACHED(); });
869 MojoHandle c, d;
870 CreateMessagePipe(&c, &d);
871
872 EXPECT_EQ(MOJO_RESULT_OK,
873 MojoAddTrigger(t, c, MOJO_HANDLE_SIGNAL_WRITABLE,
874 MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
875 writable_c_context, nullptr));
876 num_blocking_events = kMaxBlockingEvents;
877 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
878 MojoArmTrap(t, nullptr, &num_blocking_events, &blocking_events[0]));
879 EXPECT_EQ(1u, num_blocking_events);
880 EXPECT_EQ(writable_c_context, blocking_events[0].trigger_context);
881 EXPECT_EQ(MOJO_RESULT_OK, blocking_events[0].result);
882 EXPECT_TRUE(blocking_events[0].signals_state.satisfied_signals &
883 MOJO_HANDLE_SIGNAL_WRITABLE);
884
885 // Remove the new trigger and arming should succeed once again.
886 EXPECT_EQ(MOJO_RESULT_OK, MojoRemoveTrigger(t, writable_c_context, nullptr));
887 EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr));
888
889 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(t));
890 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
891 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
892 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(c));
893 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(d));
894 }
895
TEST_F(TrapTest,ActivateOtherTriggerFromEventHandler)896 TEST_F(TrapTest, ActivateOtherTriggerFromEventHandler) {
897 MojoHandle a, b;
898 CreateMessagePipe(&a, &b);
899
900 static const char kTestMessageToA[] = "hello a";
901 static const char kTestMessageToB[] = "hello b";
902
903 base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::MANUAL,
904 base::WaitableEvent::InitialState::NOT_SIGNALED);
905
906 TriggerHelper helper;
907 MojoHandle t;
908 EXPECT_EQ(MOJO_RESULT_OK, helper.CreateTrap(&t));
909
910 uintptr_t readable_a_context =
911 helper.CreateContext([&](const MojoTrapEvent& event) {
912 EXPECT_EQ(MOJO_RESULT_OK, event.result);
913 EXPECT_EQ("hello a", ReadMessage(a));
914
915 // Re-arm the trap and signal |b|.
916 EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr));
917 WriteMessage(a, kTestMessageToB);
918 });
919
920 uintptr_t readable_b_context =
921 helper.CreateContext([&](const MojoTrapEvent& event) {
922 EXPECT_EQ(MOJO_RESULT_OK, event.result);
923 EXPECT_EQ(kTestMessageToB, ReadMessage(b));
924 EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr));
925 wait.Signal();
926 });
927
928 EXPECT_EQ(MOJO_RESULT_OK,
929 MojoAddTrigger(t, a, MOJO_HANDLE_SIGNAL_READABLE,
930 MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
931 readable_a_context, nullptr));
932 EXPECT_EQ(MOJO_RESULT_OK,
933 MojoAddTrigger(t, b, MOJO_HANDLE_SIGNAL_READABLE,
934 MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
935 readable_b_context, nullptr));
936 EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr));
937
938 // Send a message to |a|. The relevant trigger should be notified and the
939 // event handler should send a message to |b|, in turn notifying the other
940 // trigger. The second event handler will signal |wait|.
941 WriteMessage(b, kTestMessageToA);
942 wait.Wait();
943 }
944
TEST_F(TrapTest,ActivateSameTriggerFromEventHandler)945 TEST_F(TrapTest, ActivateSameTriggerFromEventHandler) {
946 MojoHandle a, b;
947 CreateMessagePipe(&a, &b);
948
949 static const char kTestMessageToA[] = "hello a";
950
951 base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::MANUAL,
952 base::WaitableEvent::InitialState::NOT_SIGNALED);
953
954 TriggerHelper helper;
955 MojoHandle t;
956 EXPECT_EQ(MOJO_RESULT_OK, helper.CreateTrap(&t));
957
958 int expected_notifications = 10;
959 uintptr_t readable_a_context =
960 helper.CreateContext([&](const MojoTrapEvent& event) {
961 EXPECT_EQ(MOJO_RESULT_OK, event.result);
962 EXPECT_EQ("hello a", ReadMessage(a));
963
964 EXPECT_GT(expected_notifications, 0);
965 expected_notifications -= 1;
966 if (expected_notifications == 0) {
967 wait.Signal();
968 return;
969 } else {
970 // Re-arm the trap and signal |a| again.
971 EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr));
972 WriteMessage(b, kTestMessageToA);
973 }
974 });
975
976 EXPECT_EQ(MOJO_RESULT_OK,
977 MojoAddTrigger(t, a, MOJO_HANDLE_SIGNAL_READABLE,
978 MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
979 readable_a_context, nullptr));
980 EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr));
981
982 // Send a message to |a|. When the trigger above is activated, the event
983 // handler will rearm the trap and send another message to |a|. This will
984 // happen until |expected_notifications| reaches 0.
985 WriteMessage(b, kTestMessageToA);
986 wait.Wait();
987 }
988
TEST_F(TrapTest,ImplicitRemoveOtherTriggerWithinEventHandler)989 TEST_F(TrapTest, ImplicitRemoveOtherTriggerWithinEventHandler) {
990 MojoHandle a, b;
991 CreateMessagePipe(&a, &b);
992
993 MojoHandle c, d;
994 CreateMessagePipe(&c, &d);
995
996 static const char kTestMessageToA[] = "hi a";
997 static const char kTestMessageToC[] = "hi c";
998
999 base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::MANUAL,
1000 base::WaitableEvent::InitialState::NOT_SIGNALED);
1001
1002 TriggerHelper helper;
1003 MojoHandle t;
1004 EXPECT_EQ(MOJO_RESULT_OK, helper.CreateTrap(&t));
1005
1006 uintptr_t readable_a_context = helper.CreateContextWithCancel(
1007 [](const MojoTrapEvent&) { NOTREACHED(); }, [&] { wait.Signal(); });
1008
1009 uintptr_t readable_c_context =
1010 helper.CreateContext([&](const MojoTrapEvent& event) {
1011 EXPECT_EQ(MOJO_RESULT_OK, event.result);
1012 EXPECT_EQ(kTestMessageToC, ReadMessage(c));
1013
1014 EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr));
1015
1016 // Must result in exactly ONE notification from the above trigger, for
1017 // CANCELLED only. Because we cannot dispatch notifications until the
1018 // stack unwinds, and because we must never dispatch non-cancellation
1019 // notifications for a handle once it's been closed, we must be certain
1020 // that cancellation due to closure preemptively invalidates any
1021 // pending non-cancellation notifications queued on the current
1022 // RequestContext, such as the one resulting from the WriteMessage here.
1023 WriteMessage(b, kTestMessageToA);
1024 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
1025
1026 // Rearming should be fine since |a|'s trigger should already be
1027 // implicitly removed (even though the notification will not have
1028 // been invoked yet.)
1029 EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr));
1030
1031 // Nothing interesting should happen as a result of this.
1032 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
1033 });
1034
1035 EXPECT_EQ(MOJO_RESULT_OK,
1036 MojoAddTrigger(t, a, MOJO_HANDLE_SIGNAL_READABLE,
1037 MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
1038 readable_a_context, nullptr));
1039 EXPECT_EQ(MOJO_RESULT_OK,
1040 MojoAddTrigger(t, c, MOJO_HANDLE_SIGNAL_READABLE,
1041 MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
1042 readable_c_context, nullptr));
1043 EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr));
1044
1045 WriteMessage(d, kTestMessageToC);
1046 wait.Wait();
1047
1048 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(t));
1049 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(c));
1050 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(d));
1051 }
1052
TEST_F(TrapTest,ExplicitRemoveOtherTriggerWithinEventHandler)1053 TEST_F(TrapTest, ExplicitRemoveOtherTriggerWithinEventHandler) {
1054 MojoHandle a, b;
1055 CreateMessagePipe(&a, &b);
1056
1057 MojoHandle c, d;
1058 CreateMessagePipe(&c, &d);
1059
1060 static const char kTestMessageToA[] = "hi a";
1061 static const char kTestMessageToC[] = "hi c";
1062
1063 base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::MANUAL,
1064 base::WaitableEvent::InitialState::NOT_SIGNALED);
1065
1066 TriggerHelper helper;
1067 MojoHandle t;
1068 EXPECT_EQ(MOJO_RESULT_OK, helper.CreateTrap(&t));
1069
1070 uintptr_t readable_a_context =
1071 helper.CreateContext([](const MojoTrapEvent&) { NOTREACHED(); });
1072
1073 uintptr_t readable_c_context =
1074 helper.CreateContext([&](const MojoTrapEvent& event) {
1075 EXPECT_EQ(MOJO_RESULT_OK, event.result);
1076 EXPECT_EQ(kTestMessageToC, ReadMessage(c));
1077
1078 // Now rearm the trap.
1079 EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr));
1080
1081 // Should result in no notifications from the above trigger, because the
1082 // trigger will have been removed by the time the event handler can
1083 // execute.
1084 WriteMessage(b, kTestMessageToA);
1085 WriteMessage(b, kTestMessageToA);
1086 EXPECT_EQ(MOJO_RESULT_OK,
1087 MojoRemoveTrigger(t, readable_a_context, nullptr));
1088
1089 // Rearming should be fine now.
1090 EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr));
1091
1092 // Nothing interesting should happen as a result of these.
1093 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
1094 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
1095
1096 wait.Signal();
1097 });
1098
1099 EXPECT_EQ(MOJO_RESULT_OK,
1100 MojoAddTrigger(t, a, MOJO_HANDLE_SIGNAL_READABLE,
1101 MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
1102 readable_a_context, nullptr));
1103 EXPECT_EQ(MOJO_RESULT_OK,
1104 MojoAddTrigger(t, c, MOJO_HANDLE_SIGNAL_READABLE,
1105 MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
1106 readable_c_context, nullptr));
1107 EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr));
1108
1109 WriteMessage(d, kTestMessageToC);
1110 wait.Wait();
1111
1112 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(t));
1113 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(c));
1114 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(d));
1115 }
1116
TEST_F(TrapTest,NestedCancellation)1117 TEST_F(TrapTest, NestedCancellation) {
1118 MojoHandle a, b;
1119 CreateMessagePipe(&a, &b);
1120
1121 MojoHandle c, d;
1122 CreateMessagePipe(&c, &d);
1123
1124 static const char kTestMessageToA[] = "hey a";
1125 static const char kTestMessageToC[] = "hey c";
1126 static const char kTestMessageToD[] = "hey d";
1127
1128 // This is a tricky test. It establishes a trigger on |b| using one trap and
1129 // triggers on |c| and |d| using another trap.
1130 //
1131 // A message is written to |d| to activate |c|'s trigger, and the resuling
1132 // event handler invocation does the folllowing:
1133 // 1. Writes to |a| to eventually activate |b|'s trigger.
1134 // 2. Rearms |c|'s trap.
1135 // 3. Writes to |d| to eventually activate |c|'s trigger again.
1136 //
1137 // Meanwhile, |b|'s event handler removes |c|'s trigger altogether before
1138 // writing to |c| to activate |d|'s trigger.
1139 //
1140 // The net result should be that |c|'s trigger only gets activated once (from
1141 // the first write to |d| above) and everyone else gets notified as expected.
1142
1143 MojoHandle b_trap;
1144 MojoHandle cd_trap;
1145 TriggerHelper helper;
1146 EXPECT_EQ(MOJO_RESULT_OK, helper.CreateTrap(&b_trap));
1147 EXPECT_EQ(MOJO_RESULT_OK, helper.CreateTrap(&cd_trap));
1148
1149 base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::MANUAL,
1150 base::WaitableEvent::InitialState::NOT_SIGNALED);
1151 uintptr_t readable_d_context =
1152 helper.CreateContext([&](const MojoTrapEvent& event) {
1153 EXPECT_EQ(MOJO_RESULT_OK, event.result);
1154 EXPECT_EQ(kTestMessageToD, ReadMessage(d));
1155 wait.Signal();
1156 });
1157
1158 int num_expected_c_notifications = 1;
1159 uintptr_t readable_c_context =
1160 helper.CreateContext([&](const MojoTrapEvent& event) {
1161 EXPECT_EQ(MOJO_RESULT_OK, event.result);
1162 EXPECT_GT(num_expected_c_notifications--, 0);
1163
1164 // Trigger an eventual |readable_b_context| notification.
1165 WriteMessage(a, kTestMessageToA);
1166
1167 EXPECT_EQ(kTestMessageToC, ReadMessage(c));
1168 EXPECT_EQ(MOJO_RESULT_OK,
1169 MojoArmTrap(cd_trap, nullptr, nullptr, nullptr));
1170
1171 // Trigger another eventual |readable_c_context| notification.
1172 WriteMessage(d, kTestMessageToC);
1173 });
1174
1175 uintptr_t readable_b_context =
1176 helper.CreateContext([&](const MojoTrapEvent& event) {
1177 EXPECT_EQ(MOJO_RESULT_OK,
1178 MojoRemoveTrigger(cd_trap, readable_c_context, nullptr));
1179
1180 EXPECT_EQ(MOJO_RESULT_OK,
1181 MojoArmTrap(cd_trap, nullptr, nullptr, nullptr));
1182
1183 WriteMessage(c, kTestMessageToD);
1184 });
1185
1186 EXPECT_EQ(MOJO_RESULT_OK,
1187 MojoAddTrigger(b_trap, b, MOJO_HANDLE_SIGNAL_READABLE,
1188 MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
1189 readable_b_context, nullptr));
1190 EXPECT_EQ(MOJO_RESULT_OK,
1191 MojoAddTrigger(cd_trap, c, MOJO_HANDLE_SIGNAL_READABLE,
1192 MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
1193 readable_c_context, nullptr));
1194 EXPECT_EQ(MOJO_RESULT_OK,
1195 MojoAddTrigger(cd_trap, d, MOJO_HANDLE_SIGNAL_READABLE,
1196 MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
1197 readable_d_context, nullptr));
1198
1199 EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(b_trap, nullptr, nullptr, nullptr));
1200 EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(cd_trap, nullptr, nullptr, nullptr));
1201
1202 WriteMessage(d, kTestMessageToC);
1203 wait.Wait();
1204
1205 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(cd_trap));
1206 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b_trap));
1207 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
1208 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
1209 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(c));
1210 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(d));
1211 }
1212
TEST_F(TrapTest,RemoveSelfWithinEventHandler)1213 TEST_F(TrapTest, RemoveSelfWithinEventHandler) {
1214 MojoHandle a, b;
1215 CreateMessagePipe(&a, &b);
1216
1217 static const char kTestMessageToA[] = "hey a";
1218
1219 MojoHandle t;
1220 TriggerHelper helper;
1221 EXPECT_EQ(MOJO_RESULT_OK, helper.CreateTrap(&t));
1222
1223 base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::MANUAL,
1224 base::WaitableEvent::InitialState::NOT_SIGNALED);
1225
1226 static uintptr_t readable_a_context =
1227 helper.CreateContext([&](const MojoTrapEvent& event) {
1228 EXPECT_EQ(MOJO_RESULT_OK, event.result);
1229
1230 // There should be no problem removing this trigger from its own
1231 // notification invocation.
1232 EXPECT_EQ(MOJO_RESULT_OK,
1233 MojoRemoveTrigger(t, readable_a_context, nullptr));
1234 EXPECT_EQ(kTestMessageToA, ReadMessage(a));
1235
1236 // Arming should fail because there are no longer any registered
1237 // triggers on the trap.
1238 EXPECT_EQ(MOJO_RESULT_NOT_FOUND,
1239 MojoArmTrap(t, nullptr, nullptr, nullptr));
1240
1241 // And closing |a| should be fine (and should not invoke this
1242 // notification with MOJO_RESULT_CANCELLED) for the same reason.
1243 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
1244
1245 wait.Signal();
1246 });
1247
1248 EXPECT_EQ(MOJO_RESULT_OK,
1249 MojoAddTrigger(t, a, MOJO_HANDLE_SIGNAL_READABLE,
1250 MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
1251 readable_a_context, nullptr));
1252 EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr));
1253
1254 WriteMessage(b, kTestMessageToA);
1255 wait.Wait();
1256
1257 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
1258 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(t));
1259 }
1260
TEST_F(TrapTest,CloseTrapWithinEventHandler)1261 TEST_F(TrapTest, CloseTrapWithinEventHandler) {
1262 MojoHandle a, b;
1263 CreateMessagePipe(&a, &b);
1264
1265 static const char kTestMessageToA1[] = "hey a";
1266 static const char kTestMessageToA2[] = "hey a again";
1267
1268 MojoHandle t;
1269 TriggerHelper helper;
1270 EXPECT_EQ(MOJO_RESULT_OK, helper.CreateTrap(&t));
1271
1272 base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::MANUAL,
1273 base::WaitableEvent::InitialState::NOT_SIGNALED);
1274
1275 uintptr_t readable_a_context =
1276 helper.CreateContext([&](const MojoTrapEvent& event) {
1277 EXPECT_EQ(MOJO_RESULT_OK, event.result);
1278 EXPECT_EQ(kTestMessageToA1, ReadMessage(a));
1279 EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr));
1280
1281 // There should be no problem closing this trap from its own
1282 // notification callback.
1283 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(t));
1284
1285 // And these should not trigger more notifications, because |t| has been
1286 // closed already.
1287 WriteMessage(b, kTestMessageToA2);
1288 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
1289 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
1290
1291 wait.Signal();
1292 });
1293
1294 EXPECT_EQ(MOJO_RESULT_OK,
1295 MojoAddTrigger(t, a, MOJO_HANDLE_SIGNAL_READABLE,
1296 MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
1297 readable_a_context, nullptr));
1298 EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr));
1299
1300 WriteMessage(b, kTestMessageToA1);
1301 wait.Wait();
1302 }
1303
TEST_F(TrapTest,CloseTrapAfterImplicitTriggerRemoval)1304 TEST_F(TrapTest, CloseTrapAfterImplicitTriggerRemoval) {
1305 MojoHandle a, b;
1306 CreateMessagePipe(&a, &b);
1307
1308 static const char kTestMessageToA[] = "hey a";
1309
1310 MojoHandle t;
1311 TriggerHelper helper;
1312 EXPECT_EQ(MOJO_RESULT_OK, helper.CreateTrap(&t));
1313
1314 base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::MANUAL,
1315 base::WaitableEvent::InitialState::NOT_SIGNALED);
1316
1317 uintptr_t readable_a_context =
1318 helper.CreateContext([&](const MojoTrapEvent& event) {
1319 EXPECT_EQ(MOJO_RESULT_OK, event.result);
1320 EXPECT_EQ(kTestMessageToA, ReadMessage(a));
1321 EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr));
1322
1323 // This will cue up a notification for |MOJO_RESULT_CANCELLED|...
1324 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
1325
1326 // ...but it should never fire because we close the trap here.
1327 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(t));
1328
1329 wait.Signal();
1330 });
1331
1332 EXPECT_EQ(MOJO_RESULT_OK,
1333 MojoAddTrigger(t, a, MOJO_HANDLE_SIGNAL_READABLE,
1334 MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
1335 readable_a_context, nullptr));
1336 EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr));
1337
1338 WriteMessage(b, kTestMessageToA);
1339 wait.Wait();
1340
1341 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
1342 }
1343
TEST_F(TrapTest,OtherThreadRemovesTriggerDuringEventHandler)1344 TEST_F(TrapTest, OtherThreadRemovesTriggerDuringEventHandler) {
1345 MojoHandle a, b;
1346 CreateMessagePipe(&a, &b);
1347
1348 static const char kTestMessageToA[] = "hey a";
1349
1350 MojoHandle t;
1351 TriggerHelper helper;
1352 EXPECT_EQ(MOJO_RESULT_OK, helper.CreateTrap(&t));
1353
1354 base::WaitableEvent wait_for_notification(
1355 base::WaitableEvent::ResetPolicy::MANUAL,
1356 base::WaitableEvent::InitialState::NOT_SIGNALED);
1357
1358 base::WaitableEvent wait_for_cancellation(
1359 base::WaitableEvent::ResetPolicy::MANUAL,
1360 base::WaitableEvent::InitialState::NOT_SIGNALED);
1361
1362 static bool callback_done = false;
1363 uintptr_t readable_a_context = helper.CreateContextWithCancel(
1364 [&](const MojoTrapEvent& event) {
1365 EXPECT_EQ(MOJO_RESULT_OK, event.result);
1366 EXPECT_EQ(kTestMessageToA, ReadMessage(a));
1367
1368 wait_for_notification.Signal();
1369
1370 // Give the other thread sufficient time to race with the completion
1371 // of this callback. There should be no race, since the cancellation
1372 // notification must be mutually exclusive to this notification.
1373 base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1));
1374
1375 callback_done = true;
1376 },
1377 [&] {
1378 EXPECT_TRUE(callback_done);
1379 wait_for_cancellation.Signal();
1380 });
1381
1382 ThreadedRunner runner(base::BindOnce(base::BindLambdaForTesting([&] {
1383 wait_for_notification.Wait();
1384
1385 // Cancel the watch while the notification is still running.
1386 EXPECT_EQ(MOJO_RESULT_OK,
1387 MojoRemoveTrigger(t, readable_a_context, nullptr));
1388
1389 wait_for_cancellation.Wait();
1390
1391 EXPECT_TRUE(callback_done);
1392 })));
1393 runner.Start();
1394
1395 EXPECT_EQ(MOJO_RESULT_OK,
1396 MojoAddTrigger(t, a, MOJO_HANDLE_SIGNAL_READABLE,
1397 MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
1398 readable_a_context, nullptr));
1399 EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr));
1400
1401 WriteMessage(b, kTestMessageToA);
1402 runner.Join();
1403
1404 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
1405 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(t));
1406 }
1407
TEST_F(TrapTest,TriggersRemoveEachOtherWithinEventHandlers)1408 TEST_F(TrapTest, TriggersRemoveEachOtherWithinEventHandlers) {
1409 MojoHandle a, b;
1410 CreateMessagePipe(&a, &b);
1411
1412 static const char kTestMessageToA[] = "hey a";
1413 static const char kTestMessageToB[] = "hey b";
1414
1415 base::WaitableEvent wait_for_a_to_notify(
1416 base::WaitableEvent::ResetPolicy::MANUAL,
1417 base::WaitableEvent::InitialState::NOT_SIGNALED);
1418 base::WaitableEvent wait_for_b_to_notify(
1419 base::WaitableEvent::ResetPolicy::MANUAL,
1420 base::WaitableEvent::InitialState::NOT_SIGNALED);
1421 base::WaitableEvent wait_for_a_to_cancel(
1422 base::WaitableEvent::ResetPolicy::MANUAL,
1423 base::WaitableEvent::InitialState::NOT_SIGNALED);
1424 base::WaitableEvent wait_for_b_to_cancel(
1425 base::WaitableEvent::ResetPolicy::MANUAL,
1426 base::WaitableEvent::InitialState::NOT_SIGNALED);
1427
1428 MojoHandle a_trap;
1429 MojoHandle b_trap;
1430 TriggerHelper helper;
1431 EXPECT_EQ(MOJO_RESULT_OK, helper.CreateTrap(&a_trap));
1432 EXPECT_EQ(MOJO_RESULT_OK, helper.CreateTrap(&b_trap));
1433
1434 // We set up two traps, one triggered on |a| readability and one triggered on
1435 // |b| readability. Each removes the other's trigger from within its own event
1436 // handler. This should be safe, i.e., it should not deadlock in spite of the
1437 // fact that we also guarantee mutually exclusive event handler invocation
1438 // (including cancellations) on any given trap.
1439 bool a_cancelled = false;
1440 bool b_cancelled = false;
1441 static uintptr_t readable_b_context;
1442 uintptr_t readable_a_context = helper.CreateContextWithCancel(
1443 [&](const MojoTrapEvent& event) {
1444 EXPECT_EQ(MOJO_RESULT_OK, event.result);
1445 EXPECT_EQ(kTestMessageToA, ReadMessage(a));
1446 wait_for_a_to_notify.Signal();
1447 wait_for_b_to_notify.Wait();
1448 EXPECT_EQ(MOJO_RESULT_OK,
1449 MojoRemoveTrigger(b_trap, readable_b_context, nullptr));
1450 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b_trap));
1451 },
1452 [&] {
1453 a_cancelled = true;
1454 wait_for_a_to_cancel.Signal();
1455 wait_for_b_to_cancel.Wait();
1456 });
1457
1458 readable_b_context = helper.CreateContextWithCancel(
1459 [&](const MojoTrapEvent& event) {
1460 EXPECT_EQ(MOJO_RESULT_OK, event.result);
1461 EXPECT_EQ(kTestMessageToB, ReadMessage(b));
1462 wait_for_b_to_notify.Signal();
1463 wait_for_a_to_notify.Wait();
1464 EXPECT_EQ(MOJO_RESULT_OK,
1465 MojoRemoveTrigger(a_trap, readable_a_context, nullptr));
1466 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a_trap));
1467 },
1468 [&] {
1469 b_cancelled = true;
1470 wait_for_b_to_cancel.Signal();
1471 wait_for_a_to_cancel.Wait();
1472 });
1473
1474 EXPECT_EQ(MOJO_RESULT_OK,
1475 MojoAddTrigger(a_trap, a, MOJO_HANDLE_SIGNAL_READABLE,
1476 MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
1477 readable_a_context, nullptr));
1478 EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(a_trap, nullptr, nullptr, nullptr));
1479 EXPECT_EQ(MOJO_RESULT_OK,
1480 MojoAddTrigger(b_trap, b, MOJO_HANDLE_SIGNAL_READABLE,
1481 MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
1482 readable_b_context, nullptr));
1483 EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(b_trap, nullptr, nullptr, nullptr));
1484
1485 ThreadedRunner runner(base::BindOnce(
1486 [](MojoHandle b) { WriteMessage(b, kTestMessageToA); }, b));
1487 runner.Start();
1488
1489 WriteMessage(a, kTestMessageToB);
1490
1491 wait_for_a_to_cancel.Wait();
1492 wait_for_b_to_cancel.Wait();
1493 runner.Join();
1494
1495 EXPECT_TRUE(a_cancelled);
1496 EXPECT_TRUE(b_cancelled);
1497
1498 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
1499 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
1500 }
1501
TEST_F(TrapTest,AlwaysCancel)1502 TEST_F(TrapTest, AlwaysCancel) {
1503 // Basic sanity check to ensure that all possible ways to remove a trigger
1504 // result in a final MOJO_RESULT_CANCELLED notification.
1505
1506 MojoHandle a, b;
1507 CreateMessagePipe(&a, &b);
1508
1509 MojoHandle t;
1510 TriggerHelper helper;
1511 EXPECT_EQ(MOJO_RESULT_OK, helper.CreateTrap(&t));
1512
1513 base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::MANUAL,
1514 base::WaitableEvent::InitialState::NOT_SIGNALED);
1515 auto ignore_event = [](const MojoTrapEvent&) {};
1516 auto signal_wait = [&] { wait.Signal(); };
1517
1518 // Cancel via |MojoRemoveTrigger()|.
1519 uintptr_t context = helper.CreateContextWithCancel(ignore_event, signal_wait);
1520 EXPECT_EQ(MOJO_RESULT_OK,
1521 MojoAddTrigger(t, a, MOJO_HANDLE_SIGNAL_READABLE,
1522 MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, context,
1523 nullptr));
1524 EXPECT_EQ(MOJO_RESULT_OK, MojoRemoveTrigger(t, context, nullptr));
1525 wait.Wait();
1526 wait.Reset();
1527
1528 // Cancel by closing the trigger's watched handle.
1529 context = helper.CreateContextWithCancel(ignore_event, signal_wait);
1530 EXPECT_EQ(MOJO_RESULT_OK,
1531 MojoAddTrigger(t, a, MOJO_HANDLE_SIGNAL_READABLE,
1532 MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, context,
1533 nullptr));
1534 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
1535 wait.Wait();
1536 wait.Reset();
1537
1538 // Cancel by closing the trap handle.
1539 context = helper.CreateContextWithCancel(ignore_event, signal_wait);
1540 EXPECT_EQ(MOJO_RESULT_OK,
1541 MojoAddTrigger(t, b, MOJO_HANDLE_SIGNAL_READABLE,
1542 MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, context,
1543 nullptr));
1544 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(t));
1545 wait.Wait();
1546
1547 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
1548 }
1549
TEST_F(TrapTest,ArmFailureCirculation)1550 TEST_F(TrapTest, ArmFailureCirculation) {
1551 // Sanity check to ensure that all ready trigger events will eventually be
1552 // returned over a finite number of calls to MojoArmTrap().
1553
1554 constexpr size_t kNumTestPipes = 100;
1555 constexpr size_t kNumTestHandles = kNumTestPipes * 2;
1556 MojoHandle handles[kNumTestHandles];
1557
1558 // Create a bunch of pipes and make sure they're all readable.
1559 for (size_t i = 0; i < kNumTestPipes; ++i) {
1560 CreateMessagePipe(&handles[i], &handles[i + kNumTestPipes]);
1561 WriteMessage(handles[i], "hey");
1562 WriteMessage(handles[i + kNumTestPipes], "hay");
1563 WaitForSignals(handles[i], MOJO_HANDLE_SIGNAL_READABLE);
1564 WaitForSignals(handles[i + kNumTestPipes], MOJO_HANDLE_SIGNAL_READABLE);
1565 }
1566
1567 // Create a trap and watch all of them for readability.
1568 MojoHandle t;
1569 EXPECT_EQ(MOJO_RESULT_OK, MojoCreateTrap(&ExpectOnlyCancel, nullptr, &t));
1570 for (size_t i = 0; i < kNumTestHandles; ++i) {
1571 EXPECT_EQ(
1572 MOJO_RESULT_OK,
1573 MojoAddTrigger(t, handles[i], MOJO_HANDLE_SIGNAL_READABLE,
1574 MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, i, nullptr));
1575 }
1576
1577 // Keep trying to arm |t| until every trigger gets an entry in
1578 // |ready_contexts|. If MojoArmTrap() is well-behaved, this should terminate
1579 // eventually.
1580 std::set<uintptr_t> ready_contexts;
1581 while (ready_contexts.size() < kNumTestHandles) {
1582 uint32_t num_blocking_events = 1;
1583 MojoTrapEvent blocking_event = {sizeof(blocking_event)};
1584 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
1585 MojoArmTrap(t, nullptr, &num_blocking_events, &blocking_event));
1586 EXPECT_EQ(1u, num_blocking_events);
1587 EXPECT_EQ(MOJO_RESULT_OK, blocking_event.result);
1588 ready_contexts.insert(blocking_event.trigger_context);
1589 }
1590
1591 for (size_t i = 0; i < kNumTestHandles; ++i)
1592 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(handles[i]));
1593 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(t));
1594 }
1595
TEST_F(TrapTest,TriggerOnUnsatisfiedSignals)1596 TEST_F(TrapTest, TriggerOnUnsatisfiedSignals) {
1597 MojoHandle a, b;
1598 CreateMessagePipe(&a, &b);
1599
1600 base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::MANUAL,
1601 base::WaitableEvent::InitialState::NOT_SIGNALED);
1602 TriggerHelper helper;
1603 const uintptr_t readable_a_context =
1604 helper.CreateContext([&](const MojoTrapEvent& event) {
1605 EXPECT_EQ(MOJO_RESULT_OK, event.result);
1606 wait.Signal();
1607 });
1608
1609 MojoHandle t;
1610 EXPECT_EQ(MOJO_RESULT_OK, helper.CreateTrap(&t));
1611 EXPECT_EQ(MOJO_RESULT_OK,
1612 MojoAddTrigger(t, a, MOJO_HANDLE_SIGNAL_READABLE,
1613 MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
1614 readable_a_context, nullptr));
1615 EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr));
1616
1617 const char kMessage[] = "this is not a message";
1618
1619 WriteMessage(b, kMessage);
1620 wait.Wait();
1621
1622 // Now we know |a| is readable. Remove the trigger and add a new one to watch
1623 // for a not-readable state.
1624 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(t));
1625 const uintptr_t not_readable_a_context =
1626 helper.CreateContext([&](const MojoTrapEvent& event) {
1627 EXPECT_EQ(MOJO_RESULT_OK, event.result);
1628 wait.Signal();
1629 });
1630 EXPECT_EQ(MOJO_RESULT_OK, helper.CreateTrap(&t));
1631 EXPECT_EQ(MOJO_RESULT_OK,
1632 MojoAddTrigger(t, a, MOJO_HANDLE_SIGNAL_READABLE,
1633 MOJO_TRIGGER_CONDITION_SIGNALS_UNSATISFIED,
1634 not_readable_a_context, nullptr));
1635 EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr));
1636
1637 // This should not block, because the event should be signaled by
1638 // |not_readable_a_context| when we read the only available message off of
1639 // |a|.
1640 wait.Reset();
1641 EXPECT_EQ(kMessage, ReadMessage(a));
1642 wait.Wait();
1643
1644 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(t));
1645 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
1646 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
1647 }
1648
1649 base::Closure g_do_random_thing_callback;
1650
ReadAllMessages(const MojoTrapEvent * event)1651 void ReadAllMessages(const MojoTrapEvent* event) {
1652 if (event->result == MOJO_RESULT_OK) {
1653 MojoHandle handle = static_cast<MojoHandle>(event->trigger_context);
1654 MojoMessageHandle message;
1655 while (MojoReadMessage(handle, nullptr, &message) == MOJO_RESULT_OK)
1656 MojoDestroyMessage(message);
1657 }
1658
1659 constexpr size_t kNumRandomThingsToDoOnNotify = 5;
1660 for (size_t i = 0; i < kNumRandomThingsToDoOnNotify; ++i)
1661 g_do_random_thing_callback.Run();
1662 }
1663
RandomHandle(MojoHandle * handles,size_t size)1664 MojoHandle RandomHandle(MojoHandle* handles, size_t size) {
1665 return handles[base::RandInt(0, static_cast<int>(size) - 1)];
1666 }
1667
DoRandomThing(MojoHandle * traps,size_t num_traps,MojoHandle * watched_handles,size_t num_watched_handles)1668 void DoRandomThing(MojoHandle* traps,
1669 size_t num_traps,
1670 MojoHandle* watched_handles,
1671 size_t num_watched_handles) {
1672 switch (base::RandInt(0, 10)) {
1673 case 0:
1674 MojoClose(RandomHandle(traps, num_traps));
1675 break;
1676 case 1:
1677 MojoClose(RandomHandle(watched_handles, num_watched_handles));
1678 break;
1679 case 2:
1680 case 3:
1681 case 4: {
1682 MojoMessageHandle message;
1683 ASSERT_EQ(MOJO_RESULT_OK, MojoCreateMessage(nullptr, &message));
1684 ASSERT_EQ(MOJO_RESULT_OK,
1685 MojoSetMessageContext(message, 1, nullptr, nullptr, nullptr));
1686 MojoWriteMessage(RandomHandle(watched_handles, num_watched_handles),
1687 message, nullptr);
1688 break;
1689 }
1690 case 5:
1691 case 6: {
1692 MojoHandle t = RandomHandle(traps, num_traps);
1693 MojoHandle h = RandomHandle(watched_handles, num_watched_handles);
1694 MojoAddTrigger(t, h, MOJO_HANDLE_SIGNAL_READABLE,
1695 MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
1696 static_cast<uintptr_t>(h), nullptr);
1697 break;
1698 }
1699 case 7:
1700 case 8: {
1701 uint32_t num_blocking_events = 1;
1702 MojoTrapEvent blocking_event = {sizeof(blocking_event)};
1703 if (MojoArmTrap(RandomHandle(traps, num_traps), nullptr,
1704 &num_blocking_events,
1705 &blocking_event) == MOJO_RESULT_FAILED_PRECONDITION &&
1706 blocking_event.result == MOJO_RESULT_OK) {
1707 ReadAllMessages(&blocking_event);
1708 }
1709 break;
1710 }
1711 case 9:
1712 case 10: {
1713 MojoHandle t = RandomHandle(traps, num_traps);
1714 MojoHandle h = RandomHandle(watched_handles, num_watched_handles);
1715 MojoRemoveTrigger(t, static_cast<uintptr_t>(h), nullptr);
1716 break;
1717 }
1718 default:
1719 NOTREACHED();
1720 break;
1721 }
1722 }
1723
TEST_F(TrapTest,ConcurrencyStressTest)1724 TEST_F(TrapTest, ConcurrencyStressTest) {
1725 // Regression test for https://crbug.com/740044. Exercises racy usage of the
1726 // trap API to weed out potential crashes.
1727
1728 constexpr size_t kNumTraps = 50;
1729 constexpr size_t kNumWatchedHandles = 50;
1730 static_assert(kNumWatchedHandles % 2 == 0, "Invalid number of test handles.");
1731
1732 constexpr size_t kNumThreads = 10;
1733 static constexpr size_t kNumOperationsPerThread = 400;
1734
1735 MojoHandle traps[kNumTraps];
1736 MojoHandle watched_handles[kNumWatchedHandles];
1737 g_do_random_thing_callback = base::BindRepeating(
1738 &DoRandomThing, traps, kNumTraps, watched_handles, kNumWatchedHandles);
1739
1740 for (size_t i = 0; i < kNumTraps; ++i)
1741 MojoCreateTrap(&ReadAllMessages, nullptr, &traps[i]);
1742 for (size_t i = 0; i < kNumWatchedHandles; i += 2)
1743 CreateMessagePipe(&watched_handles[i], &watched_handles[i + 1]);
1744
1745 std::unique_ptr<ThreadedRunner> threads[kNumThreads];
1746 for (size_t i = 0; i < kNumThreads; ++i) {
1747 threads[i] = std::make_unique<ThreadedRunner>(base::BindOnce([] {
1748 for (size_t i = 0; i < kNumOperationsPerThread; ++i)
1749 g_do_random_thing_callback.Run();
1750 }));
1751 threads[i]->Start();
1752 }
1753 for (size_t i = 0; i < kNumThreads; ++i)
1754 threads[i]->Join();
1755 for (size_t i = 0; i < kNumTraps; ++i)
1756 MojoClose(traps[i]);
1757 for (size_t i = 0; i < kNumWatchedHandles; ++i)
1758 MojoClose(watched_handles[i]);
1759 }
1760
1761 } // namespace
1762 } // namespace core
1763 } // namespace mojo
1764