diff options
Diffstat (limited to 'mojo/edk/system/watcher_unittest.cc')
-rw-r--r-- | mojo/edk/system/watcher_unittest.cc | 1637 |
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 |