mirror of
https://github.com/boostorg/lockfree.git
synced 2026-01-19 16:32:09 +00:00
238 lines
6.2 KiB
C++
238 lines
6.2 KiB
C++
// 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 <boost/lockfree/detail/freelist.hpp>
|
|
#include <boost/lockfree/queue.hpp>
|
|
|
|
#include <boost/thread/thread.hpp>
|
|
|
|
#define BOOST_TEST_MAIN
|
|
#ifdef BOOST_LOCKFREE_INCLUDE_TESTS
|
|
# include <boost/test/included/unit_test.hpp>
|
|
#else
|
|
# include <boost/test/unit_test.hpp>
|
|
#endif
|
|
|
|
#include <set>
|
|
|
|
#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 >();
|
|
}
|