From 9790a3497f640605cbcacd72816dc6d83f2154fa Mon Sep 17 00:00:00 2001 From: khizmax Date: Wed, 3 Feb 2016 21:20:56 +0300 Subject: [PATCH] Moved queue unit tests to gtest framework --- CMakeLists.txt | 6 +- cds/intrusive/fcqueue.h | 2 +- cds/intrusive/segmented_queue.h | 4 +- projects/Win/vc14/gtest-queue.vcxproj | 13 + projects/Win/vc14/gtest-queue.vcxproj.filters | 39 +++ test/unit/queue/CMakeLists.txt | 11 + .../unit/queue/intrusive_basket_queue_dhp.cpp | 187 +++++++++++ test/unit/queue/intrusive_basket_queue_hp.cpp | 200 ++++++++++++ test/unit/queue/intrusive_fcqueue.cpp | 308 ++++++++++++++++++ test/unit/queue/intrusive_moirqueue_dhp.cpp | 187 +++++++++++ test/unit/queue/intrusive_moirqueue_hp.cpp | 200 ++++++++++++ test/unit/queue/intrusive_msqueue_dhp.cpp | 187 +++++++++++ test/unit/queue/intrusive_msqueue_hp.cpp | 200 ++++++++++++ test/unit/queue/intrusive_optqueue_dhp.cpp | 187 +++++++++++ test/unit/queue/intrusive_optqueue_hp.cpp | 200 ++++++++++++ .../queue/intrusive_segmented_queue_dhp.cpp | 166 ++++++++++ .../queue/intrusive_segmented_queue_hp.cpp | 166 ++++++++++ test/unit/queue/test_intrusive_msqueue.h | 159 +++++++++ .../queue/test_intrusive_segmented_queue.h | 191 +++++++++++ 19 files changed, 2607 insertions(+), 6 deletions(-) create mode 100644 test/unit/queue/intrusive_basket_queue_dhp.cpp create mode 100644 test/unit/queue/intrusive_basket_queue_hp.cpp create mode 100644 test/unit/queue/intrusive_fcqueue.cpp create mode 100644 test/unit/queue/intrusive_moirqueue_dhp.cpp create mode 100644 test/unit/queue/intrusive_moirqueue_hp.cpp create mode 100644 test/unit/queue/intrusive_msqueue_dhp.cpp create mode 100644 test/unit/queue/intrusive_msqueue_hp.cpp create mode 100644 test/unit/queue/intrusive_optqueue_dhp.cpp create mode 100644 test/unit/queue/intrusive_optqueue_hp.cpp create mode 100644 test/unit/queue/intrusive_segmented_queue_dhp.cpp create mode 100644 test/unit/queue/intrusive_segmented_queue_hp.cpp create mode 100644 test/unit/queue/test_intrusive_msqueue.h create mode 100644 test/unit/queue/test_intrusive_segmented_queue.h diff --git a/CMakeLists.txt b/CMakeLists.txt index c8d253ef..9b6f2bb5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,9 +39,9 @@ set(CDS_STATIC_LIBRARY ${PROJECT_NAME}-s) set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) set(CMAKE_INCLUDE_CURRENT_DIR ON) -if(CDS_BIN_ROOT) - set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/${CDS_BIN_ROOT}) - set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/${CDS_BIN_ROOT}) +if(CDS_BIN_DIR) + set(EXECUTABLE_OUTPUT_PATH ${CDS_BIN_DIR}) + set(LIBRARY_OUTPUT_PATH ${CDS_BIN_DIR}) else() set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) diff --git a/cds/intrusive/fcqueue.h b/cds/intrusive/fcqueue.h index c369c371..dae81665 100644 --- a/cds/intrusive/fcqueue.h +++ b/cds/intrusive/fcqueue.h @@ -83,7 +83,7 @@ namespace cds { namespace intrusive { \p Options are: - \p opt::lock_type - mutex type, default is \p cds::sync::spin - \p opt::back_off - back-off strategy, defalt is \p cds::backoff::Default - - \p opt::disposer - the functor used for dispose removed items. Default is \p opt::intrusive::v::empty_disposer. + - \p opt::disposer - the functor used to dispose removed items. Default is \p opt::intrusive::v::empty_disposer. This option is used only in \p FCQueue::clear() function. - \p opt::allocator - allocator type, default is \ref CDS_DEFAULT_ALLOCATOR - \p opt::stat - internal statistics, possible type: \p fcqueue::stat, \p fcqueue::empty_stat (the default) diff --git a/cds/intrusive/segmented_queue.h b/cds/intrusive/segmented_queue.h index dfb93882..83cfb1da 100644 --- a/cds/intrusive/segmented_queue.h +++ b/cds/intrusive/segmented_queue.h @@ -152,7 +152,7 @@ namespace cds { namespace intrusive { all other \p %segmented_queue::traits members left unchanged. \p Options are: - - \p opt::disposer - the functor used for dispose removed items. + - \p opt::disposer - the functor used to dispose removed items. - \p opt::stat - internal statistics, possible type: \p segmented_queue::stat, \p segmented_queue::empty_stat (the default) - \p opt::item_counter - item counting feature. Note that \p atomicity::empty_item_counetr is not suitable for segmented queue. @@ -599,7 +599,7 @@ namespace cds { namespace intrusive { /// Clear the queue /** - The function repeatedly calls \ref dequeue until it returns \p nullptr. + The function repeatedly calls \p dequeue() until it returns \p nullptr. The disposer specified in \p Traits template argument is called for each removed item. */ void clear() diff --git a/projects/Win/vc14/gtest-queue.vcxproj b/projects/Win/vc14/gtest-queue.vcxproj index edb20c69..713f1c8a 100644 --- a/projects/Win/vc14/gtest-queue.vcxproj +++ b/projects/Win/vc14/gtest-queue.vcxproj @@ -31,6 +31,17 @@ + + + + + + + + + + + @@ -48,6 +59,8 @@ + + diff --git a/projects/Win/vc14/gtest-queue.vcxproj.filters b/projects/Win/vc14/gtest-queue.vcxproj.filters index 2158a14d..723ac426 100644 --- a/projects/Win/vc14/gtest-queue.vcxproj.filters +++ b/projects/Win/vc14/gtest-queue.vcxproj.filters @@ -60,6 +60,39 @@ Source Files + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + @@ -71,5 +104,11 @@ Header Files + + Header Files + + + Header Files + \ No newline at end of file diff --git a/test/unit/queue/CMakeLists.txt b/test/unit/queue/CMakeLists.txt index 163a1082..62f6c2c0 100644 --- a/test/unit/queue/CMakeLists.txt +++ b/test/unit/queue/CMakeLists.txt @@ -16,6 +16,17 @@ set(CDSGTEST_QUEUE_SOURCES segmented_queue_dhp.cpp tsigas_queue.cpp vyukov_mpmc_queue.cpp + intrusive_basket_queue_hp.cpp + intrusive_basket_queue_dhp.cpp + intrusive_fcqueue.cpp + intrusive_msqueue_hp.cpp + intrusive_msqueue_dhp.cpp + intrusive_moirqueue_hp.cpp + intrusive_moirqueue_dhp.cpp + intrusive_optqueue_hp.cpp + intrusive_optqueue_dhp.cpp + intrusive_segmented_queue_hp.cpp + intrusive_segmented_queue_dhp.cpp ) include_directories( diff --git a/test/unit/queue/intrusive_basket_queue_dhp.cpp b/test/unit/queue/intrusive_basket_queue_dhp.cpp new file mode 100644 index 00000000..67f169b5 --- /dev/null +++ b/test/unit/queue/intrusive_basket_queue_dhp.cpp @@ -0,0 +1,187 @@ +/* + This file is a part of libcds - Concurrent Data Structures library + + (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016 + + Source code repo: http://github.com/khizmax/libcds/ + Download: http://sourceforge.net/projects/libcds/files/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "test_intrusive_msqueue.h" + +#include +#include +#include + +namespace { + namespace ci = cds::intrusive; + typedef cds::gc::DHP gc_type; + + + class IntrusiveBasketQueue_DHP : public cds_test::intrusive_msqueue + { + typedef cds_test::intrusive_msqueue base_class; + + protected: + typedef typename base_class::base_hook_item< ci::basket_queue::node> base_item_type; + typedef typename base_class::member_hook_item< ci::basket_queue::node> member_item_type; + + void SetUp() + { + typedef ci::BasketQueue< gc_type, base_item_type, + typename ci::basket_queue::make_traits< + ci::opt::hook< ci::basket_queue::base_hook< ci::opt::gc>> + >::type + > queue_type; + + cds::gc::dhp::GarbageCollector::Construct( 16, queue_type::c_nHazardPtrCount ); + cds::threading::Manager::attachThread(); + } + + void TearDown() + { + cds::threading::Manager::detachThread(); + cds::gc::dhp::GarbageCollector::Destruct(); + } + + template + void check_array( V& arr ) + { + for ( size_t i = 0; i < arr.size() - 1; ++i ) { + ASSERT_EQ( arr[i].nDisposeCount, 2 ); + } + ASSERT_EQ( arr.back().nDisposeCount, 1 ); + } + }; + + TEST_F( IntrusiveBasketQueue_DHP, base_hook ) + { + typedef cds::intrusive::BasketQueue< gc_type, base_item_type, + typename ci::basket_queue::make_traits< + ci::opt::disposer< mock_disposer > + ,ci::opt::hook< ci::basket_queue::base_hook< ci::opt::gc>> + >::type + > test_queue; + + std::vector arr; + arr.resize(100); + { + test_queue q; + test(q, arr); + } + gc_type::scan(); + check_array( arr ); + } + + TEST_F( IntrusiveBasketQueue_DHP, base_item_counting ) + { + typedef cds::intrusive::BasketQueue< gc_type, base_item_type, + typename ci::basket_queue::make_traits< + ci::opt::disposer< mock_disposer > + , cds::opt::item_counter< cds::atomicity::item_counter > + , ci::opt::hook< ci::basket_queue::base_hook< ci::opt::gc>> + >::type + > test_queue; + + std::vector arr; + arr.resize(100); + { + test_queue q; + test(q, arr); + } + gc_type::scan(); + check_array( arr ); + } + + TEST_F( IntrusiveBasketQueue_DHP, base_stat ) + { + struct traits : public ci::basket_queue::traits + { + typedef ci::basket_queue::base_hook< ci::opt::gc> hook; + typedef mock_disposer disposer; + typedef cds::atomicity::item_counter item_counter; + typedef ci::basket_queue::stat<> stat; + typedef cds::opt::v::sequential_consistent memory_model; + }; + typedef cds::intrusive::BasketQueue< gc_type, base_item_type, traits > test_queue; + + std::vector arr; + arr.resize(100); + { + test_queue q; + test(q, arr); + } + gc_type::scan(); + check_array( arr ); + } + + TEST_F( IntrusiveBasketQueue_DHP, member_hook ) + { + typedef cds::intrusive::BasketQueue< gc_type, member_item_type, + typename ci::basket_queue::make_traits< + ci::opt::disposer< mock_disposer > + ,ci::opt::hook< ci::basket_queue::member_hook< + offsetof( member_item_type, hMember ), + ci::opt::gc + >> + >::type + > test_queue; + + std::vector arr; + arr.resize( 100 ); + { + test_queue q; + test( q, arr ); + } + gc_type::scan(); + check_array( arr ); + } + + TEST_F( IntrusiveBasketQueue_DHP, member_hook_stat ) + { + struct traits : public ci::basket_queue::traits + { + typedef ci::basket_queue::member_hook< + offsetof( member_item_type, hMember ), + ci::opt::gc + > hook; + typedef mock_disposer disposer; + typedef cds::atomicity::item_counter item_counter; + typedef ci::basket_queue::stat<> stat; + typedef cds::opt::v::sequential_consistent memory_model; + }; + typedef cds::intrusive::BasketQueue< gc_type, member_item_type, traits > test_queue; + + std::vector arr; + arr.resize( 100 ); + { + test_queue q; + test( q, arr ); + } + gc_type::scan(); + check_array( arr ); + } + +} // namespace + diff --git a/test/unit/queue/intrusive_basket_queue_hp.cpp b/test/unit/queue/intrusive_basket_queue_hp.cpp new file mode 100644 index 00000000..2cba55e0 --- /dev/null +++ b/test/unit/queue/intrusive_basket_queue_hp.cpp @@ -0,0 +1,200 @@ +/* + This file is a part of libcds - Concurrent Data Structures library + + (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016 + + Source code repo: http://github.com/khizmax/libcds/ + Download: http://sourceforge.net/projects/libcds/files/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "test_intrusive_msqueue.h" + +#include +#include +#include + +namespace { + namespace ci = cds::intrusive; + typedef cds::gc::HP gc_type; + + + class IntrusiveBasketQueue_HP : public cds_test::intrusive_msqueue + { + typedef cds_test::intrusive_msqueue base_class; + + protected: + typedef typename base_class::base_hook_item< ci::basket_queue::node> base_item_type; + typedef typename base_class::member_hook_item< ci::basket_queue::node> member_item_type; + + void SetUp() + { + typedef ci::BasketQueue< gc_type, base_item_type > queue_type; + + cds::gc::hp::GarbageCollector::Construct( queue_type::c_nHazardPtrCount, 1, 16 ); + cds::threading::Manager::attachThread(); + } + + void TearDown() + { + cds::threading::Manager::detachThread(); + cds::gc::hp::GarbageCollector::Destruct( true ); + } + + template + void check_array( V& arr ) + { + for ( size_t i = 0; i < arr.size() - 1; ++i ) { + ASSERT_EQ( arr[i].nDisposeCount, 2 ); + } + ASSERT_EQ( arr.back().nDisposeCount, 1 ); + } + }; + + TEST_F( IntrusiveBasketQueue_HP, defaulted ) + { + typedef cds::intrusive::BasketQueue< gc_type, base_item_type, + typename ci::basket_queue::make_traits< + ci::opt::disposer< mock_disposer > + >::type + > test_queue; + + std::vector arr; + arr.resize(100); + { + test_queue q; + test(q, arr); + } + gc_type::scan(); + check_array( arr ); + } + + TEST_F( IntrusiveBasketQueue_HP, base_hook ) + { + typedef cds::intrusive::BasketQueue< gc_type, base_item_type, + typename ci::basket_queue::make_traits< + ci::opt::disposer< mock_disposer > + ,ci::opt::hook< ci::basket_queue::base_hook< ci::opt::gc>> + >::type + > test_queue; + + std::vector arr; + arr.resize(100); + { + test_queue q; + test(q, arr); + } + gc_type::scan(); + check_array( arr ); + } + + TEST_F( IntrusiveBasketQueue_HP, base_item_counting ) + { + typedef cds::intrusive::BasketQueue< gc_type, base_item_type, + typename ci::basket_queue::make_traits< + ci::opt::disposer< mock_disposer > + , cds::opt::item_counter< cds::atomicity::item_counter > + , ci::opt::hook< ci::basket_queue::base_hook< ci::opt::gc>> + >::type + > test_queue; + + std::vector arr; + arr.resize(100); + { + test_queue q; + test(q, arr); + } + gc_type::scan(); + check_array( arr ); + } + + TEST_F( IntrusiveBasketQueue_HP, base_stat ) + { + struct traits : public ci::basket_queue::traits + { + typedef mock_disposer disposer; + typedef cds::atomicity::item_counter item_counter; + typedef ci::basket_queue::stat<> stat; + typedef cds::opt::v::sequential_consistent memory_model; + }; + typedef cds::intrusive::BasketQueue< gc_type, base_item_type, traits > test_queue; + + std::vector arr; + arr.resize(100); + { + test_queue q; + test(q, arr); + } + gc_type::scan(); + check_array( arr ); + } + + TEST_F( IntrusiveBasketQueue_HP, member_hook ) + { + typedef cds::intrusive::BasketQueue< gc_type, member_item_type, + typename ci::basket_queue::make_traits< + ci::opt::disposer< mock_disposer > + ,ci::opt::hook< ci::basket_queue::member_hook< + offsetof( member_item_type, hMember ), + ci::opt::gc + >> + >::type + > test_queue; + + std::vector arr; + arr.resize( 100 ); + { + test_queue q; + test( q, arr ); + } + gc_type::scan(); + check_array( arr ); + } + + TEST_F( IntrusiveBasketQueue_HP, member_hook_stat ) + { + struct traits : public ci::basket_queue::traits + { + typedef ci::basket_queue::member_hook< + offsetof( member_item_type, hMember ), + ci::opt::gc + > hook; + typedef mock_disposer disposer; + typedef cds::atomicity::item_counter item_counter; + typedef ci::basket_queue::stat<> stat; + typedef cds::opt::v::sequential_consistent memory_model; + }; + typedef cds::intrusive::BasketQueue< gc_type, member_item_type, traits > test_queue; + + std::vector arr; + arr.resize( 100 ); + { + test_queue q; + test( q, arr ); + } + gc_type::scan(); + check_array( arr ); + } + +} // namespace + diff --git a/test/unit/queue/intrusive_fcqueue.cpp b/test/unit/queue/intrusive_fcqueue.cpp new file mode 100644 index 00000000..9a5fc069 --- /dev/null +++ b/test/unit/queue/intrusive_fcqueue.cpp @@ -0,0 +1,308 @@ +/* + This file is a part of libcds - Concurrent Data Structures library + + (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016 + + Source code repo: http://github.com/khizmax/libcds/ + Download: http://sourceforge.net/projects/libcds/files/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include + +#include +#include + +namespace { + + class IntrusiveFCQueue : public ::testing::Test + { + protected: + template + struct base_hook_item : public Hook + { + int nVal; + int nDisposeCount; + + base_hook_item() + : nDisposeCount( 0 ) + {} + }; + + template + struct member_hook_item + { + int nVal; + int nDisposeCount; + Hook hMember; + + member_hook_item() + : nDisposeCount( 0 ) + {} + }; + + struct disposer + { + template + void operator ()( T * p ) + { + ++p->nDisposeCount; + } + }; + + template + void test( Queue& q ) + { + typedef typename Queue::value_type value_type; + + size_t const nSize = 100; + value_type * pv; + std::vector arr; + arr.resize( nSize ); + for ( size_t i = 0; i < nSize; ++i ) + arr[i].nVal = static_cast(i); + + ASSERT_TRUE( q.empty() ); + ASSERT_EQ( q.size(), 0 ); + + // pop from empty queue + pv = q.pop(); + ASSERT_TRUE( pv == nullptr ); + ASSERT_TRUE( q.empty() ); + ASSERT_EQ( q.size(), 0 ); + + pv = q.dequeue(); + ASSERT_TRUE( pv == nullptr ); + ASSERT_TRUE( q.empty() ); + ASSERT_EQ( q.size(), 0 ); + + // push/pop test + for ( size_t i = 0; i < nSize; ++i ) { + if ( i & 1 ) + q.push( arr[i] ); + else + q.enqueue( arr[i] ); + ASSERT_FALSE( q.empty() ); + ASSERT_EQ( q.size(), i + 1 ); + } + + for ( size_t i = 0; i < nSize; ++i ) { + ASSERT_FALSE( q.empty() ); + ASSERT_EQ( q.size(), nSize - i ); + if ( i & 1 ) + pv = q.pop(); + else + pv = q.dequeue(); + ASSERT_FALSE( pv == nullptr ); + ASSERT_EQ( pv->nVal, static_cast(i) ); + } + ASSERT_TRUE( q.empty() ); + ASSERT_EQ( q.size(), 0 ); + + // pop() doesn't call disposer + for ( size_t i = 0; i < nSize; ++i ) { + ASSERT_EQ( arr[i].nDisposeCount, 0 ); + } + + // clear with disposer + for ( size_t i = 0; i < nSize; ++i ) + q.push( arr[i] ); + + ASSERT_FALSE( q.empty() ); + ASSERT_EQ( q.size(), nSize ); + + q.clear( true ); + ASSERT_TRUE( q.empty() ); + ASSERT_EQ( q.size(), 0 ); + + for ( size_t i = 0; i < nSize; ++i ) { + ASSERT_EQ( arr[i].nDisposeCount, 1 ); + } + + // clear without disposer + for ( size_t i = 0; i < nSize; ++i ) + q.push( arr[i] ); + + q.clear(); + ASSERT_TRUE( q.empty() ); + ASSERT_EQ( q.size(), 0 ); + + for ( size_t i = 0; i < nSize; ++i ) { + ASSERT_EQ( arr[i].nDisposeCount, 1 ); + } + } + }; + + TEST_F( IntrusiveFCQueue, base ) + { + typedef base_hook_item< boost::intrusive::list_base_hook<> > value_type; + typedef cds::intrusive::FCQueue< value_type, boost::intrusive::list< value_type >, + cds::intrusive::fcqueue::make_traits< + cds::intrusive::opt::disposer< disposer > + >::type + > queue_type; + + queue_type q; + test( q ); + } + + TEST_F( IntrusiveFCQueue, base_mutex ) + { + typedef base_hook_item< boost::intrusive::list_base_hook<> > value_type; + struct traits : public cds::intrusive::fcqueue::traits + { + typedef IntrusiveFCQueue::disposer disposer; + typedef std::mutex lock_type; + typedef cds::intrusive::fcqueue::stat<> stat; + }; + typedef cds::intrusive::FCQueue< value_type, boost::intrusive::list< value_type >, traits > queue_type; + + queue_type q; + test( q ); + } + + TEST_F( IntrusiveFCQueue, base_elimination ) + { + typedef base_hook_item< boost::intrusive::list_base_hook<> > value_type; + struct traits : public + cds::intrusive::fcqueue::make_traits < + cds::intrusive::opt::disposer< disposer > + , cds::opt::enable_elimination < true > + > ::type + {}; + typedef cds::intrusive::FCQueue< value_type, boost::intrusive::list< value_type >, traits > queue_type; + + queue_type q; + test( q ); + } + + TEST_F( IntrusiveFCQueue, member ) + { + typedef member_hook_item< boost::intrusive::list_member_hook<> > value_type; + typedef boost::intrusive::member_hook, &value_type::hMember> member_option; + + typedef cds::intrusive::FCQueue< value_type, boost::intrusive::list< value_type, member_option >, + cds::intrusive::fcqueue::make_traits< + cds::intrusive::opt::disposer< disposer > + >::type + > queue_type; + + queue_type q; + test( q ); + } + + TEST_F( IntrusiveFCQueue, member_mutex ) + { + typedef member_hook_item< boost::intrusive::list_member_hook<> > value_type; + typedef boost::intrusive::member_hook, &value_type::hMember> member_option; + + struct traits : public cds::intrusive::fcqueue::traits + { + typedef IntrusiveFCQueue::disposer disposer; + typedef std::mutex lock_type; + typedef cds::intrusive::fcqueue::stat<> stat; + }; + typedef cds::intrusive::FCQueue< value_type, boost::intrusive::list< value_type, member_option >, traits > queue_type; + + queue_type q; + test( q ); + } + + TEST_F( IntrusiveFCQueue, member_elimination ) + { + typedef member_hook_item< boost::intrusive::list_member_hook<> > value_type; + typedef boost::intrusive::member_hook, &value_type::hMember> member_option; + + typedef cds::intrusive::FCQueue< value_type, boost::intrusive::list< value_type, member_option >, + cds::intrusive::fcqueue::make_traits< + cds::intrusive::opt::disposer< disposer > + ,cds::opt::enable_elimination< true > + >::type + > queue_type; + + queue_type q; + test( q ); + } + + TEST_F( IntrusiveFCQueue, slist_base ) + { + typedef base_hook_item< boost::intrusive::slist_base_hook<>> value_type; + typedef cds::intrusive::FCQueue< value_type, boost::intrusive::slist< value_type, boost::intrusive::cache_last< true >>, + cds::intrusive::fcqueue::make_traits< + cds::intrusive::opt::disposer< disposer > + >::type + > queue_type; + + queue_type q; + test( q ); + } + + TEST_F( IntrusiveFCQueue, slist_base_elimination ) + { + typedef base_hook_item< boost::intrusive::slist_base_hook<> > value_type; + struct traits : public + cds::intrusive::fcqueue::make_traits < + cds::intrusive::opt::disposer< disposer > + , cds::opt::enable_elimination < true > + , cds::opt::lock_type< std::mutex > + > ::type + {}; + typedef cds::intrusive::FCQueue< value_type, boost::intrusive::slist< value_type, boost::intrusive::cache_last< true >>, traits > queue_type; + + queue_type q; + test( q ); + } + + TEST_F( IntrusiveFCQueue, slist_member ) + { + typedef member_hook_item< boost::intrusive::slist_member_hook<> > value_type; + typedef boost::intrusive::member_hook, &value_type::hMember> member_option; + + typedef cds::intrusive::FCQueue< value_type, boost::intrusive::slist< value_type, member_option, boost::intrusive::cache_last< true >>, + cds::intrusive::fcqueue::make_traits< + cds::intrusive::opt::disposer< disposer > + >::type + > queue_type; + + queue_type q; + test( q ); + } + + TEST_F( IntrusiveFCQueue, slist_member_elimination ) + { + typedef member_hook_item< boost::intrusive::slist_member_hook<> > value_type; + typedef boost::intrusive::member_hook, &value_type::hMember> member_option; + + typedef cds::intrusive::FCQueue< value_type, boost::intrusive::slist< value_type, member_option, boost::intrusive::cache_last< true >>, + cds::intrusive::fcqueue::make_traits< + cds::intrusive::opt::disposer< disposer > + ,cds::opt::enable_elimination< true > + >::type + > queue_type; + + queue_type q; + test( q ); + } + +} // namepace diff --git a/test/unit/queue/intrusive_moirqueue_dhp.cpp b/test/unit/queue/intrusive_moirqueue_dhp.cpp new file mode 100644 index 00000000..8f52f4cc --- /dev/null +++ b/test/unit/queue/intrusive_moirqueue_dhp.cpp @@ -0,0 +1,187 @@ +/* + This file is a part of libcds - Concurrent Data Structures library + + (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016 + + Source code repo: http://github.com/khizmax/libcds/ + Download: http://sourceforge.net/projects/libcds/files/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "test_intrusive_msqueue.h" + +#include +#include +#include + +namespace { + namespace ci = cds::intrusive; + typedef cds::gc::DHP gc_type; + + + class IntrusiveMoirQueue_DHP : public cds_test::intrusive_msqueue + { + typedef cds_test::intrusive_msqueue base_class; + + protected: + typedef typename base_class::base_hook_item< ci::msqueue::node> base_item_type; + typedef typename base_class::member_hook_item< ci::msqueue::node> member_item_type; + + void SetUp() + { + typedef ci::MoirQueue< gc_type, base_item_type, + typename ci::msqueue::make_traits< + ci::opt::hook< ci::msqueue::base_hook< ci::opt::gc>> + >::type + > queue_type; + + cds::gc::dhp::GarbageCollector::Construct( 16, queue_type::c_nHazardPtrCount ); + cds::threading::Manager::attachThread(); + } + + void TearDown() + { + cds::threading::Manager::detachThread(); + cds::gc::dhp::GarbageCollector::Destruct(); + } + + template + void check_array( V& arr ) + { + for ( size_t i = 0; i < arr.size() - 1; ++i ) { + ASSERT_EQ( arr[i].nDisposeCount, 2 ); + } + ASSERT_EQ( arr.back().nDisposeCount, 1 ); + } + }; + + TEST_F( IntrusiveMoirQueue_DHP, base_hook ) + { + typedef cds::intrusive::MoirQueue< gc_type, base_item_type, + typename ci::msqueue::make_traits< + ci::opt::disposer< mock_disposer > + ,ci::opt::hook< ci::msqueue::base_hook< ci::opt::gc>> + >::type + > test_queue; + + std::vector arr; + arr.resize(100); + { + test_queue q; + test(q, arr); + } + gc_type::scan(); + check_array( arr ); + } + + TEST_F( IntrusiveMoirQueue_DHP, base_item_counting ) + { + typedef cds::intrusive::MoirQueue< gc_type, base_item_type, + typename ci::msqueue::make_traits< + ci::opt::disposer< mock_disposer > + , cds::opt::item_counter< cds::atomicity::item_counter > + , ci::opt::hook< ci::msqueue::base_hook< ci::opt::gc>> + >::type + > test_queue; + + std::vector arr; + arr.resize(100); + { + test_queue q; + test(q, arr); + } + gc_type::scan(); + check_array( arr ); + } + + TEST_F( IntrusiveMoirQueue_DHP, base_stat ) + { + struct traits : public ci::msqueue::traits + { + typedef ci::msqueue::base_hook< ci::opt::gc> hook; + typedef mock_disposer disposer; + typedef cds::atomicity::item_counter item_counter; + typedef ci::msqueue::stat<> stat; + typedef cds::opt::v::sequential_consistent memory_model; + }; + typedef cds::intrusive::MoirQueue< gc_type, base_item_type, traits > test_queue; + + std::vector arr; + arr.resize(100); + { + test_queue q; + test(q, arr); + } + gc_type::scan(); + check_array( arr ); + } + + TEST_F( IntrusiveMoirQueue_DHP, member_hook ) + { + typedef cds::intrusive::MoirQueue< gc_type, member_item_type, + typename ci::msqueue::make_traits< + ci::opt::disposer< mock_disposer > + ,ci::opt::hook< ci::msqueue::member_hook< + offsetof( member_item_type, hMember ), + ci::opt::gc + >> + >::type + > test_queue; + + std::vector arr; + arr.resize( 100 ); + { + test_queue q; + test( q, arr ); + } + gc_type::scan(); + check_array( arr ); + } + + TEST_F( IntrusiveMoirQueue_DHP, member_hook_stat ) + { + struct traits : public ci::msqueue::traits + { + typedef ci::msqueue::member_hook< + offsetof( member_item_type, hMember ), + ci::opt::gc + > hook; + typedef mock_disposer disposer; + typedef cds::atomicity::item_counter item_counter; + typedef ci::msqueue::stat<> stat; + typedef cds::opt::v::sequential_consistent memory_model; + }; + typedef cds::intrusive::MoirQueue< gc_type, member_item_type, traits > test_queue; + + std::vector arr; + arr.resize( 100 ); + { + test_queue q; + test( q, arr ); + } + gc_type::scan(); + check_array( arr ); + } + +} // namespace + diff --git a/test/unit/queue/intrusive_moirqueue_hp.cpp b/test/unit/queue/intrusive_moirqueue_hp.cpp new file mode 100644 index 00000000..c172a7f5 --- /dev/null +++ b/test/unit/queue/intrusive_moirqueue_hp.cpp @@ -0,0 +1,200 @@ +/* + This file is a part of libcds - Concurrent Data Structures library + + (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016 + + Source code repo: http://github.com/khizmax/libcds/ + Download: http://sourceforge.net/projects/libcds/files/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "test_intrusive_msqueue.h" + +#include +#include +#include + +namespace { + namespace ci = cds::intrusive; + typedef cds::gc::HP gc_type; + + + class IntrusiveMoirQueue_HP : public cds_test::intrusive_msqueue + { + typedef cds_test::intrusive_msqueue base_class; + + protected: + typedef typename base_class::base_hook_item< ci::msqueue::node> base_item_type; + typedef typename base_class::member_hook_item< ci::msqueue::node> member_item_type; + + void SetUp() + { + typedef ci::MoirQueue< gc_type, base_item_type > queue_type; + + cds::gc::hp::GarbageCollector::Construct( queue_type::c_nHazardPtrCount, 1, 16 ); + cds::threading::Manager::attachThread(); + } + + void TearDown() + { + cds::threading::Manager::detachThread(); + cds::gc::hp::GarbageCollector::Destruct( true ); + } + + template + void check_array( V& arr ) + { + for ( size_t i = 0; i < arr.size() - 1; ++i ) { + ASSERT_EQ( arr[i].nDisposeCount, 2 ); + } + ASSERT_EQ( arr.back().nDisposeCount, 1 ); + } + }; + + TEST_F( IntrusiveMoirQueue_HP, defaulted ) + { + typedef cds::intrusive::MoirQueue< gc_type, base_item_type, + typename ci::msqueue::make_traits< + ci::opt::disposer< mock_disposer > + >::type + > test_queue; + + std::vector arr; + arr.resize(100); + { + test_queue q; + test(q, arr); + } + gc_type::scan(); + check_array( arr ); + } + + TEST_F( IntrusiveMoirQueue_HP, base_hook ) + { + typedef cds::intrusive::MoirQueue< gc_type, base_item_type, + typename ci::msqueue::make_traits< + ci::opt::disposer< mock_disposer > + ,ci::opt::hook< ci::msqueue::base_hook< ci::opt::gc>> + >::type + > test_queue; + + std::vector arr; + arr.resize(100); + { + test_queue q; + test(q, arr); + } + gc_type::scan(); + check_array( arr ); + } + + TEST_F( IntrusiveMoirQueue_HP, base_item_counting ) + { + typedef cds::intrusive::MoirQueue< gc_type, base_item_type, + typename ci::msqueue::make_traits< + ci::opt::disposer< mock_disposer > + , cds::opt::item_counter< cds::atomicity::item_counter > + , ci::opt::hook< ci::msqueue::base_hook< ci::opt::gc>> + >::type + > test_queue; + + std::vector arr; + arr.resize(100); + { + test_queue q; + test(q, arr); + } + gc_type::scan(); + check_array( arr ); + } + + TEST_F( IntrusiveMoirQueue_HP, base_stat ) + { + struct traits : public ci::msqueue::traits + { + typedef mock_disposer disposer; + typedef cds::atomicity::item_counter item_counter; + typedef ci::msqueue::stat<> stat; + typedef cds::opt::v::sequential_consistent memory_model; + }; + typedef cds::intrusive::MoirQueue< gc_type, base_item_type, traits > test_queue; + + std::vector arr; + arr.resize(100); + { + test_queue q; + test(q, arr); + } + gc_type::scan(); + check_array( arr ); + } + + TEST_F( IntrusiveMoirQueue_HP, member_hook ) + { + typedef cds::intrusive::MoirQueue< gc_type, member_item_type, + typename ci::msqueue::make_traits< + ci::opt::disposer< mock_disposer > + ,ci::opt::hook< ci::msqueue::member_hook< + offsetof( member_item_type, hMember ), + ci::opt::gc + >> + >::type + > test_queue; + + std::vector arr; + arr.resize( 100 ); + { + test_queue q; + test( q, arr ); + } + gc_type::scan(); + check_array( arr ); + } + + TEST_F( IntrusiveMoirQueue_HP, member_hook_stat ) + { + struct traits : public ci::msqueue::traits + { + typedef ci::msqueue::member_hook< + offsetof( member_item_type, hMember ), + ci::opt::gc + > hook; + typedef mock_disposer disposer; + typedef cds::atomicity::item_counter item_counter; + typedef ci::msqueue::stat<> stat; + typedef cds::opt::v::sequential_consistent memory_model; + }; + typedef cds::intrusive::MoirQueue< gc_type, member_item_type, traits > test_queue; + + std::vector arr; + arr.resize( 100 ); + { + test_queue q; + test( q, arr ); + } + gc_type::scan(); + check_array( arr ); + } + +} // namespace + diff --git a/test/unit/queue/intrusive_msqueue_dhp.cpp b/test/unit/queue/intrusive_msqueue_dhp.cpp new file mode 100644 index 00000000..67327a3d --- /dev/null +++ b/test/unit/queue/intrusive_msqueue_dhp.cpp @@ -0,0 +1,187 @@ +/* + This file is a part of libcds - Concurrent Data Structures library + + (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016 + + Source code repo: http://github.com/khizmax/libcds/ + Download: http://sourceforge.net/projects/libcds/files/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "test_intrusive_msqueue.h" + +#include +#include +#include + +namespace { + namespace ci = cds::intrusive; + typedef cds::gc::DHP gc_type; + + + class IntrusiveMSQueue_DHP : public cds_test::intrusive_msqueue + { + typedef cds_test::intrusive_msqueue base_class; + + protected: + typedef typename base_class::base_hook_item< ci::msqueue::node> base_item_type; + typedef typename base_class::member_hook_item< ci::msqueue::node> member_item_type; + + void SetUp() + { + typedef ci::MSQueue< gc_type, base_item_type, + typename ci::msqueue::make_traits< + ci::opt::hook< ci::msqueue::base_hook< ci::opt::gc>> + >::type + > queue_type; + + cds::gc::dhp::GarbageCollector::Construct( 16, queue_type::c_nHazardPtrCount ); + cds::threading::Manager::attachThread(); + } + + void TearDown() + { + cds::threading::Manager::detachThread(); + cds::gc::dhp::GarbageCollector::Destruct(); + } + + template + void check_array( V& arr ) + { + for ( size_t i = 0; i < arr.size() - 1; ++i ) { + ASSERT_EQ( arr[i].nDisposeCount, 2 ); + } + ASSERT_EQ( arr.back().nDisposeCount, 1 ); + } + }; + + TEST_F( IntrusiveMSQueue_DHP, base_hook ) + { + typedef cds::intrusive::MSQueue< gc_type, base_item_type, + typename ci::msqueue::make_traits< + ci::opt::disposer< mock_disposer > + ,ci::opt::hook< ci::msqueue::base_hook< ci::opt::gc>> + >::type + > test_queue; + + std::vector arr; + arr.resize(100); + { + test_queue q; + test(q, arr); + } + gc_type::scan(); + check_array( arr ); + } + + TEST_F( IntrusiveMSQueue_DHP, base_item_counting ) + { + typedef cds::intrusive::MSQueue< gc_type, base_item_type, + typename ci::msqueue::make_traits< + ci::opt::disposer< mock_disposer > + , cds::opt::item_counter< cds::atomicity::item_counter > + , ci::opt::hook< ci::msqueue::base_hook< ci::opt::gc>> + >::type + > test_queue; + + std::vector arr; + arr.resize(100); + { + test_queue q; + test(q, arr); + } + gc_type::scan(); + check_array( arr ); + } + + TEST_F( IntrusiveMSQueue_DHP, base_stat ) + { + struct traits : public ci::msqueue::traits + { + typedef ci::msqueue::base_hook< ci::opt::gc> hook; + typedef mock_disposer disposer; + typedef cds::atomicity::item_counter item_counter; + typedef ci::msqueue::stat<> stat; + typedef cds::opt::v::sequential_consistent memory_model; + }; + typedef cds::intrusive::MSQueue< gc_type, base_item_type, traits > test_queue; + + std::vector arr; + arr.resize(100); + { + test_queue q; + test(q, arr); + } + gc_type::scan(); + check_array( arr ); + } + + TEST_F( IntrusiveMSQueue_DHP, member_hook ) + { + typedef cds::intrusive::MSQueue< gc_type, member_item_type, + typename ci::msqueue::make_traits< + ci::opt::disposer< mock_disposer > + ,ci::opt::hook< ci::msqueue::member_hook< + offsetof( member_item_type, hMember ), + ci::opt::gc + >> + >::type + > test_queue; + + std::vector arr; + arr.resize( 100 ); + { + test_queue q; + test( q, arr ); + } + gc_type::scan(); + check_array( arr ); + } + + TEST_F( IntrusiveMSQueue_DHP, member_hook_stat ) + { + struct traits : public ci::msqueue::traits + { + typedef ci::msqueue::member_hook< + offsetof( member_item_type, hMember ), + ci::opt::gc + > hook; + typedef mock_disposer disposer; + typedef cds::atomicity::item_counter item_counter; + typedef ci::msqueue::stat<> stat; + typedef cds::opt::v::sequential_consistent memory_model; + }; + typedef cds::intrusive::MSQueue< gc_type, member_item_type, traits > test_queue; + + std::vector arr; + arr.resize( 100 ); + { + test_queue q; + test( q, arr ); + } + gc_type::scan(); + check_array( arr ); + } + +} // namespace + diff --git a/test/unit/queue/intrusive_msqueue_hp.cpp b/test/unit/queue/intrusive_msqueue_hp.cpp new file mode 100644 index 00000000..7a81e66c --- /dev/null +++ b/test/unit/queue/intrusive_msqueue_hp.cpp @@ -0,0 +1,200 @@ +/* + This file is a part of libcds - Concurrent Data Structures library + + (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016 + + Source code repo: http://github.com/khizmax/libcds/ + Download: http://sourceforge.net/projects/libcds/files/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "test_intrusive_msqueue.h" + +#include +#include +#include + +namespace { + namespace ci = cds::intrusive; + typedef cds::gc::HP gc_type; + + + class IntrusiveMSQueue_HP : public cds_test::intrusive_msqueue + { + typedef cds_test::intrusive_msqueue base_class; + + protected: + typedef typename base_class::base_hook_item< ci::msqueue::node> base_item_type; + typedef typename base_class::member_hook_item< ci::msqueue::node> member_item_type; + + void SetUp() + { + typedef ci::MSQueue< gc_type, base_item_type > queue_type; + + cds::gc::hp::GarbageCollector::Construct( queue_type::c_nHazardPtrCount, 1, 16 ); + cds::threading::Manager::attachThread(); + } + + void TearDown() + { + cds::threading::Manager::detachThread(); + cds::gc::hp::GarbageCollector::Destruct( true ); + } + + template + void check_array( V& arr ) + { + for ( size_t i = 0; i < arr.size() - 1; ++i ) { + ASSERT_EQ( arr[i].nDisposeCount, 2 ); + } + ASSERT_EQ( arr.back().nDisposeCount, 1 ); + } + }; + + TEST_F( IntrusiveMSQueue_HP, defaulted ) + { + typedef cds::intrusive::MSQueue< gc_type, base_item_type, + typename ci::msqueue::make_traits< + ci::opt::disposer< mock_disposer > + >::type + > test_queue; + + std::vector arr; + arr.resize(100); + { + test_queue q; + test(q, arr); + } + gc_type::scan(); + check_array( arr ); + } + + TEST_F( IntrusiveMSQueue_HP, base_hook ) + { + typedef cds::intrusive::MSQueue< gc_type, base_item_type, + typename ci::msqueue::make_traits< + ci::opt::disposer< mock_disposer > + ,ci::opt::hook< ci::msqueue::base_hook< ci::opt::gc>> + >::type + > test_queue; + + std::vector arr; + arr.resize(100); + { + test_queue q; + test(q, arr); + } + gc_type::scan(); + check_array( arr ); + } + + TEST_F( IntrusiveMSQueue_HP, base_item_counting ) + { + typedef cds::intrusive::MSQueue< gc_type, base_item_type, + typename ci::msqueue::make_traits< + ci::opt::disposer< mock_disposer > + , cds::opt::item_counter< cds::atomicity::item_counter > + , ci::opt::hook< ci::msqueue::base_hook< ci::opt::gc>> + >::type + > test_queue; + + std::vector arr; + arr.resize(100); + { + test_queue q; + test(q, arr); + } + gc_type::scan(); + check_array( arr ); + } + + TEST_F( IntrusiveMSQueue_HP, base_stat ) + { + struct traits : public ci::msqueue::traits + { + typedef mock_disposer disposer; + typedef cds::atomicity::item_counter item_counter; + typedef ci::msqueue::stat<> stat; + typedef cds::opt::v::sequential_consistent memory_model; + }; + typedef cds::intrusive::MSQueue< gc_type, base_item_type, traits > test_queue; + + std::vector arr; + arr.resize(100); + { + test_queue q; + test(q, arr); + } + gc_type::scan(); + check_array( arr ); + } + + TEST_F( IntrusiveMSQueue_HP, member_hook ) + { + typedef cds::intrusive::MSQueue< gc_type, member_item_type, + typename ci::msqueue::make_traits< + ci::opt::disposer< mock_disposer > + ,ci::opt::hook< ci::msqueue::member_hook< + offsetof( member_item_type, hMember ), + ci::opt::gc + >> + >::type + > test_queue; + + std::vector arr; + arr.resize( 100 ); + { + test_queue q; + test( q, arr ); + } + gc_type::scan(); + check_array( arr ); + } + + TEST_F( IntrusiveMSQueue_HP, member_hook_stat ) + { + struct traits : public ci::msqueue::traits + { + typedef ci::msqueue::member_hook< + offsetof( member_item_type, hMember ), + ci::opt::gc + > hook; + typedef mock_disposer disposer; + typedef cds::atomicity::item_counter item_counter; + typedef ci::msqueue::stat<> stat; + typedef cds::opt::v::sequential_consistent memory_model; + }; + typedef cds::intrusive::MSQueue< gc_type, member_item_type, traits > test_queue; + + std::vector arr; + arr.resize( 100 ); + { + test_queue q; + test( q, arr ); + } + gc_type::scan(); + check_array( arr ); + } + +} // namespace + diff --git a/test/unit/queue/intrusive_optqueue_dhp.cpp b/test/unit/queue/intrusive_optqueue_dhp.cpp new file mode 100644 index 00000000..83d526fb --- /dev/null +++ b/test/unit/queue/intrusive_optqueue_dhp.cpp @@ -0,0 +1,187 @@ +/* + This file is a part of libcds - Concurrent Data Structures library + + (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016 + + Source code repo: http://github.com/khizmax/libcds/ + Download: http://sourceforge.net/projects/libcds/files/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "test_intrusive_msqueue.h" + +#include +#include +#include + +namespace { + namespace ci = cds::intrusive; + typedef cds::gc::DHP gc_type; + + + class IntrusiveOptQueue_DHP : public cds_test::intrusive_msqueue + { + typedef cds_test::intrusive_msqueue base_class; + + protected: + typedef typename base_class::base_hook_item< ci::optimistic_queue::node> base_item_type; + typedef typename base_class::member_hook_item< ci::optimistic_queue::node> member_item_type; + + void SetUp() + { + typedef ci::OptimisticQueue< gc_type, base_item_type, + typename ci::optimistic_queue::make_traits< + ci::opt::hook< ci::optimistic_queue::base_hook< ci::opt::gc>> + >::type + > queue_type; + + cds::gc::dhp::GarbageCollector::Construct( 16, queue_type::c_nHazardPtrCount ); + cds::threading::Manager::attachThread(); + } + + void TearDown() + { + cds::threading::Manager::detachThread(); + cds::gc::dhp::GarbageCollector::Destruct(); + } + + template + void check_array( V& arr ) + { + for ( size_t i = 0; i < arr.size() - 1; ++i ) { + ASSERT_EQ( arr[i].nDisposeCount, 2 ); + } + ASSERT_EQ( arr.back().nDisposeCount, 1 ); + } + }; + + TEST_F( IntrusiveOptQueue_DHP, base_hook ) + { + typedef cds::intrusive::OptimisticQueue< gc_type, base_item_type, + typename ci::optimistic_queue::make_traits< + ci::opt::disposer< mock_disposer > + ,ci::opt::hook< ci::optimistic_queue::base_hook< ci::opt::gc>> + >::type + > test_queue; + + std::vector arr; + arr.resize(100); + { + test_queue q; + test(q, arr); + } + gc_type::scan(); + check_array( arr ); + } + + TEST_F( IntrusiveOptQueue_DHP, base_item_counting ) + { + typedef cds::intrusive::OptimisticQueue< gc_type, base_item_type, + typename ci::optimistic_queue::make_traits< + ci::opt::disposer< mock_disposer > + , cds::opt::item_counter< cds::atomicity::item_counter > + , ci::opt::hook< ci::optimistic_queue::base_hook< ci::opt::gc>> + >::type + > test_queue; + + std::vector arr; + arr.resize(100); + { + test_queue q; + test(q, arr); + } + gc_type::scan(); + check_array( arr ); + } + + TEST_F( IntrusiveOptQueue_DHP, base_stat ) + { + struct traits : public ci::optimistic_queue::traits + { + typedef ci::optimistic_queue::base_hook< ci::opt::gc> hook; + typedef mock_disposer disposer; + typedef cds::atomicity::item_counter item_counter; + typedef ci::optimistic_queue::stat<> stat; + typedef cds::opt::v::sequential_consistent memory_model; + }; + typedef cds::intrusive::OptimisticQueue< gc_type, base_item_type, traits > test_queue; + + std::vector arr; + arr.resize(100); + { + test_queue q; + test(q, arr); + } + gc_type::scan(); + check_array( arr ); + } + + TEST_F( IntrusiveOptQueue_DHP, member_hook ) + { + typedef cds::intrusive::OptimisticQueue< gc_type, member_item_type, + typename ci::optimistic_queue::make_traits< + ci::opt::disposer< mock_disposer > + ,ci::opt::hook< ci::optimistic_queue::member_hook< + offsetof( member_item_type, hMember ), + ci::opt::gc + >> + >::type + > test_queue; + + std::vector arr; + arr.resize( 100 ); + { + test_queue q; + test( q, arr ); + } + gc_type::scan(); + check_array( arr ); + } + + TEST_F( IntrusiveOptQueue_DHP, member_hook_stat ) + { + struct traits : public ci::optimistic_queue::traits + { + typedef ci::optimistic_queue::member_hook< + offsetof( member_item_type, hMember ), + ci::opt::gc + > hook; + typedef mock_disposer disposer; + typedef cds::atomicity::item_counter item_counter; + typedef ci::optimistic_queue::stat<> stat; + typedef cds::opt::v::sequential_consistent memory_model; + }; + typedef cds::intrusive::OptimisticQueue< gc_type, member_item_type, traits > test_queue; + + std::vector arr; + arr.resize( 100 ); + { + test_queue q; + test( q, arr ); + } + gc_type::scan(); + check_array( arr ); + } + +} // namespace + diff --git a/test/unit/queue/intrusive_optqueue_hp.cpp b/test/unit/queue/intrusive_optqueue_hp.cpp new file mode 100644 index 00000000..4b1253f4 --- /dev/null +++ b/test/unit/queue/intrusive_optqueue_hp.cpp @@ -0,0 +1,200 @@ +/* + This file is a part of libcds - Concurrent Data Structures library + + (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016 + + Source code repo: http://github.com/khizmax/libcds/ + Download: http://sourceforge.net/projects/libcds/files/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "test_intrusive_msqueue.h" + +#include +#include +#include + +namespace { + namespace ci = cds::intrusive; + typedef cds::gc::HP gc_type; + + + class IntrusiveOptQueue_HP : public cds_test::intrusive_msqueue + { + typedef cds_test::intrusive_msqueue base_class; + + protected: + typedef typename base_class::base_hook_item< ci::optimistic_queue::node> base_item_type; + typedef typename base_class::member_hook_item< ci::optimistic_queue::node> member_item_type; + + void SetUp() + { + typedef ci::OptimisticQueue< gc_type, base_item_type > queue_type; + + cds::gc::hp::GarbageCollector::Construct( queue_type::c_nHazardPtrCount, 1, 16 ); + cds::threading::Manager::attachThread(); + } + + void TearDown() + { + cds::threading::Manager::detachThread(); + cds::gc::hp::GarbageCollector::Destruct( true ); + } + + template + void check_array( V& arr ) + { + for ( size_t i = 0; i < arr.size() - 1; ++i ) { + ASSERT_EQ( arr[i].nDisposeCount, 2 ); + } + ASSERT_EQ( arr.back().nDisposeCount, 1 ); + } + }; + + TEST_F( IntrusiveOptQueue_HP, defaulted ) + { + typedef cds::intrusive::OptimisticQueue< gc_type, base_item_type, + typename ci::optimistic_queue::make_traits< + ci::opt::disposer< mock_disposer > + >::type + > test_queue; + + std::vector arr; + arr.resize(100); + { + test_queue q; + test(q, arr); + } + gc_type::scan(); + check_array( arr ); + } + + TEST_F( IntrusiveOptQueue_HP, base_hook ) + { + typedef cds::intrusive::OptimisticQueue< gc_type, base_item_type, + typename ci::optimistic_queue::make_traits< + ci::opt::disposer< mock_disposer > + ,ci::opt::hook< ci::optimistic_queue::base_hook< ci::opt::gc>> + >::type + > test_queue; + + std::vector arr; + arr.resize(100); + { + test_queue q; + test(q, arr); + } + gc_type::scan(); + check_array( arr ); + } + + TEST_F( IntrusiveOptQueue_HP, base_item_counting ) + { + typedef cds::intrusive::OptimisticQueue< gc_type, base_item_type, + typename ci::optimistic_queue::make_traits< + ci::opt::disposer< mock_disposer > + , cds::opt::item_counter< cds::atomicity::item_counter > + , ci::opt::hook< ci::optimistic_queue::base_hook< ci::opt::gc>> + >::type + > test_queue; + + std::vector arr; + arr.resize(100); + { + test_queue q; + test(q, arr); + } + gc_type::scan(); + check_array( arr ); + } + + TEST_F( IntrusiveOptQueue_HP, base_stat ) + { + struct traits : public ci::optimistic_queue::traits + { + typedef mock_disposer disposer; + typedef cds::atomicity::item_counter item_counter; + typedef ci::optimistic_queue::stat<> stat; + typedef cds::opt::v::sequential_consistent memory_model; + }; + typedef cds::intrusive::OptimisticQueue< gc_type, base_item_type, traits > test_queue; + + std::vector arr; + arr.resize(100); + { + test_queue q; + test(q, arr); + } + gc_type::scan(); + check_array( arr ); + } + + TEST_F( IntrusiveOptQueue_HP, member_hook ) + { + typedef cds::intrusive::OptimisticQueue< gc_type, member_item_type, + typename ci::optimistic_queue::make_traits< + ci::opt::disposer< mock_disposer > + ,ci::opt::hook< ci::optimistic_queue::member_hook< + offsetof( member_item_type, hMember ), + ci::opt::gc + >> + >::type + > test_queue; + + std::vector arr; + arr.resize( 100 ); + { + test_queue q; + test( q, arr ); + } + gc_type::scan(); + check_array( arr ); + } + + TEST_F( IntrusiveOptQueue_HP, member_hook_stat ) + { + struct traits : public ci::optimistic_queue::traits + { + typedef ci::optimistic_queue::member_hook< + offsetof( member_item_type, hMember ), + ci::opt::gc + > hook; + typedef mock_disposer disposer; + typedef cds::atomicity::item_counter item_counter; + typedef ci::optimistic_queue::stat<> stat; + typedef cds::opt::v::sequential_consistent memory_model; + }; + typedef cds::intrusive::OptimisticQueue< gc_type, member_item_type, traits > test_queue; + + std::vector arr; + arr.resize( 100 ); + { + test_queue q; + test( q, arr ); + } + gc_type::scan(); + check_array( arr ); + } + +} // namespace + diff --git a/test/unit/queue/intrusive_segmented_queue_dhp.cpp b/test/unit/queue/intrusive_segmented_queue_dhp.cpp new file mode 100644 index 00000000..f910f980 --- /dev/null +++ b/test/unit/queue/intrusive_segmented_queue_dhp.cpp @@ -0,0 +1,166 @@ +/* + This file is a part of libcds - Concurrent Data Structures library + + (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016 + + Source code repo: http://github.com/khizmax/libcds/ + Download: http://sourceforge.net/projects/libcds/files/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "test_intrusive_segmented_queue.h" + +#include +#include +#include + +namespace { + namespace ci = cds::intrusive; + typedef cds::gc::DHP gc_type; + + class IntrusiveSegmentedQueue_DHP : public cds_test::intrusive_segmented_queue + { + typedef cds_test::intrusive_segmented_queue base_class; + + protected: + static const size_t c_QuasiFactor = 15; + + void SetUp() + { + typedef ci::SegmentedQueue< gc_type, item > queue_type; + + cds::gc::dhp::GarbageCollector::Construct( 16, queue_type::c_nHazardPtrCount ); + cds::threading::Manager::attachThread(); + } + + void TearDown() + { + cds::threading::Manager::detachThread(); + cds::gc::hp::GarbageCollector::Destruct(); + } + + template + void check_array( V& arr ) + { + for ( size_t i = 0; i < arr.size(); ++i ) { + EXPECT_EQ( arr[i].nDisposeCount, 2 ); + EXPECT_EQ( arr[i].nDispose2Count, 1 ); + } + } + }; + + TEST_F( IntrusiveSegmentedQueue_DHP, defaulted ) + { + struct queue_traits : public cds::intrusive::segmented_queue::traits + { + typedef Disposer disposer; + }; + typedef cds::intrusive::SegmentedQueue< gc_type, item, queue_traits > queue_type; + + std::vector arr; + { + queue_type q( c_QuasiFactor ); + test( q, arr ); + } + queue_type::gc::force_dispose(); + check_array( arr ); + } + + TEST_F( IntrusiveSegmentedQueue_DHP, mutex ) + { + struct queue_traits : public + cds::intrusive::segmented_queue::make_traits < + cds::intrusive::opt::disposer< Disposer > + ,cds::opt::lock_type < std::mutex > + > ::type + {}; + typedef cds::intrusive::SegmentedQueue< gc_type, item, queue_traits > queue_type; + + std::vector arr; + { + queue_type q( c_QuasiFactor ); + test( q, arr ); + } + queue_type::gc::force_dispose(); + check_array( arr ); + } + + TEST_F( IntrusiveSegmentedQueue_DHP, shuffle ) + { + typedef cds::intrusive::SegmentedQueue< gc_type, item, + cds::intrusive::segmented_queue::make_traits< + cds::intrusive::opt::disposer< Disposer > + ,cds::opt::item_counter< cds::atomicity::item_counter > + ,cds::opt::permutation_generator< cds::opt::v::random_shuffle_permutation<> > + >::type + > queue_type; + + std::vector arr; + { + queue_type q( c_QuasiFactor ); + test( q, arr ); + } + queue_type::gc::force_dispose(); + check_array( arr ); + } + + TEST_F( IntrusiveSegmentedQueue_DHP, padding ) + { + struct queue_traits : public cds::intrusive::segmented_queue::traits + { + typedef Disposer disposer; + enum { padding = cds::opt::cache_line_padding }; + typedef ci::segmented_queue::stat<> stat; + }; + typedef cds::intrusive::SegmentedQueue< gc_type, item, queue_traits > queue_type; + + std::vector arr; + { + queue_type q( c_QuasiFactor ); + test( q, arr ); + } + queue_type::gc::force_dispose(); + check_array( arr ); + } + + TEST_F( IntrusiveSegmentedQueue_DHP, bigdata_padding ) + { + struct queue_traits : public cds::intrusive::segmented_queue::traits + { + typedef Disposer disposer; + enum { padding = cds::opt::cache_line_padding | cds::opt::padding_tiny_data_only }; + typedef cds::opt::v::sequential_consistent memory_model; + }; + typedef cds::intrusive::SegmentedQueue< gc_type, big_item, queue_traits > queue_type; + + std::vector arr; + { + queue_type q( c_QuasiFactor ); + test( q, arr ); + } + queue_type::gc::force_dispose(); + check_array( arr ); + } + +} // namespace + diff --git a/test/unit/queue/intrusive_segmented_queue_hp.cpp b/test/unit/queue/intrusive_segmented_queue_hp.cpp new file mode 100644 index 00000000..12c951dd --- /dev/null +++ b/test/unit/queue/intrusive_segmented_queue_hp.cpp @@ -0,0 +1,166 @@ +/* + This file is a part of libcds - Concurrent Data Structures library + + (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016 + + Source code repo: http://github.com/khizmax/libcds/ + Download: http://sourceforge.net/projects/libcds/files/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "test_intrusive_segmented_queue.h" + +#include +#include +#include + +namespace { + namespace ci = cds::intrusive; + typedef cds::gc::HP gc_type; + + class IntrusiveSegmentedQueue_HP : public cds_test::intrusive_segmented_queue + { + typedef cds_test::intrusive_segmented_queue base_class; + + protected: + static const size_t c_QuasiFactor = 15; + + void SetUp() + { + typedef ci::SegmentedQueue< gc_type, item > queue_type; + + cds::gc::hp::GarbageCollector::Construct( queue_type::c_nHazardPtrCount, 1, 16 ); + cds::threading::Manager::attachThread(); + } + + void TearDown() + { + cds::threading::Manager::detachThread(); + cds::gc::hp::GarbageCollector::Destruct( true ); + } + + template + void check_array( V& arr ) + { + for ( size_t i = 0; i < arr.size(); ++i ) { + EXPECT_EQ( arr[i].nDisposeCount, 2 ); + EXPECT_EQ( arr[i].nDispose2Count, 1 ); + } + } + }; + + TEST_F( IntrusiveSegmentedQueue_HP, defaulted ) + { + struct queue_traits : public cds::intrusive::segmented_queue::traits + { + typedef Disposer disposer; + }; + typedef cds::intrusive::SegmentedQueue< gc_type, item, queue_traits > queue_type; + + std::vector arr; + { + queue_type q( c_QuasiFactor ); + test( q, arr ); + } + queue_type::gc::force_dispose(); + check_array( arr ); + } + + TEST_F( IntrusiveSegmentedQueue_HP, mutex ) + { + struct queue_traits : public + cds::intrusive::segmented_queue::make_traits < + cds::intrusive::opt::disposer< Disposer > + ,cds::opt::lock_type < std::mutex > + > ::type + {}; + typedef cds::intrusive::SegmentedQueue< gc_type, item, queue_traits > queue_type; + + std::vector arr; + { + queue_type q( c_QuasiFactor ); + test( q, arr ); + } + queue_type::gc::force_dispose(); + check_array( arr ); + } + + TEST_F( IntrusiveSegmentedQueue_HP, shuffle ) + { + typedef cds::intrusive::SegmentedQueue< gc_type, item, + cds::intrusive::segmented_queue::make_traits< + cds::intrusive::opt::disposer< Disposer > + ,cds::opt::item_counter< cds::atomicity::item_counter > + ,cds::opt::permutation_generator< cds::opt::v::random_shuffle_permutation<> > + >::type + > queue_type; + + std::vector arr; + { + queue_type q( c_QuasiFactor ); + test( q, arr ); + } + queue_type::gc::force_dispose(); + check_array( arr ); + } + + TEST_F( IntrusiveSegmentedQueue_HP, padding ) + { + struct queue_traits : public cds::intrusive::segmented_queue::traits + { + typedef Disposer disposer; + enum { padding = cds::opt::cache_line_padding }; + typedef ci::segmented_queue::stat<> stat; + }; + typedef cds::intrusive::SegmentedQueue< gc_type, item, queue_traits > queue_type; + + std::vector arr; + { + queue_type q( c_QuasiFactor ); + test( q, arr ); + } + queue_type::gc::force_dispose(); + check_array( arr ); + } + + TEST_F( IntrusiveSegmentedQueue_HP, bigdata_padding ) + { + struct queue_traits : public cds::intrusive::segmented_queue::traits + { + typedef Disposer disposer; + enum { padding = cds::opt::cache_line_padding | cds::opt::padding_tiny_data_only }; + typedef cds::opt::v::sequential_consistent memory_model; + }; + typedef cds::intrusive::SegmentedQueue< gc_type, big_item, queue_traits > queue_type; + + std::vector arr; + { + queue_type q( c_QuasiFactor ); + test( q, arr ); + } + queue_type::gc::force_dispose(); + check_array( arr ); + } + +} // namespace + diff --git a/test/unit/queue/test_intrusive_msqueue.h b/test/unit/queue/test_intrusive_msqueue.h new file mode 100644 index 00000000..677a6143 --- /dev/null +++ b/test/unit/queue/test_intrusive_msqueue.h @@ -0,0 +1,159 @@ +/* + This file is a part of libcds - Concurrent Data Structures library + + (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016 + + Source code repo: http://github.com/khizmax/libcds/ + Download: http://sourceforge.net/projects/libcds/files/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef CDSUNIT_QUEUE_TEST_INTRUSIVE_MSQUEUE_H +#define CDSUNIT_QUEUE_TEST_INTRUSIVE_MSQUEUE_H + +#include + +namespace cds_test { + + class intrusive_msqueue : public ::testing::Test + { + protected: + template + struct base_hook_item : public Base + { + int nVal; + int nDisposeCount; + + base_hook_item() + : nDisposeCount( 0 ) + {} + + base_hook_item( base_hook_item const& s) + : nVal( s.nVal ) + , nDisposeCount( s.nDisposeCount ) + {} + }; + + template + struct member_hook_item + { + int nVal; + int nDisposeCount; + Member hMember; + + member_hook_item() + : nDisposeCount( 0 ) + {} + + member_hook_item( member_hook_item const& s ) + : nVal( s.nVal ) + , nDisposeCount( s.nDisposeCount ) + {} + }; + + struct mock_disposer + { + template + void operator ()( T * p ) + { + ++p->nDisposeCount; + } + }; + + template + void test( Queue& q, Data& arr ) + { + typedef typename Queue::value_type value_type; + size_t nSize = arr.size(); + + value_type * pv; + for ( size_t i = 0; i < nSize; ++i ) + arr[i].nVal = static_cast(i); + + ASSERT_TRUE( q.empty() ); + ASSERT_CONTAINER_SIZE( q, 0 ); + + // pop from empty queue + pv = q.pop(); + ASSERT_TRUE( pv == nullptr ); + ASSERT_TRUE( q.empty() ); + ASSERT_CONTAINER_SIZE( q, 0 ); + + pv =q.dequeue(); + ASSERT_TRUE( pv == nullptr ); + ASSERT_TRUE( q.empty() ); + ASSERT_CONTAINER_SIZE( q, 0 ); + + // push/pop test + for ( size_t i = 0; i < nSize; ++i ) { + if ( i & 1 ) + q.push( arr[i] ); + else + q.enqueue( arr[i] ); + ASSERT_FALSE( q.empty()); + ASSERT_CONTAINER_SIZE( q, i + 1 ); + } + + for ( size_t i = 0; i < nSize; ++i ) { + ASSERT_FALSE( q.empty() ); + ASSERT_CONTAINER_SIZE( q, nSize - i ); + if ( i & 1 ) + pv = q.pop(); + else + pv = q.dequeue(); + ASSERT_FALSE( pv == nullptr ); + ASSERT_EQ( pv->nVal, static_cast(i)); + } + ASSERT_TRUE( q.empty() ); + ASSERT_CONTAINER_SIZE( q, 0 ); + + Queue::gc::scan(); + --nSize; // last element of array is in queue yet as a dummy item + for ( size_t i = 0; i < nSize; ++i ) { + ASSERT_EQ( arr[i].nDisposeCount, 1 ); + } + ASSERT_EQ( arr[nSize].nDisposeCount, 0 ); + + // clear test + for ( size_t i = 0; i < nSize; ++i ) + q.push( arr[i] ); + + ASSERT_FALSE( q.empty() ); + ASSERT_CONTAINER_SIZE( q, nSize ); + + q.clear(); + ASSERT_TRUE( q.empty() ); + ASSERT_CONTAINER_SIZE( q, 0 ); + + Queue::gc::scan(); + for ( size_t i = 0; i < nSize - 1; ++i ) { + ASSERT_EQ( arr[i].nDisposeCount, 2 ) << "i=" << i; + } + ASSERT_EQ( arr[nSize - 1].nDisposeCount, 1 ); // this element is in the queue yet + ASSERT_EQ( arr[nSize].nDisposeCount, 1 ); + } + }; + +} // namespace cds_test + +#endif // CDSUNIT_QUEUE_TEST_INTRUSIVE_MSQUEUE_H diff --git a/test/unit/queue/test_intrusive_segmented_queue.h b/test/unit/queue/test_intrusive_segmented_queue.h new file mode 100644 index 00000000..59fbcfa1 --- /dev/null +++ b/test/unit/queue/test_intrusive_segmented_queue.h @@ -0,0 +1,191 @@ +/* + This file is a part of libcds - Concurrent Data Structures library + + (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016 + + Source code repo: http://github.com/khizmax/libcds/ + Download: http://sourceforge.net/projects/libcds/files/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef CDSUNIT_QUEUE_TEST_INTRUSIVE_SEGMENTED_QUEUE_H +#define CDSUNIT_QUEUE_TEST_INTRUSIVE_SEGMENTED_QUEUE_H + +#include + +namespace cds_test { + + class intrusive_segmented_queue : public ::testing::Test + { + protected: + struct item { + int nValue; + + size_t nDisposeCount; + size_t nDispose2Count; + + item() + : nValue( 0 ) + , nDisposeCount( 0 ) + , nDispose2Count( 0 ) + {} + + item( int nVal ) + : nValue( nVal ) + , nDisposeCount( 0 ) + , nDispose2Count( 0 ) + {} + }; + + struct big_item : public item + { + big_item() + {} + + big_item( int nVal ) + : item( nVal ) + {} + + int arr[80]; + }; + + struct Disposer + { + void operator()( item * p ) + { + ++p->nDisposeCount; + } + }; + + struct Disposer2 + { + void operator()( item * p ) + { + ++p->nDispose2Count; + } + }; + + template + void test( Queue& q, Data& val ) + { + typedef typename Queue::value_type value_type; + val.resize( 100 ); + for ( int i = 0; i < val.size(); ++i ) + val[i].nValue = i; + + ASSERT_TRUE( q.empty()); + ASSERT_CONTAINER_SIZE( q, 0 ); + + // push/enqueue + for ( size_t i = 0; i < val.size(); ++i ) { + if ( i & 1 ) { + ASSERT_TRUE( q.push( val[i] ) ); + } + else { + ASSERT_TRUE( q.enqueue( val[i] ) ); + } + + ASSERT_CONTAINER_SIZE( q, i + 1 ); + } + EXPECT_TRUE( !q.empty() ); + + // pop/dequeue + size_t nCount = 0; + while ( !q.empty() ) { + value_type * pVal; + if ( nCount & 1 ) + pVal = q.pop(); + else + pVal = q.dequeue(); + + ASSERT_TRUE( pVal != nullptr ); + + int nSegment = int( nCount / q.quasi_factor() ); + int nMin = nSegment * int( q.quasi_factor() ); + int nMax = nMin + int( q.quasi_factor() ) - 1; + EXPECT_TRUE( nMin <= pVal->nValue && pVal->nValue <= nMax ) << nMin << " <= " << pVal->nValue << " <= " << nMax; + + ++nCount; + EXPECT_CONTAINER_SIZE( q, val.size() - nCount ); + } + EXPECT_EQ( nCount, val.size()); + EXPECT_TRUE( q.empty() ); + EXPECT_CONTAINER_SIZE( q, 0 ); + + // pop from empty queue + ASSERT_TRUE( q.pop() == nullptr ); + EXPECT_TRUE( q.empty() ); + EXPECT_CONTAINER_SIZE( q, 0 ); + + // check that Disposer has not been called + Queue::gc::force_dispose(); + for ( int i = 0; i < val.size(); ++i ) { + EXPECT_EQ( val[i].nDisposeCount, 0 ); + EXPECT_EQ( val[i].nDispose2Count, 0 ); + } + + // clear + for ( int i = 0; i < val.size(); ++i ) + EXPECT_TRUE( q.push( val[i] ) ); + EXPECT_CONTAINER_SIZE( q, val.size()); + EXPECT_TRUE( !q.empty() ); + + q.clear(); + EXPECT_CONTAINER_SIZE( q, 0 ); + EXPECT_TRUE( q.empty() ); + + // check if Disposer has been called + Queue::gc::force_dispose(); + for ( size_t i = 0; i < val.size(); ++i ) { + EXPECT_EQ( val[i].nDisposeCount, 1 ); + EXPECT_EQ( val[i].nDispose2Count, 0 ); + } + + // clear_with + for ( size_t i = 0; i < val.size(); ++i ) + EXPECT_TRUE( q.push( val[i] ) ); + EXPECT_CONTAINER_SIZE( q, val.size() ); + EXPECT_TRUE( !q.empty() ); + + q.clear_with( Disposer2() ); + EXPECT_CONTAINER_SIZE( q, 0 ); + EXPECT_TRUE( q.empty() ); + + // check if Disposer has been called + Queue::gc::force_dispose(); + for ( size_t i = 0; i < val.size(); ++i ) { + EXPECT_EQ( val[i].nDisposeCount, 1 ); + EXPECT_EQ( val[i].nDispose2Count, 1 ); + } + + // check clear on destruct + for ( size_t i = 0; i < val.size(); ++i ) + EXPECT_TRUE( q.push( val[i] )); + EXPECT_CONTAINER_SIZE( q, val.size()); + EXPECT_TRUE( !q.empty()); + } + }; + +} // namespace cds_test + +#endif // CDSUNIT_QUEUE_TEST_INTRUSIVE_SEGMENTED_QUEUE_H -- 2.34.1