// Copyright (C) 2011 Tim Blechmann // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // enables error checks via dummy::~dtor #define BOOST_LOCKFREE_FREELIST_INIT_RUNS_DTOR #include #include #include #define BOOST_TEST_MAIN #ifdef BOOST_LOCKFREE_INCLUDE_TESTS # include #else # include #endif #include #include "test_helpers.hpp" using boost::lockfree::detail::atomic; atomic< bool > test_running( false ); struct dummy { dummy( void ) { if ( test_running.load( boost::lockfree::detail::memory_order_relaxed ) ) assert( allocated == 0 ); allocated = 1; } ~dummy( void ) { if ( test_running.load( boost::lockfree::detail::memory_order_relaxed ) ) assert( allocated == 1 ); allocated = 0; } size_t padding[ 2 ]; // for used for the freelist node int allocated; }; template < typename freelist_type, bool threadsafe, bool bounded > void run_test( void ) { freelist_type fl( std::allocator< int >(), 8 ); std::set< dummy* > nodes; dummy d; if ( bounded ) test_running.store( true ); for ( int i = 0; i != 4; ++i ) { dummy* allocated = fl.template construct< threadsafe, bounded >(); BOOST_TEST_REQUIRE( ( nodes.find( allocated ) == nodes.end() ) ); nodes.insert( allocated ); } for ( dummy* d : nodes ) fl.template destruct< threadsafe >( d ); nodes.clear(); for ( int i = 0; i != 4; ++i ) nodes.insert( fl.template construct< threadsafe, bounded >() ); for ( dummy* d : nodes ) fl.template destruct< threadsafe >( d ); for ( int i = 0; i != 4; ++i ) nodes.insert( fl.template construct< threadsafe, bounded >() ); if ( bounded ) test_running.store( false ); } template < bool bounded > void run_tests( void ) { run_test< boost::lockfree::detail::freelist_stack< dummy >, true, bounded >(); run_test< boost::lockfree::detail::freelist_stack< dummy >, false, bounded >(); run_test< boost::lockfree::detail::fixed_size_freelist< dummy >, true, bounded >(); } BOOST_AUTO_TEST_CASE( freelist_tests ) { run_tests< false >(); run_tests< true >(); } template < typename freelist_type, bool threadsafe > void oom_test( void ) { const bool bounded = true; freelist_type fl( std::allocator< int >(), 8 ); for ( int i = 0; i != 8; ++i ) fl.template construct< threadsafe, bounded >(); dummy* allocated = fl.template construct< threadsafe, bounded >(); BOOST_TEST_REQUIRE( allocated == (dummy*)NULL ); } BOOST_AUTO_TEST_CASE( oom_tests ) { oom_test< boost::lockfree::detail::freelist_stack< dummy >, true >(); oom_test< boost::lockfree::detail::freelist_stack< dummy >, false >(); oom_test< boost::lockfree::detail::fixed_size_freelist< dummy >, true >(); oom_test< boost::lockfree::detail::fixed_size_freelist< dummy >, false >(); } template < typename freelist_type, bool bounded > struct freelist_tester { static const int size = 128; static const int thread_count = 4; #ifndef BOOST_LOCKFREE_STRESS_TEST static const int operations_per_thread = 1000; #else static const int operations_per_thread = 100000; #endif freelist_type fl; boost::lockfree::queue< dummy* > allocated_nodes; atomic< bool > running; static_hashed_set< dummy*, 1 << 16 > working_set; freelist_tester( void ) : fl( std::allocator< int >(), size ), allocated_nodes( 256 ) {} void run() { running = true; if ( bounded ) test_running.store( true ); boost::thread_group alloc_threads; boost::thread_group dealloc_threads; for ( int i = 0; i != thread_count; ++i ) dealloc_threads.create_thread( [ this ] { deallocate(); } ); for ( int i = 0; i != thread_count; ++i ) alloc_threads.create_thread( [ this ] { allocate(); } ); alloc_threads.join_all(); test_running.store( false ); running = false; dealloc_threads.join_all(); } void allocate( void ) { for ( long i = 0; i != operations_per_thread; ++i ) { for ( ;; ) { dummy* node = fl.template construct< true, bounded >(); if ( node ) { bool success = working_set.insert( node ); (void)success; assert( success ); allocated_nodes.push( node ); break; } } } } void deallocate( void ) { for ( ;; ) { dummy* node; if ( allocated_nodes.pop( node ) ) { bool success = working_set.erase( node ); (void)success; assert( success ); fl.template destruct< true >( node ); } if ( running.load() == false ) break; #ifdef __VXWORKS__ std::this_thread::yield(); #endif } dummy* node; while ( allocated_nodes.pop( node ) ) { bool success = working_set.erase( node ); (void)success; assert( success ); fl.template destruct< true >( node ); } } }; template < typename Tester > void run_tester() { std::unique_ptr< Tester > tester( new Tester ); tester->run(); } BOOST_AUTO_TEST_CASE( unbounded_freelist_test ) { typedef freelist_tester< boost::lockfree::detail::freelist_stack< dummy >, false > test_type; run_tester< test_type >(); } BOOST_AUTO_TEST_CASE( bounded_freelist_test ) { typedef freelist_tester< boost::lockfree::detail::freelist_stack< dummy >, true > test_type; run_tester< test_type >(); } BOOST_AUTO_TEST_CASE( fixed_size_freelist_test ) { typedef freelist_tester< boost::lockfree::detail::fixed_size_freelist< dummy >, true > test_type; run_tester< test_type >(); }