4ef74379c2
In VxWorks Kernel, the re-schedule mechanism does not enable "round-robin" reschdule between the same priority tasks by default. So the case "stack_unbounded_stress_test" will lead to test case hang forever. Here's the details: The test case creates 4 tasks as “Reader”, and then 4 tasks as “Writer”, all those 8 task has the same priority 220. If the target has 2 cores, the first 2 reader tasks will occupy the cores by “while (1)” without yield, so the other 2 readers tasks and 4 writers tasks have no chance to be run. This will lead to the test case loop forever , then the exp scrip will catch it and print “RTP Execution Timeout; rebooting” The test case creates 4 tasks as “Reader”, and then 4 tasks as “Writer”, all those 8 task has the same priority 220 in VxWorks Kernel. If the target has 2 cores, the first 2 reader tasks will occupy the cores by “while (1)” without yield, so the other 2 readers tasks and 4 writers tasks have no chance to be run. This will lead to the test case loop forever without any ending. Why modify spsc_queue_stress_test.cpp : In VxWorks user-land task (Wind River calls it as RTP), the max number of objects (the internal data structure RTP uses) in one RTP is limited at most 65535. When the test is selected to run, the C++ constructor will create 1<<16 number of mutex via "new spsc_queue_tester". And after test1->run() is finished, the C++ destructor will delete 1<<16 number of mutex by default. This caused the problem, because VxWorks just support ((1<<16)-1) objects within an RTP.
234 lines
5.9 KiB
C++
234 lines
5.9 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/foreach.hpp>
|
|
#include <boost/thread.hpp>
|
|
#include <boost/scoped_ptr.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_REQUIRE(nodes.find(allocated) == nodes.end());
|
|
nodes.insert(allocated);
|
|
}
|
|
|
|
BOOST_FOREACH(dummy * d, nodes)
|
|
fl.template destruct<threadsafe>(d);
|
|
|
|
nodes.clear();
|
|
for (int i = 0; i != 4; ++i)
|
|
nodes.insert(fl.template construct<threadsafe, bounded>());
|
|
|
|
BOOST_FOREACH(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_REQUIRE(allocated == 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(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<true, bounded>();
|
|
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<true>(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<true>(node);
|
|
}
|
|
}
|
|
};
|
|
|
|
template <typename Tester>
|
|
void run_tester()
|
|
{
|
|
boost::scoped_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>();
|
|
}
|