// 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 #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 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 void run_test(void) { freelist_type fl(std::allocator(), 8); std::set nodes; dummy d; if (bounded) test_running.store(true); for (int i = 0; i != 4; ++i) { dummy * allocated = fl.template construct(); BOOST_REQUIRE(nodes.find(allocated) == nodes.end()); nodes.insert(allocated); } BOOST_FOREACH(dummy * d, nodes) fl.template destruct(d); nodes.clear(); for (int i = 0; i != 4; ++i) nodes.insert(fl.template construct()); BOOST_FOREACH(dummy * d, nodes) fl.template destruct(d); for (int i = 0; i != 4; ++i) nodes.insert(fl.template construct()); if (bounded) test_running.store(false); } template void run_tests(void) { run_test, true, bounded>(); run_test, false, bounded>(); run_test, true, bounded>(); } BOOST_AUTO_TEST_CASE( freelist_tests ) { run_tests(); run_tests(); } template void oom_test(void) { const bool bounded = true; freelist_type fl(std::allocator(), 8); for (int i = 0; i != 8; ++i) fl.template construct(); dummy * allocated = fl.template construct(); BOOST_REQUIRE(allocated == NULL); } BOOST_AUTO_TEST_CASE( oom_tests ) { oom_test, true >(); oom_test, false >(); oom_test, true >(); oom_test, false >(); } template 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 allocated_nodes; atomic running; static_hashed_set working_set; freelist_tester(void): fl(std::allocator(), 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(boost::bind(&freelist_tester::deallocate, this)); for (int i = 0; i != thread_count; ++i) alloc_threads.create_thread(boost::bind(&freelist_tester::allocate, this)); 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(); if (node) { bool success = working_set.insert(node); assert(success); allocated_nodes.push(node); break; } } } } void deallocate(void) { for (;;) { dummy * node; if (allocated_nodes.pop(node)) { bool success = working_set.erase(node); assert(success); fl.template destruct(node); } if (running.load() == false) break; #ifdef __VXWORKS__ boost::thread::yield(); #endif } dummy * node; while (allocated_nodes.pop(node)) { bool success = working_set.erase(node); assert(success); fl.template destruct(node); } } }; template void run_tester() { boost::scoped_ptr tester (new Tester); tester->run(); } BOOST_AUTO_TEST_CASE( unbounded_freelist_test ) { typedef freelist_tester, false > test_type; run_tester(); } BOOST_AUTO_TEST_CASE( bounded_freelist_test ) { typedef freelist_tester, true > test_type; run_tester(); } BOOST_AUTO_TEST_CASE( fixed_size_freelist_test ) { typedef freelist_tester, true > test_type; run_tester(); }