blob: 7cb60bc90c85067310e43b72b9659e1b745e76c2 [file] [log] [blame]
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2006. 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)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_NAMED_ALLOCATION_TEST_TEMPLATE_HEADER
#define BOOST_INTERPROCESS_NAMED_ALLOCATION_TEST_TEMPLATE_HEADER
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/mem_algo/rbtree_best_fit.hpp>
#include <boost/interprocess/sync/mutex_family.hpp>
#include <boost/interprocess/streams/bufferstream.hpp>
#include <vector>
#include <iostream>
#include <cstdio>
#include <new>
#include <utility>
#include <iterator>
#include <set>
#include <string>
#include "get_process_id_name.hpp"
namespace boost { namespace interprocess { namespace test {
namespace {
const wchar_t *get_prefix(wchar_t)
{ return L"prefix_name_"; }
const char *get_prefix(char)
{ return "prefix_name_"; }
}
//This test allocates until there is no more memory
//and after that deallocates all in the same order
template<class ManagedMemory>
bool test_names_and_types(ManagedMemory &m)
{
typedef typename ManagedMemory::char_type char_type;
typedef std::char_traits<char_type> char_traits_type;
std::vector<char*> buffers;
const int BufferLen = 100;
char_type name[BufferLen];
basic_bufferstream<char_type> formatter(name, BufferLen);
for(int i = 0; true; ++i){
formatter.seekp(0);
formatter << get_prefix(char_type()) << i << std::ends;
char *ptr = m.template construct<char>(name, std::nothrow)(i);
if(!ptr)
break;
std::size_t namelen = char_traits_type::length(m.get_instance_name(ptr));
if(namelen != char_traits_type::length(name)){
return 1;
}
if(char_traits_type::compare(m.get_instance_name(ptr), name, namelen) != 0){
return 1;
}
if(m.template find<char>(name).first == 0)
return false;
if(m.get_instance_type(ptr) != named_type)
return false;
buffers.push_back(ptr);
}
if(m.get_num_named_objects() != buffers.size() || !m.check_sanity())
return false;
for(int j = 0, max = (int)buffers.size()
;j < max
;++j){
m.destroy_ptr(buffers[j]);
}
if(m.get_num_named_objects() != 0 || !m.check_sanity())
return false;
m.shrink_to_fit_indexes();
if(!m.all_memory_deallocated())
return false;
return true;
}
//This test allocates until there is no more memory
//and after that deallocates all in the same order
template<class ManagedMemory>
bool test_named_iterators(ManagedMemory &m)
{
typedef typename ManagedMemory::char_type char_type;
typedef std::char_traits<char_type> char_traits_type;
std::vector<char*> buffers;
const int BufferLen = 100;
char_type name[BufferLen];
typedef std::basic_string<char_type> string_type;
std::set<string_type> names;
basic_bufferstream<char_type> formatter(name, BufferLen);
string_type aux_str;
for(int i = 0; true; ++i){
formatter.seekp(0);
formatter << get_prefix(char_type()) << i << std::ends;
char *ptr = m.template construct<char>(name, std::nothrow)(i);
if(!ptr)
break;
aux_str = name;
names.insert(aux_str);
buffers.push_back(ptr);
}
if(m.get_num_named_objects() != buffers.size() || !m.check_sanity())
return false;
typedef typename ManagedMemory::const_named_iterator const_named_iterator;
const_named_iterator named_beg = m.named_begin();
const_named_iterator named_end = m.named_end();
if(std::distance(named_beg, named_end) != (int)buffers.size()){
return 1;
}
for(; named_beg != named_end; ++named_beg){
const char_type *name = named_beg->name();
aux_str = name;
if(names.find(aux_str) == names.end()){
return 1;
}
if(aux_str.size() != named_beg->name_length()){
return 1;
}
const void *found_value = m.template find<char>(name).first;
if(found_value == 0)
return false;
if(found_value != named_beg->value())
return false;
}
for(int j = 0, max = (int)buffers.size()
;j < max
;++j){
m.destroy_ptr(buffers[j]);
}
if(m.get_num_named_objects() != 0 || !m.check_sanity())
return false;
m.shrink_to_fit_indexes();
if(!m.all_memory_deallocated())
return false;
return true;
}
//This test allocates until there is no more memory
//and after that deallocates all in the same order
template<class ManagedMemory>
bool test_shrink_to_fit(ManagedMemory &m)
{
typedef typename ManagedMemory::char_type char_type;
typedef std::char_traits<char_type> char_traits_type;
std::vector<char*> buffers;
const int BufferLen = 100;
char_type name[BufferLen];
basic_bufferstream<char_type> formatter(name, BufferLen);
std::size_t free_memory_before = m.get_free_memory();
for(int i = 0; true; ++i){
formatter.seekp(0);
formatter << get_prefix(char_type()) << i << std::ends;
char *ptr = m.template construct<char>(name, std::nothrow)(i);
if(!ptr)
break;
buffers.push_back(ptr);
}
for(int j = 0, max = (int)buffers.size()
;j < max
;++j){
m.destroy_ptr(buffers[j]);
}
std::size_t free_memory_after = m.get_free_memory();
if(free_memory_before != free_memory_after){
m.shrink_to_fit_indexes();
if(free_memory_before != free_memory_after)
return false;
}
return true;
}
//This test allocates until there is no more memory
//and after that deallocates all in the same order
template<class ManagedMemory>
bool test_direct_named_allocation_destruction(ManagedMemory &m)
{
typedef typename ManagedMemory::char_type char_type;
typedef std::char_traits<char_type> char_traits_type;
std::vector<char*> buffers;
const int BufferLen = 100;
char_type name[BufferLen];
basic_bufferstream<char_type> formatter(name, BufferLen);
for(int i = 0; true; ++i){
formatter.seekp(0);
formatter << get_prefix(char_type()) << i << std::ends;
char *ptr = m.template construct<char>(name, std::nothrow)(i);
if(!ptr)
break;
if(m.template find<char>(name).first == 0)
return false;
buffers.push_back(ptr);
}
if(m.get_num_named_objects() != buffers.size() || !m.check_sanity())
return false;
for(int j = 0, max = (int)buffers.size()
;j < max
;++j){
m.destroy_ptr(buffers[j]);
}
if(m.get_num_named_objects() != 0 || !m.check_sanity())
return false;
m.shrink_to_fit_indexes();
if(!m.all_memory_deallocated())
return false;
return true;
}
//This test allocates until there is no more memory
//and after that deallocates all in the inverse order
template<class ManagedMemory>
bool test_named_allocation_inverse_destruction(ManagedMemory &m)
{
typedef typename ManagedMemory::char_type char_type;
typedef std::char_traits<char_type> char_traits_type;
std::vector<char*> buffers;
const int BufferLen = 100;
char_type name[BufferLen];
basic_bufferstream<char_type> formatter(name, BufferLen);
for(int i = 0; true; ++i){
formatter.seekp(0);
formatter << get_prefix(char_type()) << i << std::ends;
char *ptr = m.template construct<char>(name, std::nothrow)(i);
if(!ptr)
break;
buffers.push_back(ptr);
}
if(m.get_num_named_objects() != buffers.size() || !m.check_sanity())
return false;
for(int j = (int)buffers.size()
;j--
;){
m.destroy_ptr(buffers[j]);
}
if(m.get_num_named_objects() != 0 || !m.check_sanity())
return false;
m.shrink_to_fit_indexes();
if(!m.all_memory_deallocated())
return false;
return true;
}
//This test allocates until there is no more memory
//and after that deallocates all following a pattern
template<class ManagedMemory>
bool test_named_allocation_mixed_destruction(ManagedMemory &m)
{
typedef typename ManagedMemory::char_type char_type;
typedef std::char_traits<char_type> char_traits_type;
std::vector<char*> buffers;
const int BufferLen = 100;
char_type name[BufferLen];
basic_bufferstream<char_type> formatter(name, BufferLen);
for(int i = 0; true; ++i){
formatter.seekp(0);
formatter << get_prefix(char_type()) << i << std::ends;
char *ptr = m.template construct<char>(name, std::nothrow)(i);
if(!ptr)
break;
buffers.push_back(ptr);
}
if(m.get_num_named_objects() != buffers.size() || !m.check_sanity())
return false;
for(int j = 0, max = (int)buffers.size()
;j < max
;++j){
int pos = (j%4)*((int)buffers.size())/4;
m.destroy_ptr(buffers[pos]);
buffers.erase(buffers.begin()+pos);
}
if(m.get_num_named_objects() != 0 || !m.check_sanity())
return false;
m.shrink_to_fit_indexes();
if(!m.all_memory_deallocated())
return false;
return true;
}
//This test allocates until there is no more memory
//and after that deallocates all in the same order
template<class ManagedMemory>
bool test_inverse_named_allocation_destruction(ManagedMemory &m)
{
typedef typename ManagedMemory::char_type char_type;
typedef std::char_traits<char_type> char_traits_type;
std::vector<char*> buffers;
const int BufferLen = 100;
char_type name[BufferLen];
basic_bufferstream<char_type> formatter(name, BufferLen);
for(unsigned int i = 0; true; ++i){
formatter.seekp(0);
formatter << get_prefix(char_type()) << i << std::ends;
char *ptr = m.template construct<char>(name, std::nothrow)(i);
if(!ptr)
break;
buffers.push_back(ptr);
}
if(m.get_num_named_objects() != buffers.size() || !m.check_sanity())
return false;
for(unsigned int j = 0, max = (unsigned int)buffers.size()
;j < max
;++j){
m.destroy_ptr(buffers[j]);
}
if(m.get_num_named_objects() != 0 || !m.check_sanity())
return false;
m.shrink_to_fit_indexes();
if(!m.all_memory_deallocated())
return false;
return true;
}
///This function calls all tests
template<class ManagedMemory>
bool test_all_named_allocation(ManagedMemory &m)
{
std::cout << "Starting test_names_and_types. Class: "
<< typeid(m).name() << std::endl;
if(!test_names_and_types(m)){
std::cout << "test_names_and_types failed. Class: "
<< typeid(m).name() << std::endl;
return false;
}
std::cout << "Starting test_direct_named_allocation_destruction. Class: "
<< typeid(m).name() << std::endl;
if(!test_direct_named_allocation_destruction(m)){
std::cout << "test_direct_named_allocation_destruction failed. Class: "
<< typeid(m).name() << std::endl;
return false;
}
std::cout << "Starting test_named_allocation_inverse_destruction. Class: "
<< typeid(m).name() << std::endl;
if(!test_named_allocation_inverse_destruction(m)){
std::cout << "test_named_allocation_inverse_destruction failed. Class: "
<< typeid(m).name() << std::endl;
return false;
}
std::cout << "Starting test_named_allocation_mixed_destruction. Class: "
<< typeid(m).name() << std::endl;
if(!test_named_allocation_mixed_destruction(m)){
std::cout << "test_named_allocation_mixed_destruction failed. Class: "
<< typeid(m).name() << std::endl;
return false;
}
std::cout << "Starting test_inverse_named_allocation_destruction. Class: "
<< typeid(m).name() << std::endl;
if(!test_inverse_named_allocation_destruction(m)){
std::cout << "test_inverse_named_allocation_destruction failed. Class: "
<< typeid(m).name() << std::endl;
return false;
}
if(!test_named_iterators(m)){
std::cout << "test_named_iterators failed. Class: "
<< typeid(m).name() << std::endl;
return false;
}
return true;
}
//This function calls all tests
template<template <class IndexConfig> class Index>
bool test_named_allocation()
{
using namespace boost::interprocess;
const int memsize = 163840;
const char *const shMemName = test::get_process_id_name();
try
{
//A shared memory with rbtree best fit algorithm
typedef basic_managed_shared_memory
<char
,rbtree_best_fit<mutex_family>
,Index
> my_managed_shared_memory;
//Create shared memory
shared_memory_object::remove(shMemName);
my_managed_shared_memory segment(create_only, shMemName, memsize);
//Now take the segment manager and launch memory test
if(!test::test_all_named_allocation(*segment.get_segment_manager())){
return false;
}
}
catch(...){
shared_memory_object::remove(shMemName);
throw;
}
shared_memory_object::remove(shMemName);
//Now test it with wchar_t
try
{
//A shared memory with simple sequential fit algorithm
typedef basic_managed_shared_memory
<wchar_t
,rbtree_best_fit<mutex_family>
,Index
> my_managed_shared_memory;
//Create shared memory
shared_memory_object::remove(shMemName);
my_managed_shared_memory segment(create_only, shMemName, memsize);
//Now take the segment manager and launch memory test
if(!test::test_all_named_allocation(*segment.get_segment_manager())){
return false;
}
}
catch(...){
shared_memory_object::remove(shMemName);
throw;
}
shared_memory_object::remove(shMemName);
return true;
}
}}} //namespace boost { namespace interprocess { namespace test {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_NAMED_ALLOCATION_TEST_TEMPLATE_HEADER