aboutsummaryrefslogtreecommitdiff
path: root/mojo/edk/system/watcher_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'mojo/edk/system/watcher_unittest.cc')
-rw-r--r--mojo/edk/system/watcher_unittest.cc1637
1 files changed, 0 insertions, 1637 deletions
diff --git a/mojo/edk/system/watcher_unittest.cc b/mojo/edk/system/watcher_unittest.cc
deleted file mode 100644
index dd396cd..0000000
--- a/mojo/edk/system/watcher_unittest.cc
+++ /dev/null
@@ -1,1637 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <stdint.h>
-
-#include <map>
-#include <memory>
-#include <set>
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/synchronization/waitable_event.h"
-#include "base/threading/platform_thread.h"
-#include "base/threading/simple_thread.h"
-#include "base/time/time.h"
-#include "mojo/edk/test/mojo_test_base.h"
-#include "mojo/public/c/system/data_pipe.h"
-#include "mojo/public/c/system/types.h"
-#include "mojo/public/c/system/watcher.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace mojo {
-namespace edk {
-namespace {
-
-using WatcherTest = test::MojoTestBase;
-
-class WatchHelper {
- public:
- using ContextCallback =
- base::Callback<void(MojoResult, MojoHandleSignalsState)>;
-
- WatchHelper() {}
- ~WatchHelper() {}
-
- MojoResult CreateWatcher(MojoHandle* handle) {
- return MojoCreateWatcher(&Notify, handle);
- }
-
- uintptr_t CreateContext(const ContextCallback& callback) {
- return CreateContextWithCancel(callback, base::Closure());
- }
-
- uintptr_t CreateContextWithCancel(const ContextCallback& callback,
- const base::Closure& cancel_callback) {
- auto context = base::MakeUnique<NotificationContext>(callback);
- NotificationContext* raw_context = context.get();
- raw_context->SetCancelCallback(base::Bind(
- [](std::unique_ptr<NotificationContext> context,
- const base::Closure& cancel_callback) {
- if (cancel_callback)
- cancel_callback.Run();
- },
- base::Passed(&context), cancel_callback));
- return reinterpret_cast<uintptr_t>(raw_context);
- }
-
- private:
- class NotificationContext {
- public:
- explicit NotificationContext(const ContextCallback& callback)
- : callback_(callback) {}
-
- ~NotificationContext() {}
-
- void SetCancelCallback(const base::Closure& cancel_callback) {
- cancel_callback_ = cancel_callback;
- }
-
- void Notify(MojoResult result, MojoHandleSignalsState state) {
- if (result == MOJO_RESULT_CANCELLED)
- cancel_callback_.Run();
- else
- callback_.Run(result, state);
- }
-
- private:
- const ContextCallback callback_;
- base::Closure cancel_callback_;
-
- DISALLOW_COPY_AND_ASSIGN(NotificationContext);
- };
-
- static void Notify(uintptr_t context,
- MojoResult result,
- MojoHandleSignalsState state,
- MojoWatcherNotificationFlags flags) {
- reinterpret_cast<NotificationContext*>(context)->Notify(result, state);
- }
-
- DISALLOW_COPY_AND_ASSIGN(WatchHelper);
-};
-
-class ThreadedRunner : public base::SimpleThread {
- public:
- explicit ThreadedRunner(const base::Closure& callback)
- : SimpleThread("ThreadedRunner"), callback_(callback) {}
- ~ThreadedRunner() override {}
-
- void Run() override { callback_.Run(); }
-
- private:
- const base::Closure callback_;
-
- DISALLOW_COPY_AND_ASSIGN(ThreadedRunner);
-};
-
-void ExpectNoNotification(uintptr_t context,
- MojoResult result,
- MojoHandleSignalsState state,
- MojoWatcherNotificationFlags flags) {
- NOTREACHED();
-}
-
-void ExpectOnlyCancel(uintptr_t context,
- MojoResult result,
- MojoHandleSignalsState state,
- MojoWatcherNotificationFlags flags) {
- EXPECT_EQ(result, MOJO_RESULT_CANCELLED);
-}
-
-TEST_F(WatcherTest, InvalidArguments) {
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- MojoCreateWatcher(&ExpectNoNotification, nullptr));
- MojoHandle w;
- EXPECT_EQ(MOJO_RESULT_OK, MojoCreateWatcher(&ExpectNoNotification, &w));
-
- // Try to watch unwatchable handles.
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- MojoWatch(w, w, MOJO_HANDLE_SIGNAL_READABLE, 0));
- MojoHandle buffer_handle = CreateBuffer(42);
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- MojoWatch(w, buffer_handle, MOJO_HANDLE_SIGNAL_READABLE, 0));
-
- // Try to cancel a watch on an invalid watcher handle.
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoCancelWatch(buffer_handle, 0));
-
- // Try to arm an invalid handle.
- EXPECT_EQ(
- MOJO_RESULT_INVALID_ARGUMENT,
- MojoArmWatcher(MOJO_HANDLE_INVALID, nullptr, nullptr, nullptr, nullptr));
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- MojoArmWatcher(buffer_handle, nullptr, nullptr, nullptr, nullptr));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(buffer_handle));
-
- // Try to arm with a non-null count but at least one null output buffer.
- uint32_t num_ready_contexts = 1;
- uintptr_t ready_context;
- MojoResult ready_result;
- MojoHandleSignalsState ready_state;
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- MojoArmWatcher(w, &num_ready_contexts, nullptr, &ready_result,
- &ready_state));
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- MojoArmWatcher(w, &num_ready_contexts, &ready_context, nullptr,
- &ready_state));
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- MojoArmWatcher(w, &num_ready_contexts, &ready_context,
- &ready_result, nullptr));
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w));
-}
-
-TEST_F(WatcherTest, WatchMessagePipeReadable) {
- MojoHandle a, b;
- CreateMessagePipe(&a, &b);
-
- base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
- WatchHelper helper;
- int num_expected_notifications = 1;
- const uintptr_t readable_a_context = helper.CreateContext(base::Bind(
- [](base::WaitableEvent* event, int* expected_count, MojoResult result,
- MojoHandleSignalsState state) {
- EXPECT_GT(*expected_count, 0);
- *expected_count -= 1;
-
- EXPECT_EQ(MOJO_RESULT_OK, result);
- event->Signal();
- },
- &event, &num_expected_notifications));
-
- MojoHandle w;
- EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, readable_a_context));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- const char kMessage1[] = "hey hey hey hey";
- const char kMessage2[] = "i said hey";
- const char kMessage3[] = "what's goin' on?";
-
- // Writing to |b| multiple times should notify exactly once.
- WriteMessage(b, kMessage1);
- WriteMessage(b, kMessage2);
- event.Wait();
-
- // This also shouldn't fire a notification; the watcher is still disarmed.
- WriteMessage(b, kMessage3);
-
- // Arming should fail with relevant information.
- constexpr size_t kMaxReadyContexts = 10;
- uint32_t num_ready_contexts = kMaxReadyContexts;
- uintptr_t ready_contexts[kMaxReadyContexts];
- MojoResult ready_results[kMaxReadyContexts];
- MojoHandleSignalsState ready_states[kMaxReadyContexts];
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
- MojoArmWatcher(w, &num_ready_contexts, ready_contexts,
- ready_results, ready_states));
- EXPECT_EQ(1u, num_ready_contexts);
- EXPECT_EQ(readable_a_context, ready_contexts[0]);
- EXPECT_EQ(MOJO_RESULT_OK, ready_results[0]);
-
- // Flush the three messages from above.
- EXPECT_EQ(kMessage1, ReadMessage(a));
- EXPECT_EQ(kMessage2, ReadMessage(a));
- EXPECT_EQ(kMessage3, ReadMessage(a));
-
- // Now we can rearm the watcher.
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
-}
-
-TEST_F(WatcherTest, CloseWatchedMessagePipeHandle) {
- MojoHandle a, b;
- CreateMessagePipe(&a, &b);
-
- base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
- WatchHelper helper;
- const uintptr_t readable_a_context = helper.CreateContextWithCancel(
- WatchHelper::ContextCallback(),
- base::Bind([](base::WaitableEvent* event) { event->Signal(); }, &event));
-
- MojoHandle w;
- EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, readable_a_context));
-
- // Test that closing a watched handle fires an appropriate notification, even
- // when the watcher is unarmed.
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
- event.Wait();
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w));
-}
-
-TEST_F(WatcherTest, CloseWatchedMessagePipeHandlePeer) {
- MojoHandle a, b;
- CreateMessagePipe(&a, &b);
-
- base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
- WatchHelper helper;
- const uintptr_t readable_a_context = helper.CreateContext(base::Bind(
- [](base::WaitableEvent* event, MojoResult result,
- MojoHandleSignalsState state) {
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result);
- event->Signal();
- },
- &event));
-
- MojoHandle w;
- EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, readable_a_context));
-
- // Test that closing a watched handle's peer with an armed watcher fires an
- // appropriate notification.
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
- event.Wait();
-
- // And now arming should fail with correct information about |a|'s state.
- constexpr size_t kMaxReadyContexts = 10;
- uint32_t num_ready_contexts = kMaxReadyContexts;
- uintptr_t ready_contexts[kMaxReadyContexts];
- MojoResult ready_results[kMaxReadyContexts];
- MojoHandleSignalsState ready_states[kMaxReadyContexts];
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
- MojoArmWatcher(w, &num_ready_contexts, ready_contexts,
- ready_results, ready_states));
- EXPECT_EQ(1u, num_ready_contexts);
- EXPECT_EQ(readable_a_context, ready_contexts[0]);
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, ready_results[0]);
- EXPECT_TRUE(ready_states[0].satisfied_signals &
- MOJO_HANDLE_SIGNAL_PEER_CLOSED);
- EXPECT_FALSE(ready_states[0].satisfiable_signals &
- MOJO_HANDLE_SIGNAL_READABLE);
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
-}
-
-TEST_F(WatcherTest, WatchDataPipeConsumerReadable) {
- constexpr size_t kTestPipeCapacity = 64;
- MojoHandle producer, consumer;
- CreateDataPipe(&producer, &consumer, kTestPipeCapacity);
-
- base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
- WatchHelper helper;
- int num_expected_notifications = 1;
- const uintptr_t readable_consumer_context = helper.CreateContext(base::Bind(
- [](base::WaitableEvent* event, int* expected_count, MojoResult result,
- MojoHandleSignalsState state) {
- EXPECT_GT(*expected_count, 0);
- *expected_count -= 1;
-
- EXPECT_EQ(MOJO_RESULT_OK, result);
- event->Signal();
- },
- &event, &num_expected_notifications));
-
- MojoHandle w;
- EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w));
- EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(w, consumer, MOJO_HANDLE_SIGNAL_READABLE,
- readable_consumer_context));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- const char kMessage1[] = "hey hey hey hey";
- const char kMessage2[] = "i said hey";
- const char kMessage3[] = "what's goin' on?";
-
- // Writing to |producer| multiple times should notify exactly once.
- WriteData(producer, kMessage1);
- WriteData(producer, kMessage2);
- event.Wait();
-
- // This also shouldn't fire a notification; the watcher is still disarmed.
- WriteData(producer, kMessage3);
-
- // Arming should fail with relevant information.
- constexpr size_t kMaxReadyContexts = 10;
- uint32_t num_ready_contexts = kMaxReadyContexts;
- uintptr_t ready_contexts[kMaxReadyContexts];
- MojoResult ready_results[kMaxReadyContexts];
- MojoHandleSignalsState ready_states[kMaxReadyContexts];
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
- MojoArmWatcher(w, &num_ready_contexts, ready_contexts,
- ready_results, ready_states));
- EXPECT_EQ(1u, num_ready_contexts);
- EXPECT_EQ(readable_consumer_context, ready_contexts[0]);
- EXPECT_EQ(MOJO_RESULT_OK, ready_results[0]);
-
- // Flush the three messages from above.
- EXPECT_EQ(kMessage1, ReadData(consumer, sizeof(kMessage1) - 1));
- EXPECT_EQ(kMessage2, ReadData(consumer, sizeof(kMessage2) - 1));
- EXPECT_EQ(kMessage3, ReadData(consumer, sizeof(kMessage3) - 1));
-
- // Now we can rearm the watcher.
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(producer));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(consumer));
-}
-
-TEST_F(WatcherTest, WatchDataPipeConsumerNewDataReadable) {
- constexpr size_t kTestPipeCapacity = 64;
- MojoHandle producer, consumer;
- CreateDataPipe(&producer, &consumer, kTestPipeCapacity);
-
- base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
- WatchHelper helper;
- int num_new_data_notifications = 0;
- const uintptr_t new_data_context = helper.CreateContext(base::Bind(
- [](base::WaitableEvent* event, int* notification_count, MojoResult result,
- MojoHandleSignalsState state) {
- *notification_count += 1;
-
- EXPECT_EQ(MOJO_RESULT_OK, result);
- event->Signal();
- },
- &event, &num_new_data_notifications));
-
- MojoHandle w;
- EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoWatch(w, consumer, MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- new_data_context));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- const char kMessage1[] = "hey hey hey hey";
- const char kMessage2[] = "i said hey";
- const char kMessage3[] = "what's goin' on?";
-
- // Writing to |producer| multiple times should notify exactly once.
- WriteData(producer, kMessage1);
- WriteData(producer, kMessage2);
- event.Wait();
-
- // This also shouldn't fire a notification; the watcher is still disarmed.
- WriteData(producer, kMessage3);
-
- // Arming should fail with relevant information.
- constexpr size_t kMaxReadyContexts = 10;
- uint32_t num_ready_contexts = kMaxReadyContexts;
- uintptr_t ready_contexts[kMaxReadyContexts];
- MojoResult ready_results[kMaxReadyContexts];
- MojoHandleSignalsState ready_states[kMaxReadyContexts];
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
- MojoArmWatcher(w, &num_ready_contexts, ready_contexts,
- ready_results, ready_states));
- EXPECT_EQ(1u, num_ready_contexts);
- EXPECT_EQ(new_data_context, ready_contexts[0]);
- EXPECT_EQ(MOJO_RESULT_OK, ready_results[0]);
-
- // Attempt to read more data than is available. Should fail but clear the
- // NEW_DATA_READABLE signal.
- char large_buffer[512];
- uint32_t large_read_size = 512;
- EXPECT_EQ(MOJO_RESULT_OUT_OF_RANGE,
- MojoReadData(consumer, large_buffer, &large_read_size,
- MOJO_READ_DATA_FLAG_ALL_OR_NONE));
-
- // Attempt to arm again. Should succeed.
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- // Write more data. Should notify.
- event.Reset();
- WriteData(producer, kMessage1);
- event.Wait();
-
- // Reading some data should clear NEW_DATA_READABLE again so we can rearm.
- EXPECT_EQ(kMessage1, ReadData(consumer, sizeof(kMessage1) - 1));
-
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- EXPECT_EQ(2, num_new_data_notifications);
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(producer));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(consumer));
-}
-
-TEST_F(WatcherTest, WatchDataPipeProducerWritable) {
- constexpr size_t kTestPipeCapacity = 8;
- MojoHandle producer, consumer;
- CreateDataPipe(&producer, &consumer, kTestPipeCapacity);
-
- // Half the capacity of the data pipe.
- const char kTestData[] = "aaaa";
- static_assert((sizeof(kTestData) - 1) * 2 == kTestPipeCapacity,
- "Invalid test data for this test.");
-
- base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
- WatchHelper helper;
- int num_expected_notifications = 1;
- const uintptr_t writable_producer_context = helper.CreateContext(base::Bind(
- [](base::WaitableEvent* event, int* expected_count, MojoResult result,
- MojoHandleSignalsState state) {
- EXPECT_GT(*expected_count, 0);
- *expected_count -= 1;
-
- EXPECT_EQ(MOJO_RESULT_OK, result);
- event->Signal();
- },
- &event, &num_expected_notifications));
-
- MojoHandle w;
- EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w));
- EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(w, producer, MOJO_HANDLE_SIGNAL_WRITABLE,
- writable_producer_context));
-
- // The producer is already writable, so arming should fail with relevant
- // information.
- constexpr size_t kMaxReadyContexts = 10;
- uint32_t num_ready_contexts = kMaxReadyContexts;
- uintptr_t ready_contexts[kMaxReadyContexts];
- MojoResult ready_results[kMaxReadyContexts];
- MojoHandleSignalsState ready_states[kMaxReadyContexts];
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
- MojoArmWatcher(w, &num_ready_contexts, ready_contexts,
- ready_results, ready_states));
- EXPECT_EQ(1u, num_ready_contexts);
- EXPECT_EQ(writable_producer_context, ready_contexts[0]);
- EXPECT_EQ(MOJO_RESULT_OK, ready_results[0]);
- EXPECT_TRUE(ready_states[0].satisfied_signals & MOJO_HANDLE_SIGNAL_WRITABLE);
-
- // Write some data, but don't fill the pipe yet. Arming should fail again.
- WriteData(producer, kTestData);
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
- MojoArmWatcher(w, &num_ready_contexts, ready_contexts,
- ready_results, ready_states));
- EXPECT_EQ(1u, num_ready_contexts);
- EXPECT_EQ(writable_producer_context, ready_contexts[0]);
- EXPECT_EQ(MOJO_RESULT_OK, ready_results[0]);
- EXPECT_TRUE(ready_states[0].satisfied_signals & MOJO_HANDLE_SIGNAL_WRITABLE);
-
- // Write more data, filling the pipe to capacity. Arming should succeed now.
- WriteData(producer, kTestData);
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- // Now read from the pipe, making the producer writable again. Should notify.
- EXPECT_EQ(kTestData, ReadData(consumer, sizeof(kTestData) - 1));
- event.Wait();
-
- // Arming should fail again.
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
- MojoArmWatcher(w, &num_ready_contexts, ready_contexts,
- ready_results, ready_states));
- EXPECT_EQ(1u, num_ready_contexts);
- EXPECT_EQ(writable_producer_context, ready_contexts[0]);
- EXPECT_EQ(MOJO_RESULT_OK, ready_results[0]);
- EXPECT_TRUE(ready_states[0].satisfied_signals & MOJO_HANDLE_SIGNAL_WRITABLE);
-
- // Fill the pipe once more and arm the watcher. Should succeed.
- WriteData(producer, kTestData);
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(producer));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(consumer));
-};
-
-TEST_F(WatcherTest, CloseWatchedDataPipeConsumerHandle) {
- constexpr size_t kTestPipeCapacity = 8;
- MojoHandle producer, consumer;
- CreateDataPipe(&producer, &consumer, kTestPipeCapacity);
-
- base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
- WatchHelper helper;
- const uintptr_t readable_consumer_context = helper.CreateContextWithCancel(
- WatchHelper::ContextCallback(),
- base::Bind([](base::WaitableEvent* event) { event->Signal(); }, &event));
-
- MojoHandle w;
- EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w));
- EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(w, consumer, MOJO_HANDLE_SIGNAL_READABLE,
- readable_consumer_context));
-
- // Closing the consumer should fire a cancellation notification.
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(consumer));
- event.Wait();
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(producer));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w));
-}
-
-TEST_F(WatcherTest, CloseWatcherDataPipeConsumerHandlePeer) {
- constexpr size_t kTestPipeCapacity = 8;
- MojoHandle producer, consumer;
- CreateDataPipe(&producer, &consumer, kTestPipeCapacity);
-
- base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
- WatchHelper helper;
- const uintptr_t readable_consumer_context = helper.CreateContext(base::Bind(
- [](base::WaitableEvent* event, MojoResult result,
- MojoHandleSignalsState state) {
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result);
- event->Signal();
- },
- &event));
-
- MojoHandle w;
- EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w));
- EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(w, consumer, MOJO_HANDLE_SIGNAL_READABLE,
- readable_consumer_context));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- // Closing the producer should fire a notification for an unsatisfiable watch.
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(producer));
- event.Wait();
-
- // Now attempt to rearm and expect appropriate error feedback.
- constexpr size_t kMaxReadyContexts = 10;
- uint32_t num_ready_contexts = kMaxReadyContexts;
- uintptr_t ready_contexts[kMaxReadyContexts];
- MojoResult ready_results[kMaxReadyContexts];
- MojoHandleSignalsState ready_states[kMaxReadyContexts];
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
- MojoArmWatcher(w, &num_ready_contexts, ready_contexts,
- ready_results, ready_states));
- EXPECT_EQ(1u, num_ready_contexts);
- EXPECT_EQ(readable_consumer_context, ready_contexts[0]);
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, ready_results[0]);
- EXPECT_FALSE(ready_states[0].satisfiable_signals &
- MOJO_HANDLE_SIGNAL_READABLE);
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(consumer));
-}
-
-TEST_F(WatcherTest, CloseWatchedDataPipeProducerHandle) {
- constexpr size_t kTestPipeCapacity = 8;
- MojoHandle producer, consumer;
- CreateDataPipe(&producer, &consumer, kTestPipeCapacity);
-
- base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
- WatchHelper helper;
- const uintptr_t writable_producer_context = helper.CreateContextWithCancel(
- WatchHelper::ContextCallback(),
- base::Bind([](base::WaitableEvent* event) { event->Signal(); }, &event));
-
- MojoHandle w;
- EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w));
- EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(w, producer, MOJO_HANDLE_SIGNAL_WRITABLE,
- writable_producer_context));
-
- // Closing the consumer should fire a cancellation notification.
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(producer));
- event.Wait();
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(consumer));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w));
-}
-
-TEST_F(WatcherTest, CloseWatchedDataPipeProducerHandlePeer) {
- constexpr size_t kTestPipeCapacity = 8;
- MojoHandle producer, consumer;
- CreateDataPipe(&producer, &consumer, kTestPipeCapacity);
-
- const char kTestMessageFullCapacity[] = "xxxxxxxx";
- static_assert(sizeof(kTestMessageFullCapacity) - 1 == kTestPipeCapacity,
- "Invalid test message size for this test.");
-
- // Make the pipe unwritable initially.
- WriteData(producer, kTestMessageFullCapacity);
-
- base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
- WatchHelper helper;
- const uintptr_t writable_producer_context = helper.CreateContext(base::Bind(
- [](base::WaitableEvent* event, MojoResult result,
- MojoHandleSignalsState state) {
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result);
- event->Signal();
- },
- &event));
-
- MojoHandle w;
- EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w));
- EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(w, producer, MOJO_HANDLE_SIGNAL_WRITABLE,
- writable_producer_context));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- // Closing the consumer should fire a notification for an unsatisfiable watch,
- // as the full data pipe can never be read from again and is therefore
- // permanently full and unwritable.
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(consumer));
- event.Wait();
-
- // Now attempt to rearm and expect appropriate error feedback.
- constexpr size_t kMaxReadyContexts = 10;
- uint32_t num_ready_contexts = kMaxReadyContexts;
- uintptr_t ready_contexts[kMaxReadyContexts];
- MojoResult ready_results[kMaxReadyContexts];
- MojoHandleSignalsState ready_states[kMaxReadyContexts];
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
- MojoArmWatcher(w, &num_ready_contexts, ready_contexts,
- ready_results, ready_states));
- EXPECT_EQ(1u, num_ready_contexts);
- EXPECT_EQ(writable_producer_context, ready_contexts[0]);
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, ready_results[0]);
- EXPECT_FALSE(ready_states[0].satisfiable_signals &
- MOJO_HANDLE_SIGNAL_WRITABLE);
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(producer));
-}
-
-TEST_F(WatcherTest, ArmWithNoWatches) {
- MojoHandle w;
- EXPECT_EQ(MOJO_RESULT_OK, MojoCreateWatcher(&ExpectNoNotification, &w));
- EXPECT_EQ(MOJO_RESULT_NOT_FOUND,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w));
-}
-
-TEST_F(WatcherTest, WatchDuplicateContext) {
- MojoHandle a, b;
- CreateMessagePipe(&a, &b);
-
- MojoHandle w;
- EXPECT_EQ(MOJO_RESULT_OK, MojoCreateWatcher(&ExpectOnlyCancel, &w));
- EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, 0));
- EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS,
- MojoWatch(w, b, MOJO_HANDLE_SIGNAL_READABLE, 0));
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
-}
-
-TEST_F(WatcherTest, CancelUnknownWatch) {
- MojoHandle w;
- EXPECT_EQ(MOJO_RESULT_OK, MojoCreateWatcher(&ExpectNoNotification, &w));
- EXPECT_EQ(MOJO_RESULT_NOT_FOUND, MojoCancelWatch(w, 1234));
-}
-
-TEST_F(WatcherTest, ArmWithWatchAlreadySatisfied) {
- MojoHandle a, b;
- CreateMessagePipe(&a, &b);
-
- MojoHandle w;
- EXPECT_EQ(MOJO_RESULT_OK, MojoCreateWatcher(&ExpectOnlyCancel, &w));
- EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(w, a, MOJO_HANDLE_SIGNAL_WRITABLE, 0));
-
- // |a| is always writable, so we can never arm this watcher.
- constexpr size_t kMaxReadyContexts = 10;
- uint32_t num_ready_contexts = kMaxReadyContexts;
- uintptr_t ready_contexts[kMaxReadyContexts];
- MojoResult ready_results[kMaxReadyContexts];
- MojoHandleSignalsState ready_states[kMaxReadyContexts];
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
- MojoArmWatcher(w, &num_ready_contexts, ready_contexts,
- ready_results, ready_states));
- EXPECT_EQ(1u, num_ready_contexts);
- EXPECT_EQ(0u, ready_contexts[0]);
- EXPECT_EQ(MOJO_RESULT_OK, ready_results[0]);
- EXPECT_TRUE(ready_states[0].satisfied_signals & MOJO_HANDLE_SIGNAL_WRITABLE);
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
-}
-
-TEST_F(WatcherTest, ArmWithWatchAlreadyUnsatisfiable) {
- MojoHandle a, b;
- CreateMessagePipe(&a, &b);
-
- MojoHandle w;
- EXPECT_EQ(MOJO_RESULT_OK, MojoCreateWatcher(&ExpectOnlyCancel, &w));
- EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, 0));
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
-
- // |b| is closed and never wrote any messages, so |a| won't be readable again.
- // MojoArmWatcher() should fail, incidcating as much.
- constexpr size_t kMaxReadyContexts = 10;
- uint32_t num_ready_contexts = kMaxReadyContexts;
- uintptr_t ready_contexts[kMaxReadyContexts];
- MojoResult ready_results[kMaxReadyContexts];
- MojoHandleSignalsState ready_states[kMaxReadyContexts];
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
- MojoArmWatcher(w, &num_ready_contexts, ready_contexts,
- ready_results, ready_states));
- EXPECT_EQ(1u, num_ready_contexts);
- EXPECT_EQ(0u, ready_contexts[0]);
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, ready_results[0]);
- EXPECT_TRUE(ready_states[0].satisfied_signals &
- MOJO_HANDLE_SIGNAL_PEER_CLOSED);
- EXPECT_FALSE(ready_states[0].satisfiable_signals &
- MOJO_HANDLE_SIGNAL_READABLE);
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
-}
-
-TEST_F(WatcherTest, MultipleWatches) {
- MojoHandle a, b;
- CreateMessagePipe(&a, &b);
-
- base::WaitableEvent a_event(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
- base::WaitableEvent b_event(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
- WatchHelper helper;
- int num_a_notifications = 0;
- int num_b_notifications = 0;
- auto notify_callback =
- base::Bind([](base::WaitableEvent* event, int* notification_count,
- MojoResult result, MojoHandleSignalsState state) {
- *notification_count += 1;
- EXPECT_EQ(MOJO_RESULT_OK, result);
- event->Signal();
- });
- uintptr_t readable_a_context = helper.CreateContext(
- base::Bind(notify_callback, &a_event, &num_a_notifications));
- uintptr_t readable_b_context = helper.CreateContext(
- base::Bind(notify_callback, &b_event, &num_b_notifications));
-
- MojoHandle w;
- EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w));
-
- // Add two independent watch contexts to watch for |a| or |b| readability.
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, readable_a_context));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoWatch(w, b, MOJO_HANDLE_SIGNAL_READABLE, readable_b_context));
-
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- const char kMessage1[] = "things are happening";
- const char kMessage2[] = "ok. ok. ok. ok.";
- const char kMessage3[] = "plz wake up";
-
- // Writing to |b| should signal |a|'s watch.
- WriteMessage(b, kMessage1);
- a_event.Wait();
- a_event.Reset();
-
- // Subsequent messages on |b| should not trigger another notification.
- WriteMessage(b, kMessage2);
- WriteMessage(b, kMessage3);
-
- // Messages on |a| also shouldn't trigger |b|'s notification, since the
- // watcher should be disarmed by now.
- WriteMessage(a, kMessage1);
- WriteMessage(a, kMessage2);
- WriteMessage(a, kMessage3);
-
- // Arming should fail. Since we only ask for at most one context's information
- // that's all we should get back. Which one we get is unspecified.
- constexpr size_t kMaxReadyContexts = 10;
- uint32_t num_ready_contexts = 1;
- uintptr_t ready_contexts[kMaxReadyContexts];
- MojoResult ready_results[kMaxReadyContexts];
- MojoHandleSignalsState ready_states[kMaxReadyContexts];
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
- MojoArmWatcher(w, &num_ready_contexts, ready_contexts,
- ready_results, ready_states));
- EXPECT_EQ(1u, num_ready_contexts);
- EXPECT_TRUE(ready_contexts[0] == readable_a_context ||
- ready_contexts[0] == readable_b_context);
- EXPECT_EQ(MOJO_RESULT_OK, ready_results[0]);
- EXPECT_TRUE(ready_states[0].satisfied_signals & MOJO_HANDLE_SIGNAL_WRITABLE);
-
- // Now try arming again, verifying that both contexts are returned.
- num_ready_contexts = kMaxReadyContexts;
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
- MojoArmWatcher(w, &num_ready_contexts, ready_contexts,
- ready_results, ready_states));
- EXPECT_EQ(2u, num_ready_contexts);
- EXPECT_EQ(MOJO_RESULT_OK, ready_results[0]);
- EXPECT_EQ(MOJO_RESULT_OK, ready_results[1]);
- EXPECT_TRUE(ready_states[0].satisfied_signals & MOJO_HANDLE_SIGNAL_WRITABLE);
- EXPECT_TRUE(ready_states[1].satisfied_signals & MOJO_HANDLE_SIGNAL_WRITABLE);
- EXPECT_TRUE((ready_contexts[0] == readable_a_context &&
- ready_contexts[1] == readable_b_context) ||
- (ready_contexts[0] == readable_b_context &&
- ready_contexts[1] == readable_a_context));
-
- // Flush out the test messages so we should be able to successfully rearm.
- EXPECT_EQ(kMessage1, ReadMessage(a));
- EXPECT_EQ(kMessage2, ReadMessage(a));
- EXPECT_EQ(kMessage3, ReadMessage(a));
- EXPECT_EQ(kMessage1, ReadMessage(b));
- EXPECT_EQ(kMessage2, ReadMessage(b));
- EXPECT_EQ(kMessage3, ReadMessage(b));
-
- // Add a watch which is always satisfied, so we can't arm. Arming should fail
- // with only this new watch's information.
- uintptr_t writable_c_context = helper.CreateContext(base::Bind(
- [](MojoResult result, MojoHandleSignalsState state) { NOTREACHED(); }));
- MojoHandle c, d;
- CreateMessagePipe(&c, &d);
-
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoWatch(w, c, MOJO_HANDLE_SIGNAL_WRITABLE, writable_c_context));
- num_ready_contexts = kMaxReadyContexts;
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
- MojoArmWatcher(w, &num_ready_contexts, ready_contexts,
- ready_results, ready_states));
- EXPECT_EQ(1u, num_ready_contexts);
- EXPECT_EQ(writable_c_context, ready_contexts[0]);
- EXPECT_EQ(MOJO_RESULT_OK, ready_results[0]);
- EXPECT_TRUE(ready_states[0].satisfied_signals & MOJO_HANDLE_SIGNAL_WRITABLE);
-
- // Cancel the new watch and arming should succeed once again.
- EXPECT_EQ(MOJO_RESULT_OK, MojoCancelWatch(w, writable_c_context));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(c));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(d));
-}
-
-TEST_F(WatcherTest, NotifyOtherFromNotificationCallback) {
- MojoHandle a, b;
- CreateMessagePipe(&a, &b);
-
- static const char kTestMessageToA[] = "hello a";
- static const char kTestMessageToB[] = "hello b";
-
- base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
-
- WatchHelper helper;
- MojoHandle w;
- EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w));
-
- uintptr_t readable_a_context = helper.CreateContext(base::Bind(
- [](MojoHandle w, MojoHandle a, MojoResult result,
- MojoHandleSignalsState state) {
- EXPECT_EQ(MOJO_RESULT_OK, result);
- EXPECT_EQ("hello a", ReadMessage(a));
-
- // Re-arm the watcher and signal |b|.
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
- WriteMessage(a, kTestMessageToB);
- },
- w, a));
-
- uintptr_t readable_b_context = helper.CreateContext(base::Bind(
- [](base::WaitableEvent* event, MojoHandle w, MojoHandle b,
- MojoResult result, MojoHandleSignalsState state) {
- EXPECT_EQ(MOJO_RESULT_OK, result);
- EXPECT_EQ(kTestMessageToB, ReadMessage(b));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
- event->Signal();
- },
- &event, w, b));
-
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, readable_a_context));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoWatch(w, b, MOJO_HANDLE_SIGNAL_READABLE, readable_b_context));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- // Send a message to |a|. The relevant watch context should be notified, and
- // should in turn send a message to |b|, waking up the other context. The
- // second context signals |event|.
- WriteMessage(b, kTestMessageToA);
- event.Wait();
-}
-
-TEST_F(WatcherTest, NotifySelfFromNotificationCallback) {
- MojoHandle a, b;
- CreateMessagePipe(&a, &b);
-
- static const char kTestMessageToA[] = "hello a";
-
- base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
-
- WatchHelper helper;
- MojoHandle w;
- EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w));
-
- int expected_notifications = 10;
- uintptr_t readable_a_context = helper.CreateContext(base::Bind(
- [](int* expected_count, MojoHandle w, MojoHandle a, MojoHandle b,
- base::WaitableEvent* event, MojoResult result,
- MojoHandleSignalsState state) {
- EXPECT_EQ(MOJO_RESULT_OK, result);
- EXPECT_EQ("hello a", ReadMessage(a));
-
- EXPECT_GT(*expected_count, 0);
- *expected_count -= 1;
- if (*expected_count == 0) {
- event->Signal();
- return;
- } else {
- // Re-arm the watcher and signal |a| again.
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
- WriteMessage(b, kTestMessageToA);
- }
- },
- &expected_notifications, w, a, b, &event));
-
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, readable_a_context));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- // Send a message to |a|. When the watch above is notified, it will rearm and
- // send another message to |a|. This will happen until
- // |expected_notifications| reaches 0.
- WriteMessage(b, kTestMessageToA);
- event.Wait();
-}
-
-TEST_F(WatcherTest, ImplicitCancelOtherFromNotificationCallback) {
- MojoHandle a, b;
- CreateMessagePipe(&a, &b);
-
- MojoHandle c, d;
- CreateMessagePipe(&c, &d);
-
- static const char kTestMessageToA[] = "hi a";
- static const char kTestMessageToC[] = "hi c";
-
- base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
-
- WatchHelper helper;
- MojoHandle w;
- EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w));
-
- uintptr_t readable_a_context = helper.CreateContextWithCancel(
- base::Bind([](MojoResult result, MojoHandleSignalsState state) {
- NOTREACHED();
- }),
- base::Bind([](base::WaitableEvent* event) { event->Signal(); }, &event));
-
- uintptr_t readable_c_context = helper.CreateContext(base::Bind(
- [](MojoHandle w, MojoHandle a, MojoHandle b, MojoHandle c,
- MojoResult result, MojoHandleSignalsState state) {
- EXPECT_EQ(MOJO_RESULT_OK, result);
- EXPECT_EQ(kTestMessageToC, ReadMessage(c));
-
- // Now rearm the watcher.
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- // Must result in exactly ONE notification on the above context, for
- // CANCELLED only. Because we cannot dispatch notifications until the
- // stack unwinds, and because we must never dispatch non-cancellation
- // notifications for a handle once it's been closed, we must be certain
- // that cancellation due to closure preemptively invalidates any
- // pending non-cancellation notifications queued on the current
- // RequestContext, such as the one resulting from the WriteMessage here.
- WriteMessage(b, kTestMessageToA);
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
-
- // Rearming should be fine since |a|'s watch should already be
- // implicitly cancelled (even though the notification will not have
- // been invoked yet.)
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- // Nothing interesting should happen as a result of this.
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
- },
- w, a, b, c));
-
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, readable_a_context));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoWatch(w, c, MOJO_HANDLE_SIGNAL_READABLE, readable_c_context));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- WriteMessage(d, kTestMessageToC);
- event.Wait();
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(c));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(d));
-}
-
-TEST_F(WatcherTest, ExplicitCancelOtherFromNotificationCallback) {
- MojoHandle a, b;
- CreateMessagePipe(&a, &b);
-
- MojoHandle c, d;
- CreateMessagePipe(&c, &d);
-
- static const char kTestMessageToA[] = "hi a";
- static const char kTestMessageToC[] = "hi c";
-
- base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
-
- WatchHelper helper;
- MojoHandle w;
- EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w));
-
- uintptr_t readable_a_context = helper.CreateContext(base::Bind(
- [](MojoResult result, MojoHandleSignalsState state) { NOTREACHED(); }));
-
- uintptr_t readable_c_context = helper.CreateContext(base::Bind(
- [](base::WaitableEvent* event, uintptr_t readable_a_context, MojoHandle w,
- MojoHandle a, MojoHandle b, MojoHandle c, MojoResult result,
- MojoHandleSignalsState state) {
- EXPECT_EQ(MOJO_RESULT_OK, result);
- EXPECT_EQ(kTestMessageToC, ReadMessage(c));
-
- // Now rearm the watcher.
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- // Should result in no notifications on the above context, because the
- // watch will have been cancelled by the time the notification callback
- // can execute.
- WriteMessage(b, kTestMessageToA);
- WriteMessage(b, kTestMessageToA);
- EXPECT_EQ(MOJO_RESULT_OK, MojoCancelWatch(w, readable_a_context));
-
- // Rearming should be fine now.
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- // Nothing interesting should happen as a result of these.
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
-
- event->Signal();
- },
- &event, readable_a_context, w, a, b, c));
-
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, readable_a_context));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoWatch(w, c, MOJO_HANDLE_SIGNAL_READABLE, readable_c_context));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- WriteMessage(d, kTestMessageToC);
- event.Wait();
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(c));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(d));
-}
-
-TEST_F(WatcherTest, NestedCancellation) {
- MojoHandle a, b;
- CreateMessagePipe(&a, &b);
-
- MojoHandle c, d;
- CreateMessagePipe(&c, &d);
-
- static const char kTestMessageToA[] = "hey a";
- static const char kTestMessageToC[] = "hey c";
- static const char kTestMessageToD[] = "hey d";
-
- // This is a tricky test. It establishes a watch on |b| using one watcher and
- // watches on |c| and |d| using another watcher.
- //
- // A message is written to |d| to wake up |c|'s watch, and the notification
- // handler for that event does the following:
- // 1. Writes to |a| to eventually wake up |b|'s watcher.
- // 2. Rearms |c|'s watcher.
- // 3. Writes to |d| to eventually wake up |c|'s watcher again.
- //
- // Meanwhile, |b|'s watch notification handler cancels |c|'s watch altogether
- // before writing to |c| to wake up |d|.
- //
- // The net result should be that |c|'s context only gets notified once (from
- // the first write to |d| above) and everyone else gets notified as expected.
-
- MojoHandle b_watcher;
- MojoHandle cd_watcher;
- WatchHelper helper;
- EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&b_watcher));
- EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&cd_watcher));
-
- base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
- uintptr_t readable_d_context = helper.CreateContext(base::Bind(
- [](base::WaitableEvent* event, MojoHandle d, MojoResult result,
- MojoHandleSignalsState state) {
- EXPECT_EQ(MOJO_RESULT_OK, result);
- EXPECT_EQ(kTestMessageToD, ReadMessage(d));
- event->Signal();
- },
- &event, d));
-
- static int num_expected_c_notifications = 1;
- uintptr_t readable_c_context = helper.CreateContext(base::Bind(
- [](MojoHandle cd_watcher, MojoHandle a, MojoHandle c, MojoHandle d,
- MojoResult result, MojoHandleSignalsState state) {
- EXPECT_EQ(MOJO_RESULT_OK, result);
- EXPECT_GT(num_expected_c_notifications--, 0);
-
- // Trigger an eventual |readable_b_context| notification.
- WriteMessage(a, kTestMessageToA);
-
- EXPECT_EQ(kTestMessageToC, ReadMessage(c));
- EXPECT_EQ(MOJO_RESULT_OK, MojoArmWatcher(cd_watcher, nullptr, nullptr,
- nullptr, nullptr));
-
- // Trigger another eventual |readable_c_context| notification.
- WriteMessage(d, kTestMessageToC);
- },
- cd_watcher, a, c, d));
-
- uintptr_t readable_b_context = helper.CreateContext(base::Bind(
- [](MojoHandle cd_watcher, uintptr_t readable_c_context, MojoHandle c,
- MojoResult result, MojoHandleSignalsState state) {
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoCancelWatch(cd_watcher, readable_c_context));
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoArmWatcher(cd_watcher, nullptr, nullptr,
- nullptr, nullptr));
-
- WriteMessage(c, kTestMessageToD);
- },
- cd_watcher, readable_c_context, c));
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(b_watcher, b, MOJO_HANDLE_SIGNAL_READABLE,
- readable_b_context));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoWatch(cd_watcher, c, MOJO_HANDLE_SIGNAL_READABLE,
- readable_c_context));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoWatch(cd_watcher, d, MOJO_HANDLE_SIGNAL_READABLE,
- readable_d_context));
-
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(b_watcher, nullptr, nullptr, nullptr, nullptr));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(cd_watcher, nullptr, nullptr, nullptr, nullptr));
-
- WriteMessage(d, kTestMessageToC);
- event.Wait();
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(cd_watcher));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b_watcher));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(c));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(d));
-}
-
-TEST_F(WatcherTest, CancelSelfInNotificationCallback) {
- MojoHandle a, b;
- CreateMessagePipe(&a, &b);
-
- static const char kTestMessageToA[] = "hey a";
-
- MojoHandle w;
- WatchHelper helper;
- EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w));
-
- base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
-
- static uintptr_t readable_a_context = helper.CreateContext(base::Bind(
- [](base::WaitableEvent* event, MojoHandle w, MojoHandle a,
- MojoResult result, MojoHandleSignalsState state) {
- EXPECT_EQ(MOJO_RESULT_OK, result);
-
- // There should be no problem cancelling this watch from its own
- // notification invocation.
- EXPECT_EQ(MOJO_RESULT_OK, MojoCancelWatch(w, readable_a_context));
- EXPECT_EQ(kTestMessageToA, ReadMessage(a));
-
- // Arming should fail because there are no longer any registered
- // watches on the watcher.
- EXPECT_EQ(MOJO_RESULT_NOT_FOUND,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- // And closing |a| should be fine (and should not invoke this
- // notification with MOJO_RESULT_CANCELLED) for the same reason.
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
-
- event->Signal();
- },
- &event, w, a));
-
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, readable_a_context));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- WriteMessage(b, kTestMessageToA);
- event.Wait();
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w));
-}
-
-TEST_F(WatcherTest, CloseWatcherInNotificationCallback) {
- MojoHandle a, b;
- CreateMessagePipe(&a, &b);
-
- static const char kTestMessageToA1[] = "hey a";
- static const char kTestMessageToA2[] = "hey a again";
-
- MojoHandle w;
- WatchHelper helper;
- EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w));
-
- base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
-
- uintptr_t readable_a_context = helper.CreateContext(base::Bind(
- [](base::WaitableEvent* event, MojoHandle w, MojoHandle a, MojoHandle b,
- MojoResult result, MojoHandleSignalsState state) {
- EXPECT_EQ(MOJO_RESULT_OK, result);
- EXPECT_EQ(kTestMessageToA1, ReadMessage(a));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- // There should be no problem closing this watcher from its own
- // notification callback.
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w));
-
- // And these should not trigger more notifications, because |w| has been
- // closed already.
- WriteMessage(b, kTestMessageToA2);
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
-
- event->Signal();
- },
- &event, w, a, b));
-
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, readable_a_context));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- WriteMessage(b, kTestMessageToA1);
- event.Wait();
-}
-
-TEST_F(WatcherTest, CloseWatcherAfterImplicitCancel) {
- MojoHandle a, b;
- CreateMessagePipe(&a, &b);
-
- static const char kTestMessageToA[] = "hey a";
-
- MojoHandle w;
- WatchHelper helper;
- EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w));
-
- base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
-
- uintptr_t readable_a_context = helper.CreateContext(base::Bind(
- [](base::WaitableEvent* event, MojoHandle w, MojoHandle a,
- MojoResult result, MojoHandleSignalsState state) {
- EXPECT_EQ(MOJO_RESULT_OK, result);
- EXPECT_EQ(kTestMessageToA, ReadMessage(a));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- // This will cue up a notification for |MOJO_RESULT_CANCELLED|...
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
-
- // ...but it should never fire because we close the watcher here.
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w));
-
- event->Signal();
- },
- &event, w, a));
-
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, readable_a_context));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- WriteMessage(b, kTestMessageToA);
- event.Wait();
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
-}
-
-TEST_F(WatcherTest, OtherThreadCancelDuringNotification) {
- MojoHandle a, b;
- CreateMessagePipe(&a, &b);
-
- static const char kTestMessageToA[] = "hey a";
-
- MojoHandle w;
- WatchHelper helper;
- EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w));
-
- base::WaitableEvent wait_for_notification(
- base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
-
- base::WaitableEvent wait_for_cancellation(
- base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
-
- static bool callback_done = false;
- uintptr_t readable_a_context = helper.CreateContextWithCancel(
- base::Bind(
- [](base::WaitableEvent* wait_for_notification, MojoHandle w,
- MojoHandle a, MojoResult result, MojoHandleSignalsState state) {
- EXPECT_EQ(MOJO_RESULT_OK, result);
- EXPECT_EQ(kTestMessageToA, ReadMessage(a));
-
- wait_for_notification->Signal();
-
- // Give the other thread sufficient time to race with the completion
- // of this callback. There should be no race, since the cancellation
- // notification must be mutually exclusive to this notification.
- base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1));
-
- callback_done = true;
- },
- &wait_for_notification, w, a),
- base::Bind(
- [](base::WaitableEvent* wait_for_cancellation) {
- EXPECT_TRUE(callback_done);
- wait_for_cancellation->Signal();
- },
- &wait_for_cancellation));
-
- ThreadedRunner runner(base::Bind(
- [](base::WaitableEvent* wait_for_notification,
- base::WaitableEvent* wait_for_cancellation, MojoHandle w,
- uintptr_t readable_a_context) {
- wait_for_notification->Wait();
-
- // Cancel the watch while the notification is still running.
- EXPECT_EQ(MOJO_RESULT_OK, MojoCancelWatch(w, readable_a_context));
-
- wait_for_cancellation->Wait();
-
- EXPECT_TRUE(callback_done);
- },
- &wait_for_notification, &wait_for_cancellation, w, readable_a_context));
- runner.Start();
-
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, readable_a_context));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- WriteMessage(b, kTestMessageToA);
- runner.Join();
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w));
-}
-
-TEST_F(WatcherTest, WatchesCancelEachOtherFromNotifications) {
- MojoHandle a, b;
- CreateMessagePipe(&a, &b);
-
- static const char kTestMessageToA[] = "hey a";
- static const char kTestMessageToB[] = "hey b";
-
- base::WaitableEvent wait_for_a_to_notify(
- base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
- base::WaitableEvent wait_for_b_to_notify(
- base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
- base::WaitableEvent wait_for_a_to_cancel(
- base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
- base::WaitableEvent wait_for_b_to_cancel(
- base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
-
- MojoHandle a_watcher;
- MojoHandle b_watcher;
- WatchHelper helper;
- EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&a_watcher));
- EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&b_watcher));
-
- // We set up two watchers, one on |a| and one on |b|. They cancel each other
- // from within their respective watch notifications. This should be safe,
- // i.e., it should not deadlock, in spite of the fact that we also guarantee
- // mutually exclusive notification execution (including cancellations) on any
- // given watch.
- bool a_cancelled = false;
- bool b_cancelled = false;
- static uintptr_t readable_b_context;
- uintptr_t readable_a_context = helper.CreateContextWithCancel(
- base::Bind(
- [](base::WaitableEvent* wait_for_a_to_notify,
- base::WaitableEvent* wait_for_b_to_notify, MojoHandle b_watcher,
- MojoHandle a, MojoResult result, MojoHandleSignalsState state) {
- EXPECT_EQ(MOJO_RESULT_OK, result);
- EXPECT_EQ(kTestMessageToA, ReadMessage(a));
- wait_for_a_to_notify->Signal();
- wait_for_b_to_notify->Wait();
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoCancelWatch(b_watcher, readable_b_context));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b_watcher));
- },
- &wait_for_a_to_notify, &wait_for_b_to_notify, b_watcher, a),
- base::Bind(
- [](base::WaitableEvent* wait_for_a_to_cancel,
- base::WaitableEvent* wait_for_b_to_cancel, bool* a_cancelled) {
- *a_cancelled = true;
- wait_for_a_to_cancel->Signal();
- wait_for_b_to_cancel->Wait();
- },
- &wait_for_a_to_cancel, &wait_for_b_to_cancel, &a_cancelled));
-
- readable_b_context = helper.CreateContextWithCancel(
- base::Bind(
- [](base::WaitableEvent* wait_for_a_to_notify,
- base::WaitableEvent* wait_for_b_to_notify,
- uintptr_t readable_a_context, MojoHandle a_watcher, MojoHandle b,
- MojoResult result, MojoHandleSignalsState state) {
- EXPECT_EQ(MOJO_RESULT_OK, result);
- EXPECT_EQ(kTestMessageToB, ReadMessage(b));
- wait_for_b_to_notify->Signal();
- wait_for_a_to_notify->Wait();
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoCancelWatch(a_watcher, readable_a_context));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a_watcher));
- },
- &wait_for_a_to_notify, &wait_for_b_to_notify, readable_a_context,
- a_watcher, b),
- base::Bind(
- [](base::WaitableEvent* wait_for_a_to_cancel,
- base::WaitableEvent* wait_for_b_to_cancel, bool* b_cancelled) {
- *b_cancelled = true;
- wait_for_b_to_cancel->Signal();
- wait_for_a_to_cancel->Wait();
- },
- &wait_for_a_to_cancel, &wait_for_b_to_cancel, &b_cancelled));
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(a_watcher, a, MOJO_HANDLE_SIGNAL_READABLE,
- readable_a_context));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(a_watcher, nullptr, nullptr, nullptr, nullptr));
- EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(b_watcher, b, MOJO_HANDLE_SIGNAL_READABLE,
- readable_b_context));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(b_watcher, nullptr, nullptr, nullptr, nullptr));
-
- ThreadedRunner runner(
- base::Bind([](MojoHandle b) { WriteMessage(b, kTestMessageToA); }, b));
- runner.Start();
-
- WriteMessage(a, kTestMessageToB);
-
- wait_for_a_to_cancel.Wait();
- wait_for_b_to_cancel.Wait();
- runner.Join();
-
- EXPECT_TRUE(a_cancelled);
- EXPECT_TRUE(b_cancelled);
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
-}
-
-TEST_F(WatcherTest, AlwaysCancel) {
- // Basic sanity check to ensure that all possible ways to cancel a watch
- // result in a final MOJO_RESULT_CANCELLED notification.
-
- MojoHandle a, b;
- CreateMessagePipe(&a, &b);
-
- MojoHandle w;
- WatchHelper helper;
- EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w));
-
- base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
- const base::Closure signal_event =
- base::Bind(&base::WaitableEvent::Signal, base::Unretained(&event));
-
- // Cancel via |MojoCancelWatch()|.
- uintptr_t context = helper.CreateContextWithCancel(
- WatchHelper::ContextCallback(), signal_event);
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, context));
- EXPECT_EQ(MOJO_RESULT_OK, MojoCancelWatch(w, context));
- event.Wait();
- event.Reset();
-
- // Cancel by closing the watched handle.
- context = helper.CreateContextWithCancel(WatchHelper::ContextCallback(),
- signal_event);
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, context));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
- event.Wait();
- event.Reset();
-
- // Cancel by closing the watcher handle.
- context = helper.CreateContextWithCancel(WatchHelper::ContextCallback(),
- signal_event);
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoWatch(w, b, MOJO_HANDLE_SIGNAL_READABLE, context));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w));
- event.Wait();
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
-}
-
-TEST_F(WatcherTest, ArmFailureCirculation) {
- // Sanity check to ensure that all ready handles will eventually be returned
- // over a finite number of calls to MojoArmWatcher().
-
- constexpr size_t kNumTestPipes = 100;
- constexpr size_t kNumTestHandles = kNumTestPipes * 2;
- MojoHandle handles[kNumTestHandles];
-
- // Create a bunch of pipes and make sure they're all readable.
- for (size_t i = 0; i < kNumTestPipes; ++i) {
- CreateMessagePipe(&handles[i], &handles[i + kNumTestPipes]);
- WriteMessage(handles[i], "hey");
- WriteMessage(handles[i + kNumTestPipes], "hay");
- WaitForSignals(handles[i], MOJO_HANDLE_SIGNAL_READABLE);
- WaitForSignals(handles[i + kNumTestPipes], MOJO_HANDLE_SIGNAL_READABLE);
- }
-
- // Create a watcher and watch all of them.
- MojoHandle w;
- EXPECT_EQ(MOJO_RESULT_OK, MojoCreateWatcher(&ExpectOnlyCancel, &w));
- for (size_t i = 0; i < kNumTestHandles; ++i) {
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoWatch(w, handles[i], MOJO_HANDLE_SIGNAL_READABLE, i));
- }
-
- // Keep trying to arm |w| until every watch gets an entry in |ready_contexts|.
- // If MojoArmWatcher() is well-behaved, this should terminate eventually.
- std::set<uintptr_t> ready_contexts;
- while (ready_contexts.size() < kNumTestHandles) {
- uint32_t num_ready_contexts = 1;
- uintptr_t ready_context;
- MojoResult ready_result;
- MojoHandleSignalsState ready_state;
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
- MojoArmWatcher(w, &num_ready_contexts, &ready_context,
- &ready_result, &ready_state));
- EXPECT_EQ(1u, num_ready_contexts);
- EXPECT_EQ(MOJO_RESULT_OK, ready_result);
- ready_contexts.insert(ready_context);
- }
-
- for (size_t i = 0; i < kNumTestHandles; ++i)
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(handles[i]));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w));
-}
-
-} // namespace
-} // namespace edk
-} // namespace mojo