diff options
Diffstat (limited to 'chromium/mojo/system/waiter_list_unittest.cc')
-rw-r--r-- | chromium/mojo/system/waiter_list_unittest.cc | 297 |
1 files changed, 297 insertions, 0 deletions
diff --git a/chromium/mojo/system/waiter_list_unittest.cc b/chromium/mojo/system/waiter_list_unittest.cc new file mode 100644 index 00000000000..1abe5e7eb4b --- /dev/null +++ b/chromium/mojo/system/waiter_list_unittest.cc @@ -0,0 +1,297 @@ +// 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/system/waiter_list.h" + +#include "base/threading/platform_thread.h" // For |Sleep()|. +#include "base/time/time.h" +#include "mojo/system/handle_signals_state.h" +#include "mojo/system/test_utils.h" +#include "mojo/system/waiter.h" +#include "mojo/system/waiter_test_utils.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace mojo { +namespace system { +namespace { + +TEST(WaiterListTest, BasicCancel) { + MojoResult result; + uint32_t context; + + // Cancel immediately after thread start. + { + WaiterList waiter_list; + test::SimpleWaiterThread thread(&result, &context); + waiter_list.AddWaiter(thread.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 1); + thread.Start(); + waiter_list.CancelAllWaiters(); + waiter_list.RemoveWaiter(thread.waiter()); // Double-remove okay. + } // Join |thread|. + EXPECT_EQ(MOJO_RESULT_CANCELLED, result); + EXPECT_EQ(1u, context); + + // Cancel before after thread start. + { + WaiterList waiter_list; + test::SimpleWaiterThread thread(&result, &context); + waiter_list.AddWaiter(thread.waiter(), MOJO_HANDLE_SIGNAL_WRITABLE, 2); + waiter_list.CancelAllWaiters(); + thread.Start(); + } // Join |thread|. + EXPECT_EQ(MOJO_RESULT_CANCELLED, result); + EXPECT_EQ(2u, context); + + // Cancel some time after thread start. + { + WaiterList waiter_list; + test::SimpleWaiterThread thread(&result, &context); + waiter_list.AddWaiter(thread.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 3); + thread.Start(); + base::PlatformThread::Sleep(2 * test::EpsilonTimeout()); + waiter_list.CancelAllWaiters(); + } // Join |thread|. + EXPECT_EQ(MOJO_RESULT_CANCELLED, result); + EXPECT_EQ(3u, context); +} + +TEST(WaiterListTest, BasicAwakeSatisfied) { + MojoResult result; + uint32_t context; + + // Awake immediately after thread start. + { + WaiterList waiter_list; + test::SimpleWaiterThread thread(&result, &context); + waiter_list.AddWaiter(thread.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 1); + thread.Start(); + waiter_list.AwakeWaitersForStateChange( + HandleSignalsState(MOJO_HANDLE_SIGNAL_READABLE, + MOJO_HANDLE_SIGNAL_READABLE | + MOJO_HANDLE_SIGNAL_WRITABLE)); + waiter_list.RemoveWaiter(thread.waiter()); + } // Join |thread|. + EXPECT_EQ(MOJO_RESULT_OK, result); + EXPECT_EQ(1u, context); + + // Awake before after thread start. + { + WaiterList waiter_list; + test::SimpleWaiterThread thread(&result, &context); + waiter_list.AddWaiter(thread.waiter(), MOJO_HANDLE_SIGNAL_WRITABLE, 2); + waiter_list.AwakeWaitersForStateChange( + HandleSignalsState(MOJO_HANDLE_SIGNAL_WRITABLE, + MOJO_HANDLE_SIGNAL_READABLE | + MOJO_HANDLE_SIGNAL_WRITABLE)); + waiter_list.RemoveWaiter(thread.waiter()); + waiter_list.RemoveWaiter(thread.waiter()); // Double-remove okay. + thread.Start(); + } // Join |thread|. + EXPECT_EQ(MOJO_RESULT_OK, result); + EXPECT_EQ(2u, context); + + // Awake some time after thread start. + { + WaiterList waiter_list; + test::SimpleWaiterThread thread(&result, &context); + waiter_list.AddWaiter(thread.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 3); + thread.Start(); + base::PlatformThread::Sleep(2 * test::EpsilonTimeout()); + waiter_list.AwakeWaitersForStateChange( + HandleSignalsState(MOJO_HANDLE_SIGNAL_READABLE, + MOJO_HANDLE_SIGNAL_READABLE | + MOJO_HANDLE_SIGNAL_WRITABLE)); + waiter_list.RemoveWaiter(thread.waiter()); + } // Join |thread|. + EXPECT_EQ(MOJO_RESULT_OK, result); + EXPECT_EQ(3u, context); +} + +TEST(WaiterListTest, BasicAwakeUnsatisfiable) { + MojoResult result; + uint32_t context; + + // Awake (for unsatisfiability) immediately after thread start. + { + WaiterList waiter_list; + test::SimpleWaiterThread thread(&result, &context); + waiter_list.AddWaiter(thread.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 1); + thread.Start(); + waiter_list.AwakeWaitersForStateChange( + HandleSignalsState(MOJO_HANDLE_SIGNAL_NONE, + MOJO_HANDLE_SIGNAL_WRITABLE)); + waiter_list.RemoveWaiter(thread.waiter()); + } // Join |thread|. + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result); + EXPECT_EQ(1u, context); + + // Awake (for unsatisfiability) before after thread start. + { + WaiterList waiter_list; + test::SimpleWaiterThread thread(&result, &context); + waiter_list.AddWaiter(thread.waiter(), MOJO_HANDLE_SIGNAL_WRITABLE, 2); + waiter_list.AwakeWaitersForStateChange( + HandleSignalsState(MOJO_HANDLE_SIGNAL_READABLE, + MOJO_HANDLE_SIGNAL_READABLE)); + waiter_list.RemoveWaiter(thread.waiter()); + thread.Start(); + } // Join |thread|. + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result); + EXPECT_EQ(2u, context); + + // Awake (for unsatisfiability) some time after thread start. + { + WaiterList waiter_list; + test::SimpleWaiterThread thread(&result, &context); + waiter_list.AddWaiter(thread.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 3); + thread.Start(); + base::PlatformThread::Sleep(2 * test::EpsilonTimeout()); + waiter_list.AwakeWaitersForStateChange( + HandleSignalsState(MOJO_HANDLE_SIGNAL_NONE, + MOJO_HANDLE_SIGNAL_WRITABLE)); + waiter_list.RemoveWaiter(thread.waiter()); + waiter_list.RemoveWaiter(thread.waiter()); // Double-remove okay. + } // Join |thread|. + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result); + EXPECT_EQ(3u, context); +} + +TEST(WaiterListTest, MultipleWaiters) { + MojoResult result1; + MojoResult result2; + MojoResult result3; + MojoResult result4; + uint32_t context1; + uint32_t context2; + uint32_t context3; + uint32_t context4; + + // Cancel two waiters. + { + WaiterList waiter_list; + test::SimpleWaiterThread thread1(&result1, &context1); + waiter_list.AddWaiter(thread1.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 1); + thread1.Start(); + test::SimpleWaiterThread thread2(&result2, &context2); + waiter_list.AddWaiter(thread2.waiter(), MOJO_HANDLE_SIGNAL_WRITABLE, 2); + thread2.Start(); + base::PlatformThread::Sleep(2 * test::EpsilonTimeout()); + waiter_list.CancelAllWaiters(); + } // Join threads. + EXPECT_EQ(MOJO_RESULT_CANCELLED, result1); + EXPECT_EQ(1u, context1); + EXPECT_EQ(MOJO_RESULT_CANCELLED, result2); + EXPECT_EQ(2u, context2); + + // Awake one waiter, cancel other. + { + WaiterList waiter_list; + test::SimpleWaiterThread thread1(&result1, &context1); + waiter_list.AddWaiter(thread1.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 3); + thread1.Start(); + test::SimpleWaiterThread thread2(&result2, &context2); + waiter_list.AddWaiter(thread2.waiter(), MOJO_HANDLE_SIGNAL_WRITABLE, 4); + thread2.Start(); + base::PlatformThread::Sleep(2 * test::EpsilonTimeout()); + waiter_list.AwakeWaitersForStateChange( + HandleSignalsState(MOJO_HANDLE_SIGNAL_READABLE, + MOJO_HANDLE_SIGNAL_READABLE | + MOJO_HANDLE_SIGNAL_WRITABLE)); + waiter_list.RemoveWaiter(thread1.waiter()); + waiter_list.CancelAllWaiters(); + } // Join threads. + EXPECT_EQ(MOJO_RESULT_OK, result1); + EXPECT_EQ(3u, context1); + EXPECT_EQ(MOJO_RESULT_CANCELLED, result2); + EXPECT_EQ(4u, context2); + + // Cancel one waiter, awake other for unsatisfiability. + { + WaiterList waiter_list; + test::SimpleWaiterThread thread1(&result1, &context1); + waiter_list.AddWaiter(thread1.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 5); + thread1.Start(); + test::SimpleWaiterThread thread2(&result2, &context2); + waiter_list.AddWaiter(thread2.waiter(), MOJO_HANDLE_SIGNAL_WRITABLE, 6); + thread2.Start(); + base::PlatformThread::Sleep(2 * test::EpsilonTimeout()); + waiter_list.AwakeWaitersForStateChange( + HandleSignalsState(MOJO_HANDLE_SIGNAL_NONE, + MOJO_HANDLE_SIGNAL_READABLE)); + waiter_list.RemoveWaiter(thread2.waiter()); + waiter_list.CancelAllWaiters(); + } // Join threads. + EXPECT_EQ(MOJO_RESULT_CANCELLED, result1); + EXPECT_EQ(5u, context1); + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result2); + EXPECT_EQ(6u, context2); + + // Cancel one waiter, awake other for unsatisfiability. + { + WaiterList waiter_list; + test::SimpleWaiterThread thread1(&result1, &context1); + waiter_list.AddWaiter(thread1.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 7); + thread1.Start(); + + base::PlatformThread::Sleep(1 * test::EpsilonTimeout()); + + // Should do nothing. + waiter_list.AwakeWaitersForStateChange( + HandleSignalsState(MOJO_HANDLE_SIGNAL_NONE, + MOJO_HANDLE_SIGNAL_READABLE | + MOJO_HANDLE_SIGNAL_WRITABLE)); + + test::SimpleWaiterThread thread2(&result2, &context2); + waiter_list.AddWaiter(thread2.waiter(), MOJO_HANDLE_SIGNAL_WRITABLE, 8); + thread2.Start(); + + base::PlatformThread::Sleep(1 * test::EpsilonTimeout()); + + // Awake #1. + waiter_list.AwakeWaitersForStateChange( + HandleSignalsState(MOJO_HANDLE_SIGNAL_READABLE, + MOJO_HANDLE_SIGNAL_READABLE | + MOJO_HANDLE_SIGNAL_WRITABLE)); + waiter_list.RemoveWaiter(thread1.waiter()); + + base::PlatformThread::Sleep(1 * test::EpsilonTimeout()); + + test::SimpleWaiterThread thread3(&result3, &context3); + waiter_list.AddWaiter(thread3.waiter(), MOJO_HANDLE_SIGNAL_WRITABLE, 9); + thread3.Start(); + + test::SimpleWaiterThread thread4(&result4, &context4); + waiter_list.AddWaiter(thread4.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 10); + thread4.Start(); + + base::PlatformThread::Sleep(1 * test::EpsilonTimeout()); + + // Awake #2 and #3 for unsatisfiability. + waiter_list.AwakeWaitersForStateChange( + HandleSignalsState(MOJO_HANDLE_SIGNAL_NONE, + MOJO_HANDLE_SIGNAL_READABLE)); + waiter_list.RemoveWaiter(thread2.waiter()); + waiter_list.RemoveWaiter(thread3.waiter()); + + // Cancel #4. + waiter_list.CancelAllWaiters(); + } // Join threads. + EXPECT_EQ(MOJO_RESULT_OK, result1); + EXPECT_EQ(7u, context1); + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result2); + EXPECT_EQ(8u, context2); + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result3); + EXPECT_EQ(9u, context3); + EXPECT_EQ(MOJO_RESULT_CANCELLED, result4); + EXPECT_EQ(10u, context4); +} + +} // namespace +} // namespace system +} // namespace mojo |