Index: mojo/public/cpp/system/tests/wait_set_unittest.cc |
diff --git a/mojo/public/cpp/system/tests/wait_set_unittest.cc b/mojo/public/cpp/system/tests/wait_set_unittest.cc |
index 2a6d9b88256b32e9857971e6d2037454d3c6077f..d60cb45924df33c88dff54a70bd8708e01024dbd 100644 |
--- a/mojo/public/cpp/system/tests/wait_set_unittest.cc |
+++ b/mojo/public/cpp/system/tests/wait_set_unittest.cc |
@@ -4,11 +4,17 @@ |
#include "mojo/public/cpp/system/wait_set.h" |
+#include <set> |
+#include <vector> |
+ |
#include "base/bind.h" |
#include "base/callback.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 "mojo/public/cpp/system/message_pipe.h" |
+#include "mojo/public/cpp/system/wait.h" |
#include "testing/gtest/include/gtest/gtest.h" |
namespace mojo { |
@@ -68,7 +74,7 @@ TEST_F(WaitSetTest, Satisfied) { |
Handle ready_handles[2]; |
MojoResult ready_results[2] = {MOJO_RESULT_UNKNOWN, MOJO_RESULT_UNKNOWN}; |
HandleSignalsState hss[2]; |
- wait_set.Wait(&num_ready_handles, ready_handles, ready_results, hss); |
+ wait_set.Wait(nullptr, &num_ready_handles, ready_handles, ready_results, hss); |
EXPECT_EQ(1u, num_ready_handles); |
EXPECT_EQ(p.handle1.get(), ready_handles[0]); |
@@ -85,7 +91,7 @@ TEST_F(WaitSetTest, Satisfied) { |
num_ready_handles = 2; |
ready_results[0] = MOJO_RESULT_UNKNOWN; |
ready_results[1] = MOJO_RESULT_UNKNOWN; |
- wait_set.Wait(&num_ready_handles, ready_handles, ready_results, hss); |
+ wait_set.Wait(nullptr, &num_ready_handles, ready_handles, ready_results, hss); |
EXPECT_EQ(1u, num_ready_handles); |
EXPECT_EQ(p.handle0.get(), ready_handles[0]); |
@@ -98,7 +104,7 @@ TEST_F(WaitSetTest, Satisfied) { |
num_ready_handles = 2; |
ready_results[0] = MOJO_RESULT_UNKNOWN; |
ready_results[1] = MOJO_RESULT_UNKNOWN; |
- wait_set.Wait(&num_ready_handles, ready_handles, ready_results, hss); |
+ wait_set.Wait(nullptr, &num_ready_handles, ready_handles, ready_results, hss); |
EXPECT_EQ(2u, num_ready_handles); |
EXPECT_TRUE((ready_handles[0] == p.handle0.get() && |
ready_handles[1] == p.handle1.get()) || |
@@ -112,7 +118,7 @@ TEST_F(WaitSetTest, Satisfied) { |
// Wait on both again, but with only enough output space for one result. |
num_ready_handles = 1; |
ready_results[0] = MOJO_RESULT_UNKNOWN; |
- wait_set.Wait(&num_ready_handles, ready_handles, ready_results, hss); |
+ wait_set.Wait(nullptr, &num_ready_handles, ready_handles, ready_results, hss); |
EXPECT_EQ(1u, num_ready_handles); |
EXPECT_TRUE(ready_handles[0] == p.handle0.get() || |
ready_handles[0] == p.handle1.get()); |
@@ -123,7 +129,7 @@ TEST_F(WaitSetTest, Satisfied) { |
num_ready_handles = 1; |
ready_results[0] = MOJO_RESULT_UNKNOWN; |
- wait_set.Wait(&num_ready_handles, ready_handles, ready_results, hss); |
+ wait_set.Wait(nullptr, &num_ready_handles, ready_handles, ready_results, hss); |
EXPECT_EQ(1u, num_ready_handles); |
EXPECT_TRUE(ready_handles[0] == p.handle0.get() || |
ready_handles[0] == p.handle1.get()); |
@@ -133,7 +139,7 @@ TEST_F(WaitSetTest, Satisfied) { |
// The wait set should be empty now. Nothing to wait on. |
num_ready_handles = 2; |
- wait_set.Wait(&num_ready_handles, ready_handles, ready_results); |
+ wait_set.Wait(nullptr, &num_ready_handles, ready_handles, ready_results); |
EXPECT_EQ(0u, num_ready_handles); |
} |
@@ -150,7 +156,7 @@ TEST_F(WaitSetTest, Unsatisfiable) { |
MojoResult ready_results[2] = {MOJO_RESULT_UNKNOWN, MOJO_RESULT_UNKNOWN}; |
p.handle1.reset(); |
- wait_set.Wait(&num_ready_handles, ready_handles, ready_results); |
+ wait_set.Wait(nullptr, &num_ready_handles, ready_handles, ready_results); |
EXPECT_EQ(1u, num_ready_handles); |
EXPECT_EQ(p.handle0.get(), ready_handles[0]); |
EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, ready_results[0]); |
@@ -175,7 +181,7 @@ TEST_F(WaitSetTest, CloseWhileWaiting) { |
size_t num_ready_handles = 2; |
Handle ready_handles[2]; |
MojoResult ready_results[2] = {MOJO_RESULT_UNKNOWN, MOJO_RESULT_UNKNOWN}; |
- wait_set.Wait(&num_ready_handles, ready_handles, ready_results); |
+ wait_set.Wait(nullptr, &num_ready_handles, ready_handles, ready_results); |
EXPECT_EQ(1u, num_ready_handles); |
EXPECT_EQ(handle0_value, ready_handles[0]); |
EXPECT_EQ(MOJO_RESULT_CANCELLED, ready_results[0]); |
@@ -203,20 +209,20 @@ TEST_F(WaitSetTest, CloseBeforeWaiting) { |
size_t num_ready_handles = 1; |
Handle ready_handle; |
MojoResult ready_result = MOJO_RESULT_UNKNOWN; |
- wait_set.Wait(&num_ready_handles, &ready_handle, &ready_result); |
+ wait_set.Wait(nullptr, &num_ready_handles, &ready_handle, &ready_result); |
EXPECT_EQ(1u, num_ready_handles); |
EXPECT_TRUE(ready_handle == handle0_value || ready_handle == handle1_value); |
EXPECT_EQ(MOJO_RESULT_CANCELLED, ready_result); |
EXPECT_EQ(MOJO_RESULT_NOT_FOUND, wait_set.RemoveHandle(handle0_value)); |
- wait_set.Wait(&num_ready_handles, &ready_handle, &ready_result); |
+ wait_set.Wait(nullptr, &num_ready_handles, &ready_handle, &ready_result); |
EXPECT_EQ(1u, num_ready_handles); |
EXPECT_TRUE(ready_handle == handle0_value || ready_handle == handle1_value); |
EXPECT_EQ(MOJO_RESULT_CANCELLED, ready_result); |
EXPECT_EQ(MOJO_RESULT_NOT_FOUND, wait_set.RemoveHandle(handle0_value)); |
// Nothing more to wait on. |
- wait_set.Wait(&num_ready_handles, &ready_handle, &ready_result); |
+ wait_set.Wait(nullptr, &num_ready_handles, &ready_handle, &ready_result); |
EXPECT_EQ(0u, num_ready_handles); |
} |
@@ -233,7 +239,7 @@ TEST_F(WaitSetTest, SatisfiedThenUnsatisfied) { |
size_t num_ready_handles = 2; |
Handle ready_handles[2]; |
MojoResult ready_results[2] = {MOJO_RESULT_UNKNOWN, MOJO_RESULT_UNKNOWN}; |
- wait_set.Wait(&num_ready_handles, ready_handles, ready_results); |
+ wait_set.Wait(nullptr, &num_ready_handles, ready_handles, ready_results); |
EXPECT_EQ(1u, num_ready_handles); |
EXPECT_EQ(p.handle1.get(), ready_handles[0]); |
EXPECT_EQ(MOJO_RESULT_OK, ready_results[0]); |
@@ -250,11 +256,121 @@ TEST_F(WaitSetTest, SatisfiedThenUnsatisfied) { |
write_after_delay.Start(); |
num_ready_handles = 2; |
- wait_set.Wait(&num_ready_handles, ready_handles, ready_results); |
+ wait_set.Wait(nullptr, &num_ready_handles, ready_handles, ready_results); |
EXPECT_EQ(1u, num_ready_handles); |
EXPECT_EQ(p.handle0.get(), ready_handles[0]); |
EXPECT_EQ(MOJO_RESULT_OK, ready_results[0]); |
} |
+TEST_F(WaitSetTest, EventOnly) { |
+ base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, |
+ base::WaitableEvent::InitialState::SIGNALED); |
+ WaitSet wait_set; |
+ wait_set.AddEvent(&event); |
+ |
+ base::WaitableEvent* ready_event = nullptr; |
+ size_t num_ready_handles = 1; |
+ Handle ready_handle; |
+ MojoResult ready_result = MOJO_RESULT_UNKNOWN; |
+ wait_set.Wait(&ready_event, &num_ready_handles, &ready_handle, &ready_result); |
+ EXPECT_EQ(0u, num_ready_handles); |
+ EXPECT_EQ(&event, ready_event); |
+} |
+ |
+TEST_F(WaitSetTest, EventAndHandle) { |
+ const char kTestMessage[] = "hello hello"; |
+ |
+ MessagePipe p; |
+ WriteMessage(p.handle0, kTestMessage); |
+ |
+ base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, |
+ base::WaitableEvent::InitialState::NOT_SIGNALED); |
+ |
+ WaitSet wait_set; |
+ wait_set.AddHandle(p.handle1.get(), MOJO_HANDLE_SIGNAL_READABLE); |
+ wait_set.AddEvent(&event); |
+ |
+ base::WaitableEvent* ready_event = nullptr; |
+ size_t num_ready_handles = 1; |
+ Handle ready_handle; |
+ MojoResult ready_result = MOJO_RESULT_UNKNOWN; |
+ wait_set.Wait(&ready_event, &num_ready_handles, &ready_handle, &ready_result); |
+ EXPECT_EQ(1u, num_ready_handles); |
+ EXPECT_EQ(nullptr, ready_event); |
+ EXPECT_EQ(p.handle1.get(), ready_handle); |
+ EXPECT_EQ(MOJO_RESULT_OK, ready_result); |
+ |
+ EXPECT_EQ(kTestMessage, ReadMessage(p.handle1)); |
+ |
+ ThreadedRunner signal_after_delay(base::Bind( |
+ [](base::WaitableEvent* event) { |
+ // Wait a little while, then close the handle. |
+ base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(200)); |
+ event->Signal(); |
+ }, |
+ &event)); |
+ signal_after_delay.Start(); |
+ |
+ wait_set.Wait(&ready_event, &num_ready_handles, &ready_handle, &ready_result); |
+ EXPECT_EQ(0u, num_ready_handles); |
+ EXPECT_EQ(&event, ready_event); |
+} |
+ |
+TEST_F(WaitSetTest, NoStarvation) { |
+ const char kTestMessage[] = "wait for it"; |
+ const size_t kNumTestPipes = 50; |
+ const size_t kNumTestEvents = 10; |
+ |
+ // Create a bunch of handles and events which are always ready and add them |
+ // to a shared WaitSet. |
+ |
+ WaitSet wait_set; |
+ |
+ MessagePipe pipes[kNumTestPipes]; |
+ for (size_t i = 0; i < kNumTestPipes; ++i) { |
+ WriteMessage(pipes[i].handle0, kTestMessage); |
+ Wait(pipes[i].handle1.get(), MOJO_HANDLE_SIGNAL_READABLE); |
+ |
+ WriteMessage(pipes[i].handle1, kTestMessage); |
+ Wait(pipes[i].handle0.get(), MOJO_HANDLE_SIGNAL_READABLE); |
+ |
+ wait_set.AddHandle(pipes[i].handle0.get(), MOJO_HANDLE_SIGNAL_READABLE); |
+ wait_set.AddHandle(pipes[i].handle1.get(), MOJO_HANDLE_SIGNAL_READABLE); |
+ } |
+ |
+ std::vector<std::unique_ptr<base::WaitableEvent>> events(kNumTestEvents); |
+ for (auto& event_ptr : events) { |
+ event_ptr = base::MakeUnique<base::WaitableEvent>( |
+ base::WaitableEvent::ResetPolicy::MANUAL, |
+ base::WaitableEvent::InitialState::NOT_SIGNALED); |
+ event_ptr->Signal(); |
+ wait_set.AddEvent(event_ptr.get()); |
+ } |
+ |
+ // Now verify that all handle and event signals are deteceted within a finite |
+ // number of consecutive Wait() calls. Do it a few times for good measure. |
+ for (size_t i = 0; i < 3; ++i) { |
+ std::set<base::WaitableEvent*> ready_events; |
+ std::set<Handle> ready_handles; |
+ while (ready_events.size() < kNumTestEvents || |
+ ready_handles.size() < kNumTestPipes * 2) { |
+ base::WaitableEvent* ready_event = nullptr; |
+ size_t num_ready_handles = 1; |
+ Handle ready_handle; |
+ MojoResult ready_result = MOJO_RESULT_UNKNOWN; |
+ wait_set.Wait(&ready_event, &num_ready_handles, &ready_handle, |
+ &ready_result); |
+ if (ready_event) |
+ ready_events.insert(ready_event); |
+ |
+ if (num_ready_handles) { |
+ EXPECT_EQ(1u, num_ready_handles); |
+ EXPECT_EQ(MOJO_RESULT_OK, ready_result); |
+ ready_handles.insert(ready_handle); |
+ } |
+ } |
+ } |
+} |
+ |
} // namespace |
} // namespace mojo |