Index: mojo/edk/system/message_pipe_dispatcher_unittest.cc |
diff --git a/mojo/edk/system/message_pipe_dispatcher_unittest.cc b/mojo/edk/system/message_pipe_dispatcher_unittest.cc |
deleted file mode 100644 |
index 96ca4367d855ff2e02b4f58d67a0a5014d4cf975..0000000000000000000000000000000000000000 |
--- a/mojo/edk/system/message_pipe_dispatcher_unittest.cc |
+++ /dev/null |
@@ -1,729 +0,0 @@ |
-// Copyright 2013 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. |
- |
-// NOTE(vtl): Some of these tests are inherently flaky (e.g., if run on a |
-// heavily-loaded system). Sorry. |test::EpsilonTimeout()| may be increased to |
-// increase tolerance and reduce observed flakiness (though doing so reduces the |
-// meaningfulness of the test). |
- |
-#include "mojo/edk/system/message_pipe_dispatcher.h" |
- |
-#include <string.h> |
- |
-#include <limits> |
- |
-#include "base/memory/ref_counted.h" |
-#include "base/memory/scoped_vector.h" |
-#include "base/rand_util.h" |
-#include "base/threading/platform_thread.h" // For |Sleep()|. |
-#include "base/threading/simple_thread.h" |
-#include "base/time/time.h" |
-#include "mojo/edk/system/message_pipe.h" |
-#include "mojo/edk/system/test_utils.h" |
-#include "mojo/edk/system/waiter.h" |
-#include "mojo/edk/system/waiter_test_utils.h" |
-#include "testing/gtest/include/gtest/gtest.h" |
- |
-namespace mojo { |
-namespace system { |
-namespace { |
- |
-TEST(MessagePipeDispatcherTest, Basic) { |
- test::Stopwatch stopwatch; |
- int32_t buffer[1]; |
- const uint32_t kBufferSize = static_cast<uint32_t>(sizeof(buffer)); |
- uint32_t buffer_size; |
- |
- // Run this test both with |d0| as port 0, |d1| as port 1 and vice versa. |
- for (unsigned i = 0; i < 2; i++) { |
- scoped_refptr<MessagePipeDispatcher> d0(new MessagePipeDispatcher( |
- MessagePipeDispatcher::kDefaultCreateOptions)); |
- EXPECT_EQ(Dispatcher::kTypeMessagePipe, d0->GetType()); |
- scoped_refptr<MessagePipeDispatcher> d1(new MessagePipeDispatcher( |
- MessagePipeDispatcher::kDefaultCreateOptions)); |
- { |
- scoped_refptr<MessagePipe> mp(MessagePipe::CreateLocalLocal()); |
- d0->Init(mp, i); // 0, 1. |
- d1->Init(mp, i ^ 1); // 1, 0. |
- } |
- Waiter w; |
- uint32_t context = 0; |
- HandleSignalsState hss; |
- |
- // Try adding a writable waiter when already writable. |
- w.Init(); |
- hss = HandleSignalsState(); |
- EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, |
- d0->AddWaiter(&w, MOJO_HANDLE_SIGNAL_WRITABLE, 0, &hss)); |
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); |
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, |
- hss.satisfiable_signals); |
- // Shouldn't need to remove the waiter (it was not added). |
- |
- // Add a readable waiter to |d0|, then make it readable (by writing to |
- // |d1|), then wait. |
- w.Init(); |
- ASSERT_EQ(MOJO_RESULT_OK, |
- d0->AddWaiter(&w, MOJO_HANDLE_SIGNAL_READABLE, 1, nullptr)); |
- buffer[0] = 123456789; |
- EXPECT_EQ(MOJO_RESULT_OK, |
- d1->WriteMessage(UserPointer<const void>(buffer), |
- kBufferSize, |
- nullptr, |
- MOJO_WRITE_MESSAGE_FLAG_NONE)); |
- stopwatch.Start(); |
- EXPECT_EQ(MOJO_RESULT_OK, w.Wait(MOJO_DEADLINE_INDEFINITE, &context)); |
- EXPECT_EQ(1u, context); |
- EXPECT_LT(stopwatch.Elapsed(), test::EpsilonTimeout()); |
- hss = HandleSignalsState(); |
- d0->RemoveWaiter(&w, &hss); |
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, |
- hss.satisfied_signals); |
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, |
- hss.satisfiable_signals); |
- |
- // Try adding a readable waiter when already readable (from above). |
- w.Init(); |
- hss = HandleSignalsState(); |
- EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, |
- d0->AddWaiter(&w, MOJO_HANDLE_SIGNAL_READABLE, 2, &hss)); |
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, |
- hss.satisfied_signals); |
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, |
- hss.satisfiable_signals); |
- // Shouldn't need to remove the waiter (it was not added). |
- |
- // Make |d0| no longer readable (by reading from it). |
- buffer[0] = 0; |
- buffer_size = kBufferSize; |
- EXPECT_EQ(MOJO_RESULT_OK, |
- d0->ReadMessage(UserPointer<void>(buffer), |
- MakeUserPointer(&buffer_size), |
- 0, |
- nullptr, |
- MOJO_READ_MESSAGE_FLAG_NONE)); |
- EXPECT_EQ(kBufferSize, buffer_size); |
- EXPECT_EQ(123456789, buffer[0]); |
- |
- // Wait for zero time for readability on |d0| (will time out). |
- w.Init(); |
- ASSERT_EQ(MOJO_RESULT_OK, |
- d0->AddWaiter(&w, MOJO_HANDLE_SIGNAL_READABLE, 3, nullptr)); |
- stopwatch.Start(); |
- EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, w.Wait(0, nullptr)); |
- EXPECT_LT(stopwatch.Elapsed(), test::EpsilonTimeout()); |
- hss = HandleSignalsState(); |
- d0->RemoveWaiter(&w, &hss); |
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); |
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, |
- hss.satisfiable_signals); |
- |
- // Wait for non-zero, finite time for readability on |d0| (will time out). |
- w.Init(); |
- ASSERT_EQ(MOJO_RESULT_OK, |
- d0->AddWaiter(&w, MOJO_HANDLE_SIGNAL_READABLE, 3, nullptr)); |
- stopwatch.Start(); |
- EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, |
- w.Wait(2 * test::EpsilonTimeout().InMicroseconds(), nullptr)); |
- base::TimeDelta elapsed = stopwatch.Elapsed(); |
- EXPECT_GT(elapsed, (2 - 1) * test::EpsilonTimeout()); |
- EXPECT_LT(elapsed, (2 + 1) * test::EpsilonTimeout()); |
- hss = HandleSignalsState(); |
- d0->RemoveWaiter(&w, &hss); |
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); |
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, |
- hss.satisfiable_signals); |
- |
- EXPECT_EQ(MOJO_RESULT_OK, d0->Close()); |
- EXPECT_EQ(MOJO_RESULT_OK, d1->Close()); |
- } |
-} |
- |
-TEST(MessagePipeDispatcherTest, InvalidParams) { |
- char buffer[1]; |
- |
- scoped_refptr<MessagePipeDispatcher> d0( |
- new MessagePipeDispatcher(MessagePipeDispatcher::kDefaultCreateOptions)); |
- scoped_refptr<MessagePipeDispatcher> d1( |
- new MessagePipeDispatcher(MessagePipeDispatcher::kDefaultCreateOptions)); |
- { |
- scoped_refptr<MessagePipe> mp(MessagePipe::CreateLocalLocal()); |
- d0->Init(mp, 0); |
- d1->Init(mp, 1); |
- } |
- |
- // |WriteMessage|: |
- // Huge buffer size. |
- EXPECT_EQ(MOJO_RESULT_RESOURCE_EXHAUSTED, |
- d0->WriteMessage(UserPointer<const void>(buffer), |
- std::numeric_limits<uint32_t>::max(), |
- nullptr, |
- MOJO_WRITE_MESSAGE_FLAG_NONE)); |
- |
- EXPECT_EQ(MOJO_RESULT_OK, d0->Close()); |
- EXPECT_EQ(MOJO_RESULT_OK, d1->Close()); |
-} |
- |
-// These test invalid arguments that should cause death if we're being paranoid |
-// about checking arguments (which we would want to do if, e.g., we were in a |
-// true "kernel" situation, but we might not want to do otherwise for |
-// performance reasons). Probably blatant errors like passing in null pointers |
-// (for required pointer arguments) will still cause death, but perhaps not |
-// predictably. |
-TEST(MessagePipeDispatcherTest, InvalidParamsDeath) { |
- const char kMemoryCheckFailedRegex[] = "Check failed"; |
- |
- scoped_refptr<MessagePipeDispatcher> d0( |
- new MessagePipeDispatcher(MessagePipeDispatcher::kDefaultCreateOptions)); |
- scoped_refptr<MessagePipeDispatcher> d1( |
- new MessagePipeDispatcher(MessagePipeDispatcher::kDefaultCreateOptions)); |
- { |
- scoped_refptr<MessagePipe> mp(MessagePipe::CreateLocalLocal()); |
- d0->Init(mp, 0); |
- d1->Init(mp, 1); |
- } |
- |
- // |WriteMessage|: |
- // Null buffer with nonzero buffer size. |
- EXPECT_DEATH_IF_SUPPORTED( |
- d0->WriteMessage( |
- NullUserPointer(), 1, nullptr, MOJO_WRITE_MESSAGE_FLAG_NONE), |
- kMemoryCheckFailedRegex); |
- |
- // |ReadMessage|: |
- // Null buffer with nonzero buffer size. |
- // First write something so that we actually have something to read. |
- EXPECT_EQ(MOJO_RESULT_OK, |
- d1->WriteMessage(UserPointer<const void>("x"), |
- 1, |
- nullptr, |
- MOJO_WRITE_MESSAGE_FLAG_NONE)); |
- uint32_t buffer_size = 1; |
- EXPECT_DEATH_IF_SUPPORTED(d0->ReadMessage(NullUserPointer(), |
- MakeUserPointer(&buffer_size), |
- 0, |
- nullptr, |
- MOJO_READ_MESSAGE_FLAG_NONE), |
- kMemoryCheckFailedRegex); |
- |
- EXPECT_EQ(MOJO_RESULT_OK, d0->Close()); |
- EXPECT_EQ(MOJO_RESULT_OK, d1->Close()); |
-} |
- |
-// Test what happens when one end is closed (single-threaded test). |
-TEST(MessagePipeDispatcherTest, BasicClosed) { |
- int32_t buffer[1]; |
- const uint32_t kBufferSize = static_cast<uint32_t>(sizeof(buffer)); |
- uint32_t buffer_size; |
- |
- // Run this test both with |d0| as port 0, |d1| as port 1 and vice versa. |
- for (unsigned i = 0; i < 2; i++) { |
- scoped_refptr<MessagePipeDispatcher> d0(new MessagePipeDispatcher( |
- MessagePipeDispatcher::kDefaultCreateOptions)); |
- scoped_refptr<MessagePipeDispatcher> d1(new MessagePipeDispatcher( |
- MessagePipeDispatcher::kDefaultCreateOptions)); |
- { |
- scoped_refptr<MessagePipe> mp(MessagePipe::CreateLocalLocal()); |
- d0->Init(mp, i); // 0, 1. |
- d1->Init(mp, i ^ 1); // 1, 0. |
- } |
- Waiter w; |
- HandleSignalsState hss; |
- |
- // Write (twice) to |d1|. |
- buffer[0] = 123456789; |
- EXPECT_EQ(MOJO_RESULT_OK, |
- d1->WriteMessage(UserPointer<const void>(buffer), |
- kBufferSize, |
- nullptr, |
- MOJO_WRITE_MESSAGE_FLAG_NONE)); |
- buffer[0] = 234567890; |
- EXPECT_EQ(MOJO_RESULT_OK, |
- d1->WriteMessage(UserPointer<const void>(buffer), |
- kBufferSize, |
- nullptr, |
- MOJO_WRITE_MESSAGE_FLAG_NONE)); |
- |
- // Try waiting for readable on |d0|; should fail (already satisfied). |
- w.Init(); |
- hss = HandleSignalsState(); |
- EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, |
- d0->AddWaiter(&w, MOJO_HANDLE_SIGNAL_READABLE, 0, &hss)); |
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, |
- hss.satisfied_signals); |
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, |
- hss.satisfiable_signals); |
- |
- // Try reading from |d1|; should fail (nothing to read). |
- buffer[0] = 0; |
- buffer_size = kBufferSize; |
- EXPECT_EQ(MOJO_RESULT_SHOULD_WAIT, |
- d1->ReadMessage(UserPointer<void>(buffer), |
- MakeUserPointer(&buffer_size), |
- 0, |
- nullptr, |
- MOJO_READ_MESSAGE_FLAG_NONE)); |
- |
- // Close |d1|. |
- EXPECT_EQ(MOJO_RESULT_OK, d1->Close()); |
- |
- // Try waiting for readable on |d0|; should fail (already satisfied). |
- w.Init(); |
- hss = HandleSignalsState(); |
- EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, |
- d0->AddWaiter(&w, MOJO_HANDLE_SIGNAL_READABLE, 1, &hss)); |
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); |
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); |
- |
- // Read from |d0|. |
- buffer[0] = 0; |
- buffer_size = kBufferSize; |
- EXPECT_EQ(MOJO_RESULT_OK, |
- d0->ReadMessage(UserPointer<void>(buffer), |
- MakeUserPointer(&buffer_size), |
- 0, |
- nullptr, |
- MOJO_READ_MESSAGE_FLAG_NONE)); |
- EXPECT_EQ(kBufferSize, buffer_size); |
- EXPECT_EQ(123456789, buffer[0]); |
- |
- // Try waiting for readable on |d0|; should fail (already satisfied). |
- w.Init(); |
- hss = HandleSignalsState(); |
- EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, |
- d0->AddWaiter(&w, MOJO_HANDLE_SIGNAL_READABLE, 2, &hss)); |
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); |
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); |
- |
- // Read again from |d0|. |
- buffer[0] = 0; |
- buffer_size = kBufferSize; |
- EXPECT_EQ(MOJO_RESULT_OK, |
- d0->ReadMessage(UserPointer<void>(buffer), |
- MakeUserPointer(&buffer_size), |
- 0, |
- nullptr, |
- MOJO_READ_MESSAGE_FLAG_NONE)); |
- EXPECT_EQ(kBufferSize, buffer_size); |
- EXPECT_EQ(234567890, buffer[0]); |
- |
- // Try waiting for readable on |d0|; should fail (unsatisfiable). |
- w.Init(); |
- hss = HandleSignalsState(); |
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, |
- d0->AddWaiter(&w, MOJO_HANDLE_SIGNAL_READABLE, 3, &hss)); |
- EXPECT_EQ(0u, hss.satisfied_signals); |
- EXPECT_EQ(0u, hss.satisfiable_signals); |
- |
- // Try waiting for writable on |d0|; should fail (unsatisfiable). |
- w.Init(); |
- hss = HandleSignalsState(); |
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, |
- d0->AddWaiter(&w, MOJO_HANDLE_SIGNAL_WRITABLE, 4, &hss)); |
- EXPECT_EQ(0u, hss.satisfied_signals); |
- EXPECT_EQ(0u, hss.satisfiable_signals); |
- |
- // Try reading from |d0|; should fail (nothing to read and other end |
- // closed). |
- buffer[0] = 0; |
- buffer_size = kBufferSize; |
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, |
- d0->ReadMessage(UserPointer<void>(buffer), |
- MakeUserPointer(&buffer_size), |
- 0, |
- nullptr, |
- MOJO_READ_MESSAGE_FLAG_NONE)); |
- |
- // Try writing to |d0|; should fail (other end closed). |
- buffer[0] = 345678901; |
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, |
- d0->WriteMessage(UserPointer<const void>(buffer), |
- kBufferSize, |
- nullptr, |
- MOJO_WRITE_MESSAGE_FLAG_NONE)); |
- |
- EXPECT_EQ(MOJO_RESULT_OK, d0->Close()); |
- } |
-} |
- |
-#if defined(OS_WIN) |
-// http://crbug.com/396386 |
-#define MAYBE_BasicThreaded DISABLED_BasicThreaded |
-#else |
-#define MAYBE_BasicThreaded BasicThreaded |
-#endif |
-TEST(MessagePipeDispatcherTest, MAYBE_BasicThreaded) { |
- test::Stopwatch stopwatch; |
- int32_t buffer[1]; |
- const uint32_t kBufferSize = static_cast<uint32_t>(sizeof(buffer)); |
- uint32_t buffer_size; |
- base::TimeDelta elapsed; |
- bool did_wait; |
- MojoResult result; |
- uint32_t context; |
- HandleSignalsState hss; |
- |
- // Run this test both with |d0| as port 0, |d1| as port 1 and vice versa. |
- for (unsigned i = 0; i < 2; i++) { |
- scoped_refptr<MessagePipeDispatcher> d0(new MessagePipeDispatcher( |
- MessagePipeDispatcher::kDefaultCreateOptions)); |
- scoped_refptr<MessagePipeDispatcher> d1(new MessagePipeDispatcher( |
- MessagePipeDispatcher::kDefaultCreateOptions)); |
- { |
- scoped_refptr<MessagePipe> mp(MessagePipe::CreateLocalLocal()); |
- d0->Init(mp, i); // 0, 1. |
- d1->Init(mp, i ^ 1); // 1, 0. |
- } |
- |
- // Wait for readable on |d1|, which will become readable after some time. |
- { |
- test::WaiterThread thread(d1, |
- MOJO_HANDLE_SIGNAL_READABLE, |
- MOJO_DEADLINE_INDEFINITE, |
- 1, |
- &did_wait, |
- &result, |
- &context, |
- &hss); |
- stopwatch.Start(); |
- thread.Start(); |
- base::PlatformThread::Sleep(2 * test::EpsilonTimeout()); |
- // Wake it up by writing to |d0|. |
- buffer[0] = 123456789; |
- EXPECT_EQ(MOJO_RESULT_OK, |
- d0->WriteMessage(UserPointer<const void>(buffer), |
- kBufferSize, |
- nullptr, |
- MOJO_WRITE_MESSAGE_FLAG_NONE)); |
- } // Joins the thread. |
- elapsed = stopwatch.Elapsed(); |
- EXPECT_GT(elapsed, (2 - 1) * test::EpsilonTimeout()); |
- EXPECT_LT(elapsed, (2 + 1) * test::EpsilonTimeout()); |
- EXPECT_TRUE(did_wait); |
- EXPECT_EQ(MOJO_RESULT_OK, result); |
- EXPECT_EQ(1u, context); |
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, |
- hss.satisfied_signals); |
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, |
- hss.satisfiable_signals); |
- |
- // Now |d1| is already readable. Try waiting for it again. |
- { |
- test::WaiterThread thread(d1, |
- MOJO_HANDLE_SIGNAL_READABLE, |
- MOJO_DEADLINE_INDEFINITE, |
- 2, |
- &did_wait, |
- &result, |
- &context, |
- &hss); |
- stopwatch.Start(); |
- thread.Start(); |
- } // Joins the thread. |
- EXPECT_LT(stopwatch.Elapsed(), test::EpsilonTimeout()); |
- EXPECT_FALSE(did_wait); |
- EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, result); |
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, |
- hss.satisfied_signals); |
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, |
- hss.satisfiable_signals); |
- |
- // Consume what we wrote to |d0|. |
- buffer[0] = 0; |
- buffer_size = kBufferSize; |
- EXPECT_EQ(MOJO_RESULT_OK, |
- d1->ReadMessage(UserPointer<void>(buffer), |
- MakeUserPointer(&buffer_size), |
- 0, |
- nullptr, |
- MOJO_READ_MESSAGE_FLAG_NONE)); |
- EXPECT_EQ(kBufferSize, buffer_size); |
- EXPECT_EQ(123456789, buffer[0]); |
- |
- // Wait for readable on |d1| and close |d0| after some time, which should |
- // cancel that wait. |
- { |
- test::WaiterThread thread(d1, |
- MOJO_HANDLE_SIGNAL_READABLE, |
- MOJO_DEADLINE_INDEFINITE, |
- 3, |
- &did_wait, |
- &result, |
- &context, |
- &hss); |
- stopwatch.Start(); |
- thread.Start(); |
- base::PlatformThread::Sleep(2 * test::EpsilonTimeout()); |
- EXPECT_EQ(MOJO_RESULT_OK, d0->Close()); |
- } // Joins the thread. |
- elapsed = stopwatch.Elapsed(); |
- EXPECT_GT(elapsed, (2 - 1) * test::EpsilonTimeout()); |
- EXPECT_LT(elapsed, (2 + 1) * test::EpsilonTimeout()); |
- EXPECT_TRUE(did_wait); |
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result); |
- EXPECT_EQ(3u, context); |
- EXPECT_EQ(0u, hss.satisfied_signals); |
- EXPECT_EQ(0u, hss.satisfiable_signals); |
- |
- EXPECT_EQ(MOJO_RESULT_OK, d1->Close()); |
- } |
- |
- for (unsigned i = 0; i < 2; i++) { |
- scoped_refptr<MessagePipeDispatcher> d0(new MessagePipeDispatcher( |
- MessagePipeDispatcher::kDefaultCreateOptions)); |
- scoped_refptr<MessagePipeDispatcher> d1(new MessagePipeDispatcher( |
- MessagePipeDispatcher::kDefaultCreateOptions)); |
- { |
- scoped_refptr<MessagePipe> mp(MessagePipe::CreateLocalLocal()); |
- d0->Init(mp, i); // 0, 1. |
- d1->Init(mp, i ^ 1); // 1, 0. |
- } |
- |
- // Wait for readable on |d1| and close |d1| after some time, which should |
- // cancel that wait. |
- { |
- test::WaiterThread thread(d1, |
- MOJO_HANDLE_SIGNAL_READABLE, |
- MOJO_DEADLINE_INDEFINITE, |
- 4, |
- &did_wait, |
- &result, |
- &context, |
- &hss); |
- stopwatch.Start(); |
- thread.Start(); |
- base::PlatformThread::Sleep(2 * test::EpsilonTimeout()); |
- EXPECT_EQ(MOJO_RESULT_OK, d1->Close()); |
- } // Joins the thread. |
- elapsed = stopwatch.Elapsed(); |
- EXPECT_GT(elapsed, (2 - 1) * test::EpsilonTimeout()); |
- EXPECT_LT(elapsed, (2 + 1) * test::EpsilonTimeout()); |
- EXPECT_TRUE(did_wait); |
- EXPECT_EQ(MOJO_RESULT_CANCELLED, result); |
- EXPECT_EQ(4u, context); |
- EXPECT_EQ(0u, hss.satisfied_signals); |
- EXPECT_EQ(0u, hss.satisfiable_signals); |
- |
- EXPECT_EQ(MOJO_RESULT_OK, d0->Close()); |
- } |
-} |
- |
-// Stress test ----------------------------------------------------------------- |
- |
-const size_t kMaxMessageSize = 2000; |
- |
-class WriterThread : public base::SimpleThread { |
- public: |
- // |*messages_written| and |*bytes_written| belong to the thread while it's |
- // alive. |
- WriterThread(scoped_refptr<Dispatcher> write_dispatcher, |
- size_t* messages_written, |
- size_t* bytes_written) |
- : base::SimpleThread("writer_thread"), |
- write_dispatcher_(write_dispatcher), |
- messages_written_(messages_written), |
- bytes_written_(bytes_written) { |
- *messages_written_ = 0; |
- *bytes_written_ = 0; |
- } |
- |
- virtual ~WriterThread() { Join(); } |
- |
- private: |
- virtual void Run() override { |
- // Make some data to write. |
- unsigned char buffer[kMaxMessageSize]; |
- for (size_t i = 0; i < kMaxMessageSize; i++) |
- buffer[i] = static_cast<unsigned char>(i); |
- |
- // Number of messages to write. |
- *messages_written_ = static_cast<size_t>(base::RandInt(1000, 6000)); |
- |
- // Write messages. |
- for (size_t i = 0; i < *messages_written_; i++) { |
- uint32_t bytes_to_write = static_cast<uint32_t>( |
- base::RandInt(1, static_cast<int>(kMaxMessageSize))); |
- EXPECT_EQ(MOJO_RESULT_OK, |
- write_dispatcher_->WriteMessage(UserPointer<const void>(buffer), |
- bytes_to_write, |
- nullptr, |
- MOJO_WRITE_MESSAGE_FLAG_NONE)); |
- *bytes_written_ += bytes_to_write; |
- } |
- |
- // Write one last "quit" message. |
- EXPECT_EQ(MOJO_RESULT_OK, |
- write_dispatcher_->WriteMessage(UserPointer<const void>("quit"), |
- 4, |
- nullptr, |
- MOJO_WRITE_MESSAGE_FLAG_NONE)); |
- } |
- |
- const scoped_refptr<Dispatcher> write_dispatcher_; |
- size_t* const messages_written_; |
- size_t* const bytes_written_; |
- |
- DISALLOW_COPY_AND_ASSIGN(WriterThread); |
-}; |
- |
-class ReaderThread : public base::SimpleThread { |
- public: |
- // |*messages_read| and |*bytes_read| belong to the thread while it's alive. |
- ReaderThread(scoped_refptr<Dispatcher> read_dispatcher, |
- size_t* messages_read, |
- size_t* bytes_read) |
- : base::SimpleThread("reader_thread"), |
- read_dispatcher_(read_dispatcher), |
- messages_read_(messages_read), |
- bytes_read_(bytes_read) { |
- *messages_read_ = 0; |
- *bytes_read_ = 0; |
- } |
- |
- virtual ~ReaderThread() { Join(); } |
- |
- private: |
- virtual void Run() override { |
- unsigned char buffer[kMaxMessageSize]; |
- Waiter w; |
- HandleSignalsState hss; |
- MojoResult result; |
- |
- // Read messages. |
- for (;;) { |
- // Wait for it to be readable. |
- w.Init(); |
- hss = HandleSignalsState(); |
- result = |
- read_dispatcher_->AddWaiter(&w, MOJO_HANDLE_SIGNAL_READABLE, 0, &hss); |
- EXPECT_TRUE(result == MOJO_RESULT_OK || |
- result == MOJO_RESULT_ALREADY_EXISTS) |
- << "result: " << result; |
- if (result == MOJO_RESULT_OK) { |
- // Actually need to wait. |
- EXPECT_EQ(MOJO_RESULT_OK, w.Wait(MOJO_DEADLINE_INDEFINITE, nullptr)); |
- read_dispatcher_->RemoveWaiter(&w, &hss); |
- } |
- // We may not actually be readable, since we're racing with other threads. |
- EXPECT_TRUE((hss.satisfiable_signals & MOJO_HANDLE_SIGNAL_READABLE)); |
- |
- // Now, try to do the read. |
- // Clear the buffer so that we can check the result. |
- memset(buffer, 0, sizeof(buffer)); |
- uint32_t buffer_size = static_cast<uint32_t>(sizeof(buffer)); |
- result = read_dispatcher_->ReadMessage(UserPointer<void>(buffer), |
- MakeUserPointer(&buffer_size), |
- 0, |
- nullptr, |
- MOJO_READ_MESSAGE_FLAG_NONE); |
- EXPECT_TRUE(result == MOJO_RESULT_OK || result == MOJO_RESULT_SHOULD_WAIT) |
- << "result: " << result; |
- // We're racing with others to read, so maybe we failed. |
- if (result == MOJO_RESULT_SHOULD_WAIT) |
- continue; // In which case, try again. |
- // Check for quit. |
- if (buffer_size == 4 && memcmp("quit", buffer, 4) == 0) |
- return; |
- EXPECT_GE(buffer_size, 1u); |
- EXPECT_LE(buffer_size, kMaxMessageSize); |
- EXPECT_TRUE(IsValidMessage(buffer, buffer_size)); |
- |
- (*messages_read_)++; |
- *bytes_read_ += buffer_size; |
- } |
- } |
- |
- static bool IsValidMessage(const unsigned char* buffer, |
- uint32_t message_size) { |
- size_t i; |
- for (i = 0; i < message_size; i++) { |
- if (buffer[i] != static_cast<unsigned char>(i)) |
- return false; |
- } |
- // Check that the remaining bytes weren't stomped on. |
- for (; i < kMaxMessageSize; i++) { |
- if (buffer[i] != 0) |
- return false; |
- } |
- return true; |
- } |
- |
- const scoped_refptr<Dispatcher> read_dispatcher_; |
- size_t* const messages_read_; |
- size_t* const bytes_read_; |
- |
- DISALLOW_COPY_AND_ASSIGN(ReaderThread); |
-}; |
- |
-TEST(MessagePipeDispatcherTest, Stress) { |
- static const size_t kNumWriters = 30; |
- static const size_t kNumReaders = kNumWriters; |
- |
- scoped_refptr<MessagePipeDispatcher> d_write( |
- new MessagePipeDispatcher(MessagePipeDispatcher::kDefaultCreateOptions)); |
- scoped_refptr<MessagePipeDispatcher> d_read( |
- new MessagePipeDispatcher(MessagePipeDispatcher::kDefaultCreateOptions)); |
- { |
- scoped_refptr<MessagePipe> mp(MessagePipe::CreateLocalLocal()); |
- d_write->Init(mp, 0); |
- d_read->Init(mp, 1); |
- } |
- |
- size_t messages_written[kNumWriters]; |
- size_t bytes_written[kNumWriters]; |
- size_t messages_read[kNumReaders]; |
- size_t bytes_read[kNumReaders]; |
- { |
- // Make writers. |
- ScopedVector<WriterThread> writers; |
- for (size_t i = 0; i < kNumWriters; i++) { |
- writers.push_back( |
- new WriterThread(d_write, &messages_written[i], &bytes_written[i])); |
- } |
- |
- // Make readers. |
- ScopedVector<ReaderThread> readers; |
- for (size_t i = 0; i < kNumReaders; i++) { |
- readers.push_back( |
- new ReaderThread(d_read, &messages_read[i], &bytes_read[i])); |
- } |
- |
- // Start writers. |
- for (size_t i = 0; i < kNumWriters; i++) |
- writers[i]->Start(); |
- |
- // Start readers. |
- for (size_t i = 0; i < kNumReaders; i++) |
- readers[i]->Start(); |
- |
- // TODO(vtl): Maybe I should have an event that triggers all the threads to |
- // start doing stuff for real (so that the first ones created/started aren't |
- // advantaged). |
- } // Joins all the threads. |
- |
- size_t total_messages_written = 0; |
- size_t total_bytes_written = 0; |
- for (size_t i = 0; i < kNumWriters; i++) { |
- total_messages_written += messages_written[i]; |
- total_bytes_written += bytes_written[i]; |
- } |
- size_t total_messages_read = 0; |
- size_t total_bytes_read = 0; |
- for (size_t i = 0; i < kNumReaders; i++) { |
- total_messages_read += messages_read[i]; |
- total_bytes_read += bytes_read[i]; |
- // We'd have to be really unlucky to have read no messages on a thread. |
- EXPECT_GT(messages_read[i], 0u) << "reader: " << i; |
- EXPECT_GE(bytes_read[i], messages_read[i]) << "reader: " << i; |
- } |
- EXPECT_EQ(total_messages_written, total_messages_read); |
- EXPECT_EQ(total_bytes_written, total_bytes_read); |
- |
- EXPECT_EQ(MOJO_RESULT_OK, d_write->Close()); |
- EXPECT_EQ(MOJO_RESULT_OK, d_read->Close()); |
-} |
- |
-} // namespace |
-} // namespace system |
-} // namespace mojo |