| Index: mojo/edk/system/watcher_unittest.cc
|
| diff --git a/mojo/edk/system/watcher_unittest.cc b/mojo/edk/system/watcher_unittest.cc
|
| deleted file mode 100644
|
| index a3f27424321d55a6e225da26dce44dff3ec9c1f3..0000000000000000000000000000000000000000
|
| --- a/mojo/edk/system/watcher_unittest.cc
|
| +++ /dev/null
|
| @@ -1,1590 +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 "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));
|
| -}
|
| -
|
| -} // namespace
|
| -} // namespace edk
|
| -} // namespace mojo
|
|
|