From 0d2eaa0b21ef2e6b0766f6053b9f1905b6511f2c Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Thu, 22 Jun 2023 09:44:54 -0700 Subject: [PATCH] Add explicit tests for rw_spinlock --- test/CMakeLists.txt | 1 + test/Jamfile.v2 | 1 + test/cfoa/rw_spinlock_tests.cpp | 255 ++++++++++++++++++++++++++++++++ 3 files changed, 257 insertions(+) create mode 100644 test/cfoa/rw_spinlock_tests.cpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index f9dd0e45..81a4be2d 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -140,6 +140,7 @@ foa_tests(SOURCES exception/merge_exception_tests.cpp) # CFOA tests +cfoa_tests(SOURCES cfoa/rw_spinlock_tests.cpp) cfoa_tests(SOURCES cfoa/latch_tests.cpp) cfoa_tests(SOURCES cfoa/insert_tests.cpp) cfoa_tests(SOURCES cfoa/erase_tests.cpp) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 4e256e2a..6a568e7c 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -177,6 +177,7 @@ alias foa_tests : local CFOA_TESTS = latch_tests + rw_spinlock_tests insert_tests erase_tests try_emplace_tests diff --git a/test/cfoa/rw_spinlock_tests.cpp b/test/cfoa/rw_spinlock_tests.cpp new file mode 100644 index 00000000..eb2801e2 --- /dev/null +++ b/test/cfoa/rw_spinlock_tests.cpp @@ -0,0 +1,255 @@ +// Copyright 2023 Peter Dimov +// Copyright 2023 Christian Mazakas +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include "helpers.hpp" + +#include +#include + +#include +#include + +using boost::unordered::detail::foa::rw_spinlock; + +static int count = 0; + +UNORDERED_AUTO_TEST (rw_spinlock_test) { + rw_spinlock sp, sp2; + + sp.lock(); + sp2.lock(); + sp.unlock(); + sp2.unlock(); + + { + std::lock_guard lock(sp); + std::lock_guard lock2(sp2); + } +} + +UNORDERED_AUTO_TEST (rw_spinlock_test2) { + rw_spinlock sp, sp2; + + BOOST_TEST(sp.try_lock()); + BOOST_TEST(!sp.try_lock()); + BOOST_TEST(sp2.try_lock()); + BOOST_TEST(!sp.try_lock()); + BOOST_TEST(!sp2.try_lock()); + sp.unlock(); + sp2.unlock(); + + sp.lock(); + BOOST_TEST(!sp.try_lock()); + sp2.lock(); + BOOST_TEST(!sp.try_lock()); + BOOST_TEST(!sp2.try_lock()); + sp.unlock(); + sp2.unlock(); + + { + std::lock_guard lock(sp); + BOOST_TEST(!sp.try_lock()); + std::lock_guard lock2(sp2); + BOOST_TEST(!sp.try_lock()); + BOOST_TEST(!sp2.try_lock()); + } +} + +void f(rw_spinlock& sp, int n) +{ + for (int i = 0; i < n; ++i) { + std::lock_guard lock(sp); + ++count; + } +} + +UNORDERED_AUTO_TEST (rw_spinlock_test3) { + count = 0; + + rw_spinlock sp; + + int const N = 1000000; // iterations + int const M = 8; // threads + + std::thread th[M]; + + for (int i = 0; i < M; ++i) { + th[i] = std::thread([=, &sp] { f(sp, N); }); + } + + for (int i = 0; i < M; ++i) { + th[i].join(); + } + + BOOST_TEST_EQ(count, N * M); +} + +UNORDERED_AUTO_TEST (rw_spinlock_test4) { + rw_spinlock sp, sp2; + + sp.lock(); + sp2.lock_shared(); + sp2.lock_shared(); + + sp.unlock(); + sp2.unlock_shared(); + sp2.unlock_shared(); + + { + std::lock_guard lock(sp); + boost::compat::shared_lock lock2(sp2); + boost::compat::shared_lock lock3(sp2); + } +} + +UNORDERED_AUTO_TEST (rw_spinlock_test5) { + rw_spinlock sp; + + { + BOOST_TEST(sp.try_lock_shared()); + BOOST_TEST(sp.try_lock_shared()); + sp.unlock_shared(); + sp.unlock_shared(); + } + + { + BOOST_TEST(sp.try_lock()); + BOOST_TEST(!sp.try_lock_shared()); + sp.unlock(); + } + + { + std::lock_guard lock(sp); + BOOST_TEST(!sp.try_lock_shared()); + } + + { + boost::compat::shared_lock lock(sp); + BOOST_TEST(!sp.try_lock()); + BOOST_TEST(sp.try_lock_shared()); + sp.unlock_shared(); + } +} + +UNORDERED_AUTO_TEST (rw_spinlock_test6) { + count = 0; + + rw_spinlock sp; + + int const N = 1000000; // total iterations + int const M = 8; // threads + + std::thread th[M]; + + for (int i = 0; i < M; ++i) { + int n = N; + th[i] = std::thread([n, &sp] { + for (;;) { + { + boost::compat::shared_lock lock(sp); + if (count >= n) + break; + } + + { + std::lock_guard lock(sp); + if (count >= n) + break; + ++count; + } + } + }); + } + + for (int i = 0; i < M; ++i) { + th[i].join(); + } + + BOOST_TEST_EQ(count, N); +} + +UNORDERED_AUTO_TEST (rw_spinlock_test7) { + rw_spinlock sp; + + int const N = 1000000; // total iterations + int const M = 8; // threads + + std::thread th[M]; + + for (int i = 0; i < M; ++i) { + int n = N; + th[i] = std::thread([=, &sp] { + for (;;) { + int oldc; + + { + boost::compat::shared_lock lock(sp); + if (count >= n) + break; + oldc = count; + } + + { + std::lock_guard lock(sp); + if (count == oldc) + ++count; + } + } + }); + } + + for (int i = 0; i < M; ++i) { + th[i].join(); + } + + BOOST_TEST_EQ(count, N); +} + +UNORDERED_AUTO_TEST (rw_spinlock_test8) { + count = 0; + + rw_spinlock sp; + + int const N = 1000; // total iterations + int const M = 4; // threads + + std::thread th[M]; + + for (int i = 0; i < M; ++i) { + int k = i; + int m = M; + int n = N; + + th[i] = std::thread([k, m, n, &sp] { + for (int j = 0; j < n; ++j) { + int oldc; + + for (;;) { + { + boost::compat::shared_lock lock(sp); + oldc = count; + } + + if (oldc % m == k) + break; + } + + { + std::lock_guard lock(sp); + if (count == oldc) + ++count; + } + } + }); + } + + for (int i = 0; i < M; ++i) { + th[i].join(); + } + + BOOST_TEST_EQ(count, N * M); +} + +RUN_TESTS()