From 483eb2f56657e8e7f419ab1a4fab8dce9ade8609 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 27 Apr 2024 20:24:20 +0200 Subject: Adding upstream version 14.2.21. Signed-off-by: Daniel Baumann --- src/boost/libs/lockfree/test/Jamfile.v2 | 44 +++ src/boost/libs/lockfree/test/freelist_test.cpp | 233 ++++++++++++ .../lockfree/test/queue_bounded_stress_test.cpp | 27 ++ .../lockfree/test/queue_fixedsize_stress_test.cpp | 28 ++ .../libs/lockfree/test/queue_interprocess_test.cpp | 57 +++ src/boost/libs/lockfree/test/queue_test.cpp | 194 ++++++++++ .../lockfree/test/queue_unbounded_stress_test.cpp | 27 ++ .../libs/lockfree/test/spsc_queue_stress_test.cpp | 222 +++++++++++ src/boost/libs/lockfree/test/spsc_queue_test.cpp | 407 +++++++++++++++++++++ .../lockfree/test/stack_bounded_stress_test.cpp | 27 ++ .../lockfree/test/stack_fixedsize_stress_test.cpp | 28 ++ .../libs/lockfree/test/stack_interprocess_test.cpp | 57 +++ src/boost/libs/lockfree/test/stack_test.cpp | 219 +++++++++++ .../lockfree/test/stack_unbounded_stress_test.cpp | 28 ++ src/boost/libs/lockfree/test/tagged_ptr_test.cpp | 58 +++ src/boost/libs/lockfree/test/test_common.hpp | 145 ++++++++ src/boost/libs/lockfree/test/test_helpers.hpp | 110 ++++++ 17 files changed, 1911 insertions(+) create mode 100644 src/boost/libs/lockfree/test/Jamfile.v2 create mode 100644 src/boost/libs/lockfree/test/freelist_test.cpp create mode 100644 src/boost/libs/lockfree/test/queue_bounded_stress_test.cpp create mode 100644 src/boost/libs/lockfree/test/queue_fixedsize_stress_test.cpp create mode 100644 src/boost/libs/lockfree/test/queue_interprocess_test.cpp create mode 100644 src/boost/libs/lockfree/test/queue_test.cpp create mode 100644 src/boost/libs/lockfree/test/queue_unbounded_stress_test.cpp create mode 100644 src/boost/libs/lockfree/test/spsc_queue_stress_test.cpp create mode 100644 src/boost/libs/lockfree/test/spsc_queue_test.cpp create mode 100644 src/boost/libs/lockfree/test/stack_bounded_stress_test.cpp create mode 100644 src/boost/libs/lockfree/test/stack_fixedsize_stress_test.cpp create mode 100644 src/boost/libs/lockfree/test/stack_interprocess_test.cpp create mode 100644 src/boost/libs/lockfree/test/stack_test.cpp create mode 100644 src/boost/libs/lockfree/test/stack_unbounded_stress_test.cpp create mode 100644 src/boost/libs/lockfree/test/tagged_ptr_test.cpp create mode 100644 src/boost/libs/lockfree/test/test_common.hpp create mode 100644 src/boost/libs/lockfree/test/test_helpers.hpp (limited to 'src/boost/libs/lockfree/test') diff --git a/src/boost/libs/lockfree/test/Jamfile.v2 b/src/boost/libs/lockfree/test/Jamfile.v2 new file mode 100644 index 00000000..8ce4189c --- /dev/null +++ b/src/boost/libs/lockfree/test/Jamfile.v2 @@ -0,0 +1,44 @@ +# (C) Copyright 2010: 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) + +import testing ; + +lib boost_chrono ; +lib boost_interprocess ; +lib boost_system ; +lib boost_thread ; +lib boost_unit_test_framework ; + +project + : source-location . + : requirements + ../../test/build//boost_unit_test_framework + ../../atomic/build//boost_atomic + ; + + +rule test_all +{ + local all_rules = ; + + for local fileb in [ glob *.cpp ] + { + all_rules += [ run $(fileb) + : # additional args + : # test-files + : # requirements + acc:-lrt + acc-pa_risc:-lrt + windows,gcc:"-lole32 -loleaut32 -lpsapi -ladvapi32" + hpux,gcc:"-Wl,+as,mpas" + ../../thread/build//boost_thread/ + multi + static + ] ; + } + + return $(all_rules) ; +} + +test-suite lockfree : [ test_all r ] : multi ; diff --git a/src/boost/libs/lockfree/test/freelist_test.cpp b/src/boost/libs/lockfree/test/freelist_test.cpp new file mode 100644 index 00000000..4eb9c5c4 --- /dev/null +++ b/src/boost/libs/lockfree/test/freelist_test.cpp @@ -0,0 +1,233 @@ +// 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(); +} diff --git a/src/boost/libs/lockfree/test/queue_bounded_stress_test.cpp b/src/boost/libs/lockfree/test/queue_bounded_stress_test.cpp new file mode 100644 index 00000000..aa882ce1 --- /dev/null +++ b/src/boost/libs/lockfree/test/queue_bounded_stress_test.cpp @@ -0,0 +1,27 @@ +// 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) + +#include + +#include + +#define BOOST_TEST_MAIN +#ifdef BOOST_LOCKFREE_INCLUDE_TESTS +#include +#else +#include +#endif + +#include "test_common.hpp" + +BOOST_AUTO_TEST_CASE( queue_test_bounded ) +{ + typedef queue_stress_tester tester_type; + boost::scoped_ptr tester(new tester_type(4, 4) ); + + boost::lockfree::queue q(128); + tester->run(q); +} diff --git a/src/boost/libs/lockfree/test/queue_fixedsize_stress_test.cpp b/src/boost/libs/lockfree/test/queue_fixedsize_stress_test.cpp new file mode 100644 index 00000000..8ae46f27 --- /dev/null +++ b/src/boost/libs/lockfree/test/queue_fixedsize_stress_test.cpp @@ -0,0 +1,28 @@ +// 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) + +#include + +#include + +#define BOOST_TEST_MAIN +#ifdef BOOST_LOCKFREE_INCLUDE_TESTS +#include +#else +#include +#endif + +#include "test_common.hpp" + + +BOOST_AUTO_TEST_CASE( queue_test_fixed_size ) +{ + typedef queue_stress_tester<> tester_type; + boost::scoped_ptr tester(new tester_type(4, 4) ); + + boost::lockfree::queue > q; + tester->run(q); +} diff --git a/src/boost/libs/lockfree/test/queue_interprocess_test.cpp b/src/boost/libs/lockfree/test/queue_interprocess_test.cpp new file mode 100644 index 00000000..78c0ce9f --- /dev/null +++ b/src/boost/libs/lockfree/test/queue_interprocess_test.cpp @@ -0,0 +1,57 @@ +// 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) + +#include //std::system +#include + +#include +#include +#include + +using namespace boost::interprocess; +typedef allocator ShmemAllocator; +typedef boost::lockfree::queue, + boost::lockfree::capacity<2048> + > queue; + +int main (int argc, char *argv[]) +{ + if(argc == 1){ + struct shm_remove + { + shm_remove() { shared_memory_object::remove("boost_queue_interprocess_test_shm"); } + ~shm_remove(){ shared_memory_object::remove("boost_queue_interprocess_test_shm"); } + } remover; + + managed_shared_memory segment(create_only, "boost_queue_interprocess_test_shm", 262144); + ShmemAllocator alloc_inst (segment.get_segment_manager()); + + queue * q = segment.construct("queue")(alloc_inst); + for (int i = 0; i != 1024; ++i) + q->push(i); + + std::string s(argv[0]); s += " child "; + if(0 != std::system(s.c_str())) + return 1; + + while (!q->empty()) + boost::thread::yield(); + return 0; + } else { + managed_shared_memory segment(open_only, "boost_queue_interprocess_test_shm"); + queue * q = segment.find("queue").first; + + int from_queue; + for (int i = 0; i != 1024; ++i) { + bool success = q->pop(from_queue); + assert (success); + assert (from_queue == i); + } + segment.destroy("queue"); + } + return 0; +} diff --git a/src/boost/libs/lockfree/test/queue_test.cpp b/src/boost/libs/lockfree/test/queue_test.cpp new file mode 100644 index 00000000..79f6f0ed --- /dev/null +++ b/src/boost/libs/lockfree/test/queue_test.cpp @@ -0,0 +1,194 @@ +// 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) + +#include + +#include +#include + +#define BOOST_TEST_MAIN +#ifdef BOOST_LOCKFREE_INCLUDE_TESTS +#include +#else +#include +#endif + +#include + +#include "test_helpers.hpp" + +using namespace boost; +using namespace boost::lockfree; +using namespace std; + +BOOST_AUTO_TEST_CASE( simple_queue_test ) +{ + queue f(64); + + BOOST_WARN(f.is_lock_free()); + + BOOST_REQUIRE(f.empty()); + f.push(1); + f.push(2); + + int i1(0), i2(0); + + BOOST_REQUIRE(f.pop(i1)); + BOOST_REQUIRE_EQUAL(i1, 1); + + BOOST_REQUIRE(f.pop(i2)); + BOOST_REQUIRE_EQUAL(i2, 2); + BOOST_REQUIRE(f.empty()); +} + +BOOST_AUTO_TEST_CASE( simple_queue_test_capacity ) +{ + queue > f; + + BOOST_WARN(f.is_lock_free()); + + BOOST_REQUIRE(f.empty()); + f.push(1); + f.push(2); + + int i1(0), i2(0); + + BOOST_REQUIRE(f.pop(i1)); + BOOST_REQUIRE_EQUAL(i1, 1); + + BOOST_REQUIRE(f.pop(i2)); + BOOST_REQUIRE_EQUAL(i2, 2); + BOOST_REQUIRE(f.empty()); +} + + +BOOST_AUTO_TEST_CASE( unsafe_queue_test ) +{ + queue f(64); + + BOOST_WARN(f.is_lock_free()); + BOOST_REQUIRE(f.empty()); + + int i1(0), i2(0); + + f.unsynchronized_push(1); + f.unsynchronized_push(2); + + BOOST_REQUIRE(f.unsynchronized_pop(i1)); + BOOST_REQUIRE_EQUAL(i1, 1); + + BOOST_REQUIRE(f.unsynchronized_pop(i2)); + BOOST_REQUIRE_EQUAL(i2, 2); + BOOST_REQUIRE(f.empty()); +} + + +BOOST_AUTO_TEST_CASE( queue_consume_one_test ) +{ + queue f(64); + + BOOST_WARN(f.is_lock_free()); + BOOST_REQUIRE(f.empty()); + + f.push(1); + f.push(2); + +#ifdef BOOST_NO_CXX11_LAMBDAS + bool success1 = f.consume_one(test_equal(1)); + bool success2 = f.consume_one(test_equal(2)); +#else + bool success1 = f.consume_one([] (int i) { + BOOST_REQUIRE_EQUAL(i, 1); + }); + + bool success2 = f.consume_one([] (int i) { + BOOST_REQUIRE_EQUAL(i, 2); + }); +#endif + + BOOST_REQUIRE(success1); + BOOST_REQUIRE(success2); + + BOOST_REQUIRE(f.empty()); +} + +BOOST_AUTO_TEST_CASE( queue_consume_all_test ) +{ + queue f(64); + + BOOST_WARN(f.is_lock_free()); + BOOST_REQUIRE(f.empty()); + + f.push(1); + f.push(2); + +#ifdef BOOST_NO_CXX11_LAMBDAS + size_t consumed = f.consume_all(dummy_functor()); +#else + size_t consumed = f.consume_all([] (int i) { + }); +#endif + + BOOST_REQUIRE_EQUAL(consumed, 2u); + + BOOST_REQUIRE(f.empty()); +} + + +BOOST_AUTO_TEST_CASE( queue_convert_pop_test ) +{ + queue f(128); + BOOST_REQUIRE(f.empty()); + f.push(new int(1)); + f.push(new int(2)); + f.push(new int(3)); + f.push(new int(4)); + + { + int * i1; + + BOOST_REQUIRE(f.pop(i1)); + BOOST_REQUIRE_EQUAL(*i1, 1); + delete i1; + } + + + { + boost::shared_ptr i2; + BOOST_REQUIRE(f.pop(i2)); + BOOST_REQUIRE_EQUAL(*i2, 2); + } + + { +#ifdef BOOST_NO_AUTO_PTR + unique_ptr i3; +#else + auto_ptr i3; +#endif + BOOST_REQUIRE(f.pop(i3)); + + BOOST_REQUIRE_EQUAL(*i3, 3); + } + + { + boost::shared_ptr i4; + BOOST_REQUIRE(f.pop(i4)); + + BOOST_REQUIRE_EQUAL(*i4, 4); + } + + + BOOST_REQUIRE(f.empty()); +} + +BOOST_AUTO_TEST_CASE( reserve_test ) +{ + typedef boost::lockfree::queue< void* > memory_queue; + + memory_queue ms(1); + ms.reserve(1); + ms.reserve_unsafe(1); +} diff --git a/src/boost/libs/lockfree/test/queue_unbounded_stress_test.cpp b/src/boost/libs/lockfree/test/queue_unbounded_stress_test.cpp new file mode 100644 index 00000000..10b70e2b --- /dev/null +++ b/src/boost/libs/lockfree/test/queue_unbounded_stress_test.cpp @@ -0,0 +1,27 @@ +// 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) + +#include + +#include + +#define BOOST_TEST_MAIN +#ifdef BOOST_LOCKFREE_INCLUDE_TESTS +#include +#else +#include +#endif + +#include "test_common.hpp" + +BOOST_AUTO_TEST_CASE( queue_test_unbounded ) +{ + typedef queue_stress_tester tester_type; + boost::scoped_ptr tester(new tester_type(4, 4) ); + + boost::lockfree::queue q(128); + tester->run(q); +} diff --git a/src/boost/libs/lockfree/test/spsc_queue_stress_test.cpp b/src/boost/libs/lockfree/test/spsc_queue_stress_test.cpp new file mode 100644 index 00000000..a63afd0e --- /dev/null +++ b/src/boost/libs/lockfree/test/spsc_queue_stress_test.cpp @@ -0,0 +1,222 @@ +// Copyright (C) 2011-2013 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) + +#include +#include + +#define BOOST_TEST_MAIN +#ifdef BOOST_LOCKFREE_INCLUDE_TESTS +#include +#else +#include +#endif + +#include +#include + +#include "test_helpers.hpp" +#include "test_common.hpp" + +using namespace boost; +using namespace boost::lockfree; +using namespace std; + +#ifndef BOOST_LOCKFREE_STRESS_TEST +static const boost::uint32_t nodes_per_thread = 100000; +#else +static const boost::uint32_t nodes_per_thread = 100000000; +#endif + +struct spsc_queue_tester +{ + spsc_queue > sf; + + boost::lockfree::detail::atomic spsc_queue_cnt, received_nodes; + +// In VxWorks one RTP just supports 65535 objects +#ifndef __VXWORKS__ + static_hashed_set working_set; +#else + static_hashed_set working_set; +#endif + + spsc_queue_tester(void): + spsc_queue_cnt(0), received_nodes(0) + {} + + void add(void) + { + for (boost::uint32_t i = 0; i != nodes_per_thread; ++i) { + int id = generate_id(); + working_set.insert(id); + + while (sf.push(id) == false) + {} + + ++spsc_queue_cnt; + } + running = false; + } + + bool get_element(void) + { + int data; + bool success = sf.pop(data); + + if (success) { + ++received_nodes; + --spsc_queue_cnt; + bool erased = working_set.erase(data); + assert(erased); + return true; + } else + return false; + } + + boost::lockfree::detail::atomic running; + + void get(void) + { + for(;;) { + bool success = get_element(); + if (!running && !success) + break; + } + + while ( get_element() ); + } + + void run(void) + { + running = true; + + BOOST_REQUIRE(sf.empty()); + + boost::thread reader(boost::bind(&spsc_queue_tester::get, this)); + boost::thread writer(boost::bind(&spsc_queue_tester::add, this)); + cout << "reader and writer threads created" << endl; + + writer.join(); + cout << "writer threads joined. waiting for readers to finish" << endl; + + reader.join(); + + BOOST_REQUIRE_EQUAL(received_nodes, nodes_per_thread); + BOOST_REQUIRE_EQUAL(spsc_queue_cnt, 0); + BOOST_REQUIRE(sf.empty()); + BOOST_REQUIRE(working_set.count_nodes() == 0); + } +}; + +BOOST_AUTO_TEST_CASE( spsc_queue_test_caching ) +{ + boost::shared_ptr test1(new spsc_queue_tester); + test1->run(); +} + +struct spsc_queue_tester_buffering +{ + spsc_queue > sf; + + boost::lockfree::detail::atomic spsc_queue_cnt; + +// In VxWorks one RTP just supports 65535 objects +#ifndef __VXWORKS__ + static_hashed_set working_set; +#else + static_hashed_set working_set; +#endif + + boost::lockfree::detail::atomic received_nodes; + + spsc_queue_tester_buffering(void): + spsc_queue_cnt(0), received_nodes(0) + {} + + static const size_t buf_size = 5; + + void add(void) + { + boost::array input_buffer; + for (boost::uint32_t i = 0; i != nodes_per_thread; i+=buf_size) { + for (size_t i = 0; i != buf_size; ++i) { + int id = generate_id(); + working_set.insert(id); + input_buffer[i] = id; + } + + size_t pushed = 0; + + do { + pushed += sf.push(input_buffer.c_array() + pushed, + input_buffer.size() - pushed); + } while (pushed != buf_size); + + spsc_queue_cnt+=buf_size; + } + running = false; + } + + bool get_elements(void) + { + boost::array output_buffer; + + size_t popd = sf.pop(output_buffer.c_array(), output_buffer.size()); + + if (popd) { + received_nodes += popd; + spsc_queue_cnt -= popd; + + for (size_t i = 0; i != popd; ++i) { + bool erased = working_set.erase(output_buffer[i]); + assert(erased); + } + + return true; + } else + return false; + } + + boost::lockfree::detail::atomic running; + + void get(void) + { + for(;;) { + bool success = get_elements(); + if (!running && !success) + break; + } + + while ( get_elements() ); + } + + void run(void) + { + running = true; + + boost::thread reader(boost::bind(&spsc_queue_tester_buffering::get, this)); + boost::thread writer(boost::bind(&spsc_queue_tester_buffering::add, this)); + cout << "reader and writer threads created" << endl; + + writer.join(); + cout << "writer threads joined. waiting for readers to finish" << endl; + + reader.join(); + + BOOST_REQUIRE_EQUAL(received_nodes, nodes_per_thread); + BOOST_REQUIRE_EQUAL(spsc_queue_cnt, 0); + BOOST_REQUIRE(sf.empty()); + BOOST_REQUIRE(working_set.count_nodes() == 0); + } +}; + + +BOOST_AUTO_TEST_CASE( spsc_queue_test_buffering ) +{ + boost::shared_ptr test1(new spsc_queue_tester_buffering); + test1->run(); +} + diff --git a/src/boost/libs/lockfree/test/spsc_queue_test.cpp b/src/boost/libs/lockfree/test/spsc_queue_test.cpp new file mode 100644 index 00000000..99f393f0 --- /dev/null +++ b/src/boost/libs/lockfree/test/spsc_queue_test.cpp @@ -0,0 +1,407 @@ +// 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) + +#include + +#define BOOST_TEST_MAIN +#ifdef BOOST_LOCKFREE_INCLUDE_TESTS +#include +#else +#include +#endif + +#include +#include + +#include "test_helpers.hpp" +#include "test_common.hpp" + +using namespace boost; +using namespace boost::lockfree; +using namespace std; + +BOOST_AUTO_TEST_CASE( simple_spsc_queue_test ) +{ + spsc_queue > f; + + BOOST_REQUIRE(f.empty()); + f.push(1); + f.push(2); + + int i1(0), i2(0); + + BOOST_REQUIRE(f.pop(i1)); + BOOST_REQUIRE_EQUAL(i1, 1); + + BOOST_REQUIRE(f.pop(i2)); + BOOST_REQUIRE_EQUAL(i2, 2); + BOOST_REQUIRE(f.empty()); +} + +BOOST_AUTO_TEST_CASE( simple_spsc_queue_test_compile_time_size ) +{ + spsc_queue f(64); + + BOOST_REQUIRE(f.empty()); + f.push(1); + f.push(2); + + int i1(0), i2(0); + + BOOST_REQUIRE(f.pop(i1)); + BOOST_REQUIRE_EQUAL(i1, 1); + + BOOST_REQUIRE(f.pop(i2)); + BOOST_REQUIRE_EQUAL(i2, 2); + BOOST_REQUIRE(f.empty()); +} + +BOOST_AUTO_TEST_CASE( ranged_push_test ) +{ + spsc_queue stk(64); + + int data[2] = {1, 2}; + + BOOST_REQUIRE_EQUAL(stk.push(data, data + 2), data + 2); + + int out; + BOOST_REQUIRE(stk.pop(out)); BOOST_REQUIRE_EQUAL(out, 1); + BOOST_REQUIRE(stk.pop(out)); BOOST_REQUIRE_EQUAL(out, 2); + BOOST_REQUIRE(!stk.pop(out)); +} + +BOOST_AUTO_TEST_CASE( spsc_queue_consume_one_test ) +{ + spsc_queue f(64); + + BOOST_WARN(f.is_lock_free()); + BOOST_REQUIRE(f.empty()); + + f.push(1); + f.push(2); + +#ifdef BOOST_NO_CXX11_LAMBDAS + bool success1 = f.consume_one(test_equal(1)); + bool success2 = f.consume_one(test_equal(2)); +#else + bool success1 = f.consume_one([] (int i) { + BOOST_REQUIRE_EQUAL(i, 1); + }); + + bool success2 = f.consume_one([] (int i) { + BOOST_REQUIRE_EQUAL(i, 2); + }); +#endif + + BOOST_REQUIRE(success1); + BOOST_REQUIRE(success2); + + BOOST_REQUIRE(f.empty()); +} + +BOOST_AUTO_TEST_CASE( spsc_queue_consume_all_test ) +{ + spsc_queue f(64); + + BOOST_WARN(f.is_lock_free()); + BOOST_REQUIRE(f.empty()); + + f.push(1); + f.push(2); + +#ifdef BOOST_NO_CXX11_LAMBDAS + size_t consumed = f.consume_all(dummy_functor()); +#else + size_t consumed = f.consume_all([] (int i) { + }); +#endif + + BOOST_REQUIRE_EQUAL(consumed, 2u); + + BOOST_REQUIRE(f.empty()); +} + +enum { + pointer_and_size, + reference_to_array, + iterator_pair, + output_iterator_ +}; + +BOOST_AUTO_TEST_CASE( spsc_queue_capacity_test ) +{ + spsc_queue > f; + + BOOST_REQUIRE(f.push(1)); + BOOST_REQUIRE(f.push(2)); + BOOST_REQUIRE(!f.push(3)); + + spsc_queue g(2); + + BOOST_REQUIRE(g.push(1)); + BOOST_REQUIRE(g.push(2)); + BOOST_REQUIRE(!g.push(3)); +} + +template +void spsc_queue_avail_test_run(QueueType & q) +{ + BOOST_REQUIRE_EQUAL( q.write_available(), 16 ); + BOOST_REQUIRE_EQUAL( q.read_available(), 0 ); + + for (size_t i = 0; i != 8; ++i) { + BOOST_REQUIRE_EQUAL( q.write_available(), 16 - i ); + BOOST_REQUIRE_EQUAL( q.read_available(), i ); + + q.push( 1 ); + } + + // empty queue + int dummy; + while (q.pop(dummy)) + {} + + for (size_t i = 0; i != 16; ++i) { + BOOST_REQUIRE_EQUAL( q.write_available(), 16 - i ); + BOOST_REQUIRE_EQUAL( q.read_available(), i ); + + q.push( 1 ); + } +} + +BOOST_AUTO_TEST_CASE( spsc_queue_avail_test ) +{ + spsc_queue > f; + spsc_queue_avail_test_run(f); + + spsc_queue g(16); + spsc_queue_avail_test_run(g); +} + + +template +void spsc_queue_buffer_push_return_value(void) +{ + const size_t xqueue_size = 64; + const size_t buffer_size = 100; + spsc_queue > rb; + + int data[xqueue_size]; + for (size_t i = 0; i != xqueue_size; ++i) + data[i] = (int)i*2; + + switch (EnqueueMode) { + case pointer_and_size: + BOOST_REQUIRE_EQUAL(rb.push(data, xqueue_size), xqueue_size); + break; + + case reference_to_array: + BOOST_REQUIRE_EQUAL(rb.push(data), xqueue_size); + break; + + case iterator_pair: + BOOST_REQUIRE_EQUAL(rb.push(data, data + xqueue_size), data + xqueue_size); + break; + + default: + assert(false); + } + + switch (EnqueueMode) { + case pointer_and_size: + BOOST_REQUIRE_EQUAL(rb.push(data, xqueue_size), buffer_size - xqueue_size); + break; + + case reference_to_array: + BOOST_REQUIRE_EQUAL(rb.push(data), buffer_size - xqueue_size); + break; + + case iterator_pair: + BOOST_REQUIRE_EQUAL(rb.push(data, data + xqueue_size), data + buffer_size - xqueue_size); + break; + + default: + assert(false); + } +} + +BOOST_AUTO_TEST_CASE( spsc_queue_buffer_push_return_value_test ) +{ + spsc_queue_buffer_push_return_value(); + spsc_queue_buffer_push_return_value(); + spsc_queue_buffer_push_return_value(); +} + +template +void spsc_queue_buffer_push(void) +{ + const size_t xqueue_size = ElementCount; + spsc_queue > rb; + + int data[xqueue_size]; + for (size_t i = 0; i != xqueue_size; ++i) + data[i] = (int)i*2; + + std::vector vdata(data, data + xqueue_size); + + for (int i = 0; i != NumberOfIterations; ++i) { + BOOST_REQUIRE(rb.empty()); + switch (EnqueueMode) { + case pointer_and_size: + BOOST_REQUIRE_EQUAL(rb.push(data, xqueue_size), xqueue_size); + break; + + case reference_to_array: + BOOST_REQUIRE_EQUAL(rb.push(data), xqueue_size); + break; + + case iterator_pair: + BOOST_REQUIRE_EQUAL(rb.push(data, data + xqueue_size), data + xqueue_size); + break; + + default: + assert(false); + } + + int out[xqueue_size]; + BOOST_REQUIRE_EQUAL(rb.pop(out, xqueue_size), xqueue_size); + for (size_t i = 0; i != xqueue_size; ++i) + BOOST_REQUIRE_EQUAL(data[i], out[i]); + } +} + +BOOST_AUTO_TEST_CASE( spsc_queue_buffer_push_test ) +{ + spsc_queue_buffer_push(); + spsc_queue_buffer_push(); + spsc_queue_buffer_push(); +} + +template +void spsc_queue_buffer_pop(void) +{ + const size_t xqueue_size = ElementCount; + spsc_queue > rb; + + int data[xqueue_size]; + for (size_t i = 0; i != xqueue_size; ++i) + data[i] = (int)i*2; + + std::vector vdata(data, data + xqueue_size); + + for (int i = 0; i != NumberOfIterations; ++i) { + BOOST_REQUIRE(rb.empty()); + BOOST_REQUIRE_EQUAL(rb.push(data), xqueue_size); + + int out[xqueue_size]; + vector vout; + + switch (EnqueueMode) { + case pointer_and_size: + BOOST_REQUIRE_EQUAL(rb.pop(out, xqueue_size), xqueue_size); + break; + + case reference_to_array: + BOOST_REQUIRE_EQUAL(rb.pop(out), xqueue_size); + break; + + case output_iterator_: + BOOST_REQUIRE_EQUAL(rb.pop(std::back_inserter(vout)), xqueue_size); + break; + + default: + assert(false); + } + + if (EnqueueMode == output_iterator_) { + BOOST_REQUIRE_EQUAL(vout.size(), xqueue_size); + for (size_t i = 0; i != xqueue_size; ++i) + BOOST_REQUIRE_EQUAL(data[i], vout[i]); + } else { + for (size_t i = 0; i != xqueue_size; ++i) + BOOST_REQUIRE_EQUAL(data[i], out[i]); + } + } +} + +BOOST_AUTO_TEST_CASE( spsc_queue_buffer_pop_test ) +{ + spsc_queue_buffer_pop(); + spsc_queue_buffer_pop(); + spsc_queue_buffer_pop(); +} + +// Test front() and pop() +template < typename Queue > +void spsc_queue_front_pop(Queue& queue) +{ + queue.push(1); + queue.push(2); + queue.push(3); + + // front as ref and const ref + int& rfront = queue.front(); + const int& crfront = queue.front(); + + BOOST_REQUIRE_EQUAL(1, rfront); + BOOST_REQUIRE_EQUAL(1, crfront); + + int front = 0; + + // access element pushed first + front = queue.front(); + BOOST_REQUIRE_EQUAL(1, front); + + // front is still the same + front = queue.front(); + BOOST_REQUIRE_EQUAL(1, front); + + queue.pop(); + + front = queue.front(); + BOOST_REQUIRE_EQUAL(2, front); + + queue.pop(); // pop 2 + + bool pop_ret = queue.pop(); // pop 3 + BOOST_REQUIRE(pop_ret); + + pop_ret = queue.pop(); // pop on empty queue + BOOST_REQUIRE( ! pop_ret); +} + +BOOST_AUTO_TEST_CASE( spsc_queue_buffer_front_and_pop_runtime_sized_test ) +{ + spsc_queue > queue; + spsc_queue_front_pop(queue); +} + +BOOST_AUTO_TEST_CASE( spsc_queue_buffer_front_and_pop_compiletime_sized_test ) +{ + spsc_queue queue(64); + spsc_queue_front_pop(queue); +} + +BOOST_AUTO_TEST_CASE( spsc_queue_reset_test ) +{ + spsc_queue > f; + + BOOST_REQUIRE(f.empty()); + f.push(1); + f.push(2); + + f.reset(); + + BOOST_REQUIRE(f.empty()); +} diff --git a/src/boost/libs/lockfree/test/stack_bounded_stress_test.cpp b/src/boost/libs/lockfree/test/stack_bounded_stress_test.cpp new file mode 100644 index 00000000..55d097fb --- /dev/null +++ b/src/boost/libs/lockfree/test/stack_bounded_stress_test.cpp @@ -0,0 +1,27 @@ +// 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) + +#include + +#include + +#define BOOST_TEST_MAIN +#ifdef BOOST_LOCKFREE_INCLUDE_TESTS +#include +#else +#include +#endif + +#include "test_common.hpp" + +BOOST_AUTO_TEST_CASE( stack_test_bounded ) +{ + typedef queue_stress_tester tester_type; + boost::scoped_ptr tester(new tester_type(4, 4) ); + + boost::lockfree::stack q(128); + tester->run(q); +} diff --git a/src/boost/libs/lockfree/test/stack_fixedsize_stress_test.cpp b/src/boost/libs/lockfree/test/stack_fixedsize_stress_test.cpp new file mode 100644 index 00000000..688af308 --- /dev/null +++ b/src/boost/libs/lockfree/test/stack_fixedsize_stress_test.cpp @@ -0,0 +1,28 @@ +// 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) + +#include + +#include + +#define BOOST_TEST_MAIN +#ifdef BOOST_LOCKFREE_INCLUDE_TESTS +#include +#else +#include +#endif + +#include "test_common.hpp" + + +BOOST_AUTO_TEST_CASE( stack_test_fixed_size ) +{ + typedef queue_stress_tester<> tester_type; + boost::scoped_ptr tester(new tester_type(4, 4) ); + + boost::lockfree::stack > q; + tester->run(q); +} diff --git a/src/boost/libs/lockfree/test/stack_interprocess_test.cpp b/src/boost/libs/lockfree/test/stack_interprocess_test.cpp new file mode 100644 index 00000000..1a60e63f --- /dev/null +++ b/src/boost/libs/lockfree/test/stack_interprocess_test.cpp @@ -0,0 +1,57 @@ +// 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) + +#include //std::system +#include + +#include +#include +#include + +using namespace boost::interprocess; +typedef allocator ShmemAllocator; +typedef boost::lockfree::stack, + boost::lockfree::capacity<2048> + > stack; + +int main (int argc, char *argv[]) +{ + if(argc == 1){ + struct shm_remove + { + shm_remove() { shared_memory_object::remove("MySharedMemory"); } + ~shm_remove(){ shared_memory_object::remove("MySharedMemory"); } + } remover; + + managed_shared_memory segment(create_only, "MySharedMemory", 65536); + ShmemAllocator alloc_inst (segment.get_segment_manager()); + + stack * queue = segment.construct("stack")(alloc_inst); + for (int i = 0; i != 1024; ++i) + queue->push(i); + + std::string s(argv[0]); s += " child "; + if(0 != std::system(s.c_str())) + return 1; + + while (!queue->empty()) + boost::thread::yield(); + return 0; + } else { + managed_shared_memory segment(open_only, "MySharedMemory"); + stack * queue = segment.find("stack").first; + + int from_queue; + for (int i = 0; i != 1024; ++i) { + bool success = queue->pop(from_queue); + assert (success); + assert (from_queue == 1023 - i); + } + segment.destroy("stack"); + } + return 0; +} diff --git a/src/boost/libs/lockfree/test/stack_test.cpp b/src/boost/libs/lockfree/test/stack_test.cpp new file mode 100644 index 00000000..303222b6 --- /dev/null +++ b/src/boost/libs/lockfree/test/stack_test.cpp @@ -0,0 +1,219 @@ +// 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) + + +#include +#include + +#define BOOST_TEST_MAIN +#ifdef BOOST_LOCKFREE_INCLUDE_TESTS +#include +#else +#include +#endif + +#include "test_helpers.hpp" + +BOOST_AUTO_TEST_CASE( simple_stack_test ) +{ + boost::lockfree::stack stk(128); + + stk.push(1); + stk.push(2); + long out; + BOOST_REQUIRE(stk.pop(out)); BOOST_REQUIRE_EQUAL(out, 2); + BOOST_REQUIRE(stk.pop(out)); BOOST_REQUIRE_EQUAL(out, 1); + BOOST_REQUIRE(!stk.pop(out)); +} + +BOOST_AUTO_TEST_CASE( unsafe_stack_test ) +{ + boost::lockfree::stack stk(128); + + stk.unsynchronized_push(1); + stk.unsynchronized_push(2); + long out; + BOOST_REQUIRE(stk.unsynchronized_pop(out)); BOOST_REQUIRE_EQUAL(out, 2); + BOOST_REQUIRE(stk.unsynchronized_pop(out)); BOOST_REQUIRE_EQUAL(out, 1); + BOOST_REQUIRE(!stk.unsynchronized_pop(out)); +} + +BOOST_AUTO_TEST_CASE( ranged_push_test ) +{ + boost::lockfree::stack stk(128); + + long data[2] = {1, 2}; + + BOOST_REQUIRE_EQUAL(stk.push(data, data + 2), data + 2); + + long out; + BOOST_REQUIRE(stk.unsynchronized_pop(out)); BOOST_REQUIRE_EQUAL(out, 2); + BOOST_REQUIRE(stk.unsynchronized_pop(out)); BOOST_REQUIRE_EQUAL(out, 1); + BOOST_REQUIRE(!stk.unsynchronized_pop(out)); +} + +BOOST_AUTO_TEST_CASE( ranged_unsynchronized_push_test ) +{ + boost::lockfree::stack stk(128); + + long data[2] = {1, 2}; + + BOOST_REQUIRE_EQUAL(stk.unsynchronized_push(data, data + 2), data + 2); + + long out; + BOOST_REQUIRE(stk.unsynchronized_pop(out)); BOOST_REQUIRE_EQUAL(out, 2); + BOOST_REQUIRE(stk.unsynchronized_pop(out)); BOOST_REQUIRE_EQUAL(out, 1); + BOOST_REQUIRE(!stk.unsynchronized_pop(out)); +} + +BOOST_AUTO_TEST_CASE( fixed_size_stack_test ) +{ + boost::lockfree::stack > stk; + + stk.push(1); + stk.push(2); + long out; + BOOST_REQUIRE(stk.pop(out)); BOOST_REQUIRE_EQUAL(out, 2); + BOOST_REQUIRE(stk.pop(out)); BOOST_REQUIRE_EQUAL(out, 1); + BOOST_REQUIRE(!stk.pop(out)); + BOOST_REQUIRE(stk.empty()); +} + +BOOST_AUTO_TEST_CASE( fixed_size_stack_test_exhausted ) +{ + boost::lockfree::stack > stk; + + stk.push(1); + stk.push(2); + BOOST_REQUIRE(!stk.push(3)); + long out; + BOOST_REQUIRE(stk.pop(out)); BOOST_REQUIRE_EQUAL(out, 2); + BOOST_REQUIRE(stk.pop(out)); BOOST_REQUIRE_EQUAL(out, 1); + BOOST_REQUIRE(!stk.pop(out)); + BOOST_REQUIRE(stk.empty()); +} + +BOOST_AUTO_TEST_CASE( bounded_stack_test_exhausted ) +{ + boost::lockfree::stack stk(2); + + stk.bounded_push(1); + stk.bounded_push(2); + BOOST_REQUIRE(!stk.bounded_push(3)); + long out; + BOOST_REQUIRE(stk.pop(out)); BOOST_REQUIRE_EQUAL(out, 2); + BOOST_REQUIRE(stk.pop(out)); BOOST_REQUIRE_EQUAL(out, 1); + BOOST_REQUIRE(!stk.pop(out)); + BOOST_REQUIRE(stk.empty()); +} + +BOOST_AUTO_TEST_CASE( stack_consume_one_test ) +{ + boost::lockfree::stack f(64); + + BOOST_WARN(f.is_lock_free()); + BOOST_REQUIRE(f.empty()); + + f.push(1); + f.push(2); + +#ifdef BOOST_NO_CXX11_LAMBDAS + bool success1 = f.consume_one(test_equal(2)); + bool success2 = f.consume_one(test_equal(1)); +#else + bool success1 = f.consume_one([] (int i) { + BOOST_REQUIRE_EQUAL(i, 2); + }); + + bool success2 = f.consume_one([] (int i) { + BOOST_REQUIRE_EQUAL(i, 1); + }); +#endif + + BOOST_REQUIRE(success1); + BOOST_REQUIRE(success2); + + BOOST_REQUIRE(f.empty()); +} + +BOOST_AUTO_TEST_CASE( stack_consume_all_test ) +{ + boost::lockfree::stack f(64); + + BOOST_WARN(f.is_lock_free()); + BOOST_REQUIRE(f.empty()); + + f.push(1); + f.push(2); + +#ifdef BOOST_NO_CXX11_LAMBDAS + size_t consumed = f.consume_all(dummy_functor()); +#else + size_t consumed = f.consume_all([] (int i) { + }); +#endif + + BOOST_REQUIRE_EQUAL(consumed, 2u); + + BOOST_REQUIRE(f.empty()); +} + +BOOST_AUTO_TEST_CASE( stack_consume_all_atomic_test ) +{ + boost::lockfree::stack f(64); + + BOOST_WARN(f.is_lock_free()); + BOOST_REQUIRE(f.empty()); + + f.push(1); + f.push(2); + f.push(3); + +#ifdef BOOST_NO_CXX11_LAMBDAS + size_t consumed = f.consume_all_atomic(dummy_functor()); +#else + size_t consumed = f.consume_all_atomic([] (int i) { + }); +#endif + + BOOST_REQUIRE_EQUAL(consumed, 3u); + + BOOST_REQUIRE(f.empty()); +} + + +BOOST_AUTO_TEST_CASE( stack_consume_all_atomic_reversed_test ) +{ + boost::lockfree::stack f(64); + + BOOST_WARN(f.is_lock_free()); + BOOST_REQUIRE(f.empty()); + + f.push(1); + f.push(2); + f.push(3); + +#ifdef BOOST_NO_CXX11_LAMBDAS + size_t consumed = f.consume_all_atomic_reversed(dummy_functor()); +#else + size_t consumed = f.consume_all_atomic_reversed([] (int i) { + }); +#endif + + BOOST_REQUIRE_EQUAL(consumed, 3u); + + BOOST_REQUIRE(f.empty()); +} + + +BOOST_AUTO_TEST_CASE( reserve_test ) +{ + typedef boost::lockfree::stack< void* > memory_stack; + + memory_stack ms(1); + ms.reserve(1); + ms.reserve_unsafe(1); +} diff --git a/src/boost/libs/lockfree/test/stack_unbounded_stress_test.cpp b/src/boost/libs/lockfree/test/stack_unbounded_stress_test.cpp new file mode 100644 index 00000000..98d97517 --- /dev/null +++ b/src/boost/libs/lockfree/test/stack_unbounded_stress_test.cpp @@ -0,0 +1,28 @@ +// 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) + +#include + +#include + +#define BOOST_TEST_MAIN +#ifdef BOOST_LOCKFREE_INCLUDE_TESTS +#include +#else +#include +#endif + +#include "test_common.hpp" + + +BOOST_AUTO_TEST_CASE( stack_test_unbounded ) +{ + typedef queue_stress_tester tester_type; + boost::scoped_ptr tester(new tester_type(4, 4) ); + + boost::lockfree::stack q(128); + tester->run(q); +} diff --git a/src/boost/libs/lockfree/test/tagged_ptr_test.cpp b/src/boost/libs/lockfree/test/tagged_ptr_test.cpp new file mode 100644 index 00000000..4ce1dd74 --- /dev/null +++ b/src/boost/libs/lockfree/test/tagged_ptr_test.cpp @@ -0,0 +1,58 @@ +// 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) + +#include + +#include + +#define BOOST_TEST_MAIN +#ifdef BOOST_LOCKFREE_INCLUDE_TESTS +#include +#else +#include +#endif + +BOOST_AUTO_TEST_CASE( tagged_ptr_test ) +{ + using namespace boost::lockfree::detail; + int a(1), b(2); + + typedef tagged_ptr::tag_t tag_t; + const tag_t max_tag = (std::numeric_limits::max)(); + + { + tagged_ptr i (&a, 0); + tagged_ptr j (&b, 1); + + i = j; + + BOOST_REQUIRE_EQUAL(i.get_ptr(), &b); + BOOST_REQUIRE_EQUAL(i.get_tag(), 1); + } + + { + tagged_ptr i (&a, 0); + tagged_ptr j (i); + + BOOST_REQUIRE_EQUAL(i.get_ptr(), j.get_ptr()); + BOOST_REQUIRE_EQUAL(i.get_tag(), j.get_tag()); + } + + { + tagged_ptr i (&a, 0); + BOOST_REQUIRE_EQUAL(i.get_tag() + 1, i.get_next_tag()); + } + + { + tagged_ptr j (&a, max_tag); + BOOST_REQUIRE_EQUAL(j.get_next_tag(), 0); + } + + { + tagged_ptr j (&a, max_tag - 1); + BOOST_REQUIRE_EQUAL(j.get_next_tag(), max_tag); + } +} diff --git a/src/boost/libs/lockfree/test/test_common.hpp b/src/boost/libs/lockfree/test/test_common.hpp new file mode 100644 index 00000000..2db41a84 --- /dev/null +++ b/src/boost/libs/lockfree/test/test_common.hpp @@ -0,0 +1,145 @@ +// 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) + +#include +#include +#include "test_helpers.hpp" + +#include +#include + +namespace impl { + +using boost::array; +using namespace boost; +using namespace std; + +template +struct queue_stress_tester +{ + static const unsigned int buckets = 1<<13; +#ifndef BOOST_LOCKFREE_STRESS_TEST + static const long node_count = 5000; +#else + static const long node_count = 500000; +#endif + const int reader_threads; + const int writer_threads; + + boost::lockfree::detail::atomic writers_finished; + + static_hashed_set data; + static_hashed_set dequeued; + array, buckets> returned; + + boost::lockfree::detail::atomic push_count, pop_count; + + queue_stress_tester(int reader, int writer): + reader_threads(reader), writer_threads(writer), push_count(0), pop_count(0) + {} + + template + void add_items(queue & stk) + { + for (long i = 0; i != node_count; ++i) { + long id = generate_id(); + + bool inserted = data.insert(id); + assert(inserted); + + if (Bounded) + while(stk.bounded_push(id) == false) { +#ifdef __VXWORKS__ + thread::yield(); +#endif + } + else + while(stk.push(id) == false) { +#ifdef __VXWORKS__ + thread::yield(); +#endif + } + ++push_count; + } + writers_finished += 1; + } + + boost::lockfree::detail::atomic running; + + template + bool consume_element(queue & q) + { + long id; + bool ret = q.pop(id); + + if (!ret) + return false; + + bool erased = data.erase(id); + bool inserted = dequeued.insert(id); + assert(erased); + assert(inserted); + ++pop_count; + return true; + } + + template + void get_items(queue & q) + { + for (;;) { + bool received_element = consume_element(q); + if (received_element) + continue; + + if ( writers_finished.load() == writer_threads ) + break; + +#ifdef __VXWORKS__ + thread::yield(); +#endif + } + + while (consume_element(q)); + } + + template + void run(queue & stk) + { + BOOST_WARN(stk.is_lock_free()); + writers_finished.store(0); + + thread_group writer; + thread_group reader; + + BOOST_REQUIRE(stk.empty()); + + for (int i = 0; i != reader_threads; ++i) + reader.create_thread(boost::bind(&queue_stress_tester::template get_items, this, boost::ref(stk))); + + for (int i = 0; i != writer_threads; ++i) + writer.create_thread(boost::bind(&queue_stress_tester::template add_items, this, boost::ref(stk))); + + std::cout << "threads created" << std::endl; + + writer.join_all(); + + std::cout << "writer threads joined, waiting for readers" << std::endl; + + reader.join_all(); + + std::cout << "reader threads joined" << std::endl; + + BOOST_REQUIRE_EQUAL(data.count_nodes(), (size_t)0); + BOOST_REQUIRE(stk.empty()); + + BOOST_REQUIRE_EQUAL(push_count, pop_count); + BOOST_REQUIRE_EQUAL(push_count, writer_threads * node_count); + } +}; + +} + +using impl::queue_stress_tester; diff --git a/src/boost/libs/lockfree/test/test_helpers.hpp b/src/boost/libs/lockfree/test/test_helpers.hpp new file mode 100644 index 00000000..882fa1c4 --- /dev/null +++ b/src/boost/libs/lockfree/test/test_helpers.hpp @@ -0,0 +1,110 @@ +// 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) + +#ifndef BOOST_LOCKFREE_TEST_HELPERS +#define BOOST_LOCKFREE_TEST_HELPERS + +#include +#include +#include +#include + +#include + +template +int_type generate_id(void) +{ + static boost::lockfree::detail::atomic generator(0); + return ++generator; +} + +template +class static_hashed_set +{ + +public: + int calc_index(int_type id) + { + // knuth hash ... does not need to be good, but has to be portable + size_t factor = size_t((float)buckets * 1.616f); + + return ((size_t)id * factor) % buckets; + } + + bool insert(int_type const & id) + { + std::size_t index = calc_index(id); + + boost::lock_guard lock (ref_mutex[index]); + + std::pair::iterator, bool> p; + p = data[index].insert(id); + + return p.second; + } + + bool find (int_type const & id) + { + std::size_t index = calc_index(id); + + boost::lock_guard lock (ref_mutex[index]); + + return data[index].find(id) != data[index].end(); + } + + bool erase(int_type const & id) + { + std::size_t index = calc_index(id); + + boost::lock_guard lock (ref_mutex[index]); + + if (data[index].find(id) != data[index].end()) { + data[index].erase(id); + assert(data[index].find(id) == data[index].end()); + return true; + } + else + return false; + } + + std::size_t count_nodes(void) const + { + std::size_t ret = 0; + for (int i = 0; i != buckets; ++i) { + boost::lock_guard lock (ref_mutex[i]); + ret += data[i].size(); + } + return ret; + } + +private: + boost::array, buckets> data; + mutable boost::array ref_mutex; +}; + +struct test_equal +{ + test_equal(int i): + i(i) + {} + + void operator()(int arg) const + { + BOOST_REQUIRE_EQUAL(arg, i); + } + + int i; +}; + +struct dummy_functor +{ + void operator()(int /* arg */) const + { + } +}; + + +#endif -- cgit v1.2.3