• 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 <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