1 //////////////////////////////////////////////////////////////////////////////
2 //
3 // (C) Copyright Ion Gaztanaga 2006-2012. Distributed under the Boost
4 // Software License, Version 1.0. (See accompanying file
5 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // See http://www.boost.org/libs/interprocess for documentation.
8 //
9 //////////////////////////////////////////////////////////////////////////////
10 
11 #ifndef BOOST_INTERPROCESS_NAMED_ALLOCATION_TEST_TEMPLATE_HEADER
12 #define BOOST_INTERPROCESS_NAMED_ALLOCATION_TEST_TEMPLATE_HEADER
13 
14 #include <boost/interprocess/detail/config_begin.hpp>
15 
16 // interprocess
17 #include <boost/interprocess/managed_shared_memory.hpp>
18 #include <boost/interprocess/mem_algo/rbtree_best_fit.hpp>
19 #include <boost/interprocess/streams/bufferstream.hpp>
20 #include <boost/interprocess/sync/mutex_family.hpp>
21 // container
22 #include <boost/container/detail/iterator.hpp>
23 #include <boost/container/detail/minimal_char_traits_header.hpp>  //char_traits
24 // std
25 #include <cstdio>
26 #include <iostream>
27 #include <new>
28 #include <set>
29 #include <vector>
30 
31 // local
32 #include "get_process_id_name.hpp"
33 
34 namespace boost { namespace interprocess { namespace test {
35 
36 namespace {
get_prefix(wchar_t)37    const wchar_t *get_prefix(wchar_t)
38    {  return L"prefix_name_"; }
39 
get_prefix(char)40    const char *get_prefix(char)
41    {  return "prefix_name_"; }
42 }
43 
44 //This test allocates until there is no more memory
45 //and after that deallocates all in the same order
46 template<class ManagedMemory>
test_names_and_types(ManagedMemory & m)47 bool test_names_and_types(ManagedMemory &m)
48 {
49    typedef typename ManagedMemory::char_type char_type;
50    typedef std::char_traits<char_type> char_traits_type;
51    std::vector<char*> buffers;
52    const int BufferLen = 100;
53    char_type name[BufferLen];
54 
55    basic_bufferstream<char_type> formatter(name, BufferLen);
56 
57    for(int i = 0; true; ++i){
58       formatter.seekp(0);
59       formatter << get_prefix(char_type()) << i << std::ends;
60 
61       char *ptr = m.template construct<char>(name, std::nothrow)(i);
62 
63       if(!ptr)
64          break;
65 
66       std::size_t namelen = char_traits_type::length(m.get_instance_name(ptr));
67       if(namelen != char_traits_type::length(name)){
68          return 1;
69       }
70 
71       if(char_traits_type::compare(m.get_instance_name(ptr), name, namelen) != 0){
72          return 1;
73       }
74 
75       if(m.template find<char>(name).first == 0)
76          return false;
77 
78       if(m.get_instance_type(ptr) != named_type)
79          return false;
80 
81       buffers.push_back(ptr);
82    }
83 
84    if(m.get_num_named_objects() != buffers.size() || !m.check_sanity())
85       return false;
86 
87    for(int j = 0, max = (int)buffers.size()
88       ;j < max
89       ;++j){
90       m.destroy_ptr(buffers[j]);
91    }
92 
93    if(m.get_num_named_objects() != 0 || !m.check_sanity())
94       return false;
95    m.shrink_to_fit_indexes();
96    if(!m.all_memory_deallocated())
97       return false;
98    return true;
99 }
100 
101 
102 //This test allocates until there is no more memory
103 //and after that deallocates all in the same order
104 template<class ManagedMemory>
test_named_iterators(ManagedMemory & m)105 bool test_named_iterators(ManagedMemory &m)
106 {
107    typedef typename ManagedMemory::char_type char_type;
108    std::vector<char*> buffers;
109    const int BufferLen = 100;
110    char_type name[BufferLen];
111    typedef std::basic_string<char_type> string_type;
112    std::set<string_type> names;
113 
114    basic_bufferstream<char_type> formatter(name, BufferLen);
115 
116    string_type aux_str;
117 
118    for(int i = 0; true; ++i){
119       formatter.seekp(0);
120       formatter << get_prefix(char_type()) << i << std::ends;
121       char *ptr = m.template construct<char>(name, std::nothrow)(i);
122       if(!ptr)
123          break;
124       aux_str = name;
125       names.insert(aux_str);
126       buffers.push_back(ptr);
127    }
128 
129    if(m.get_num_named_objects() != buffers.size() || !m.check_sanity())
130       return false;
131 
132    typedef typename ManagedMemory::const_named_iterator const_named_iterator;
133    const_named_iterator named_beg = m.named_begin();
134    const_named_iterator named_end = m.named_end();
135 
136    if((std::size_t)boost::container::iterator_distance(named_beg, named_end) != (std::size_t)buffers.size()){
137       return 1;
138    }
139 
140    for(; named_beg != named_end; ++named_beg){
141       const char_type *name_str = named_beg->name();
142       aux_str = name_str;
143       if(names.find(aux_str) == names.end()){
144          return 1;
145       }
146 
147       if(aux_str.size() != named_beg->name_length()){
148          return 1;
149       }
150 
151       const void *found_value = m.template find<char>(name_str).first;
152 
153       if(found_value == 0)
154          return false;
155       if(found_value != named_beg->value())
156          return false;
157    }
158 
159    for(int j = 0, max = (int)buffers.size()
160       ;j < max
161       ;++j){
162       m.destroy_ptr(buffers[j]);
163    }
164 
165    if(m.get_num_named_objects() != 0 || !m.check_sanity())
166       return false;
167    m.shrink_to_fit_indexes();
168    if(!m.all_memory_deallocated())
169       return false;
170    return true;
171 }
172 
173 //This test allocates until there is no more memory
174 //and after that deallocates all in the same order
175 template<class ManagedMemory>
test_shrink_to_fit(ManagedMemory & m)176 bool test_shrink_to_fit(ManagedMemory &m)
177 {
178    typedef typename ManagedMemory::char_type char_type;
179    std::vector<char*> buffers;
180    const int BufferLen = 100;
181    char_type name[BufferLen];
182 
183    basic_bufferstream<char_type> formatter(name, BufferLen);
184 
185    std::size_t free_memory_before = m.get_free_memory();
186 
187    for(int i = 0; true; ++i){
188       formatter.seekp(0);
189       formatter << get_prefix(char_type()) << i << std::ends;
190 
191       char *ptr = m.template construct<char>(name, std::nothrow)(i);
192 
193       if(!ptr)
194          break;
195       buffers.push_back(ptr);
196    }
197 
198    for(int j = 0, max = (int)buffers.size()
199       ;j < max
200       ;++j){
201       m.destroy_ptr(buffers[j]);
202    }
203 
204    std::size_t free_memory_after = m.get_free_memory();
205 
206    if(free_memory_before != free_memory_after){
207       m.shrink_to_fit_indexes();
208       if(free_memory_before != free_memory_after)
209          return false;
210    }
211    return true;
212 }
213 
214 //This test allocates until there is no more memory
215 //and after that deallocates all in the same order
216 template<class ManagedMemory>
test_direct_named_allocation_destruction(ManagedMemory & m)217 bool test_direct_named_allocation_destruction(ManagedMemory &m)
218 {
219    typedef typename ManagedMemory::char_type char_type;
220    std::vector<char*> buffers;
221    const int BufferLen = 100;
222    char_type name[BufferLen];
223 
224    basic_bufferstream<char_type> formatter(name, BufferLen);
225 
226    for(int i = 0; true; ++i){
227       formatter.seekp(0);
228       formatter << get_prefix(char_type()) << i << std::ends;
229       char *ptr = m.template construct<char>(name, std::nothrow)(i);
230       if(!ptr)
231          break;
232       if(m.template find<char>(name).first == 0)
233          return false;
234       buffers.push_back(ptr);
235    }
236 
237    if(m.get_num_named_objects() != buffers.size() || !m.check_sanity())
238       return false;
239 
240    for(int j = 0, max = (int)buffers.size()
241       ;j < max
242       ;++j){
243       m.destroy_ptr(buffers[j]);
244    }
245 
246    if(m.get_num_named_objects() != 0 || !m.check_sanity())
247       return false;
248    m.shrink_to_fit_indexes();
249    if(!m.all_memory_deallocated())
250       return false;
251    return true;
252 }
253 
254 //This test allocates until there is no more memory
255 //and after that deallocates all in the inverse order
256 template<class ManagedMemory>
test_named_allocation_inverse_destruction(ManagedMemory & m)257 bool test_named_allocation_inverse_destruction(ManagedMemory &m)
258 {
259    typedef typename ManagedMemory::char_type char_type;
260 
261    std::vector<char*> buffers;
262    const int BufferLen = 100;
263    char_type name[BufferLen];
264 
265    basic_bufferstream<char_type> formatter(name, BufferLen);
266 
267    for(int i = 0; true; ++i){
268       formatter.seekp(0);
269       formatter << get_prefix(char_type()) << i << std::ends;
270       char *ptr = m.template construct<char>(name, std::nothrow)(i);
271       if(!ptr)
272          break;
273       buffers.push_back(ptr);
274    }
275 
276    if(m.get_num_named_objects() != buffers.size() || !m.check_sanity())
277       return false;
278 
279    for(int j = (int)buffers.size()
280       ;j--
281       ;){
282       m.destroy_ptr(buffers[j]);
283    }
284 
285    if(m.get_num_named_objects() != 0 || !m.check_sanity())
286       return false;
287    m.shrink_to_fit_indexes();
288    if(!m.all_memory_deallocated())
289       return false;
290    return true;
291 }
292 
293 //This test allocates until there is no more memory
294 //and after that deallocates all following a pattern
295 template<class ManagedMemory>
test_named_allocation_mixed_destruction(ManagedMemory & m)296 bool test_named_allocation_mixed_destruction(ManagedMemory &m)
297 {
298    typedef typename ManagedMemory::char_type char_type;
299 
300    std::vector<char*> buffers;
301    const int BufferLen = 100;
302    char_type name[BufferLen];
303 
304    basic_bufferstream<char_type> formatter(name, BufferLen);
305 
306    for(int i = 0; true; ++i){
307       formatter.seekp(0);
308       formatter << get_prefix(char_type()) << i << std::ends;
309       char *ptr = m.template construct<char>(name, std::nothrow)(i);
310       if(!ptr)
311          break;
312       buffers.push_back(ptr);
313    }
314 
315    if(m.get_num_named_objects() != buffers.size() || !m.check_sanity())
316       return false;
317 
318    for(int j = 0, max = (int)buffers.size()
319       ;j < max
320       ;++j){
321       int pos = (j%4)*((int)buffers.size())/4;
322       m.destroy_ptr(buffers[pos]);
323       buffers.erase(buffers.begin()+pos);
324    }
325 
326    if(m.get_num_named_objects() != 0 || !m.check_sanity())
327       return false;
328    m.shrink_to_fit_indexes();
329    if(!m.all_memory_deallocated())
330       return false;
331    return true;
332 }
333 
334 //This test allocates until there is no more memory
335 //and after that deallocates all in the same order
336 template<class ManagedMemory>
test_inverse_named_allocation_destruction(ManagedMemory & m)337 bool test_inverse_named_allocation_destruction(ManagedMemory &m)
338 {
339    typedef typename ManagedMemory::char_type char_type;
340 
341    std::vector<char*> buffers;
342    const int BufferLen = 100;
343    char_type name[BufferLen];
344 
345    basic_bufferstream<char_type> formatter(name, BufferLen);
346 
347    for(unsigned int i = 0; true; ++i){
348       formatter.seekp(0);
349       formatter << get_prefix(char_type()) << i << std::ends;
350       char *ptr = m.template construct<char>(name, std::nothrow)(i);
351       if(!ptr)
352          break;
353       buffers.push_back(ptr);
354    }
355 
356    if(m.get_num_named_objects() != buffers.size() || !m.check_sanity())
357       return false;
358 
359    for(unsigned int j = 0, max = (unsigned int)buffers.size()
360       ;j < max
361       ;++j){
362       m.destroy_ptr(buffers[j]);
363    }
364 
365    if(m.get_num_named_objects() != 0 || !m.check_sanity())
366       return false;
367    m.shrink_to_fit_indexes();
368    if(!m.all_memory_deallocated())
369       return false;
370    return true;
371 }
372 
373 ///This function calls all tests
374 template<class ManagedMemory>
test_all_named_allocation(ManagedMemory & m)375 bool test_all_named_allocation(ManagedMemory &m)
376 {
377    std::cout << "Starting test_names_and_types. Class: "
378              << typeid(m).name() << std::endl;
379 
380    if(!test_names_and_types(m)){
381       std::cout << "test_names_and_types failed. Class: "
382                 << typeid(m).name() << std::endl;
383       return false;
384    }
385 
386    std::cout << "Starting test_direct_named_allocation_destruction. Class: "
387              << typeid(m).name() << std::endl;
388 
389    if(!test_direct_named_allocation_destruction(m)){
390       std::cout << "test_direct_named_allocation_destruction failed. Class: "
391                 << typeid(m).name() << std::endl;
392       return false;
393    }
394 
395    std::cout << "Starting test_named_allocation_inverse_destruction. Class: "
396              << typeid(m).name() << std::endl;
397 
398    if(!test_named_allocation_inverse_destruction(m)){
399       std::cout << "test_named_allocation_inverse_destruction failed. Class: "
400                 << typeid(m).name() << std::endl;
401       return false;
402    }
403 
404    std::cout << "Starting test_named_allocation_mixed_destruction. Class: "
405              << typeid(m).name() << std::endl;
406 
407    if(!test_named_allocation_mixed_destruction(m)){
408       std::cout << "test_named_allocation_mixed_destruction failed. Class: "
409                 << typeid(m).name() << std::endl;
410       return false;
411    }
412 
413    std::cout << "Starting test_inverse_named_allocation_destruction. Class: "
414              << typeid(m).name() << std::endl;
415 
416    if(!test_inverse_named_allocation_destruction(m)){
417       std::cout << "test_inverse_named_allocation_destruction failed. Class: "
418                 << typeid(m).name() << std::endl;
419       return false;
420    }
421 
422    if(!test_named_iterators(m)){
423       std::cout << "test_named_iterators failed. Class: "
424                 << typeid(m).name() << std::endl;
425       return false;
426    }
427 
428    return true;
429 }
430 
431 //This function calls all tests
432 template<template <class IndexConfig> class Index>
test_named_allocation()433 bool test_named_allocation()
434 {
435    using namespace boost::interprocess;
436 
437    const int memsize = 163840;
438    const char *const shMemName = test::get_process_id_name();
439    try
440    {
441       //A shared memory with rbtree best fit algorithm
442       typedef basic_managed_shared_memory
443          <char
444          ,rbtree_best_fit<mutex_family>
445          ,Index
446          > my_managed_shared_memory;
447 
448       //Create shared memory
449       shared_memory_object::remove(shMemName);
450       my_managed_shared_memory segment(create_only, shMemName, memsize);
451 
452       //Now take the segment manager and launch memory test
453       if(!test::test_all_named_allocation(*segment.get_segment_manager())){
454          return false;
455       }
456    }
457    catch(...){
458       shared_memory_object::remove(shMemName);
459       throw;
460    }
461    shared_memory_object::remove(shMemName);
462 
463    //Now test it with wchar_t
464    try
465    {
466       //A shared memory with simple sequential fit algorithm
467       typedef basic_managed_shared_memory
468          <wchar_t
469          ,rbtree_best_fit<mutex_family>
470          ,Index
471          > my_managed_shared_memory;
472 
473       //Create shared memory
474       shared_memory_object::remove(shMemName);
475       my_managed_shared_memory segment(create_only, shMemName, memsize);
476 
477       //Now take the segment manager and launch memory test
478       if(!test::test_all_named_allocation(*segment.get_segment_manager())){
479          return false;
480       }
481    }
482    catch(...){
483       shared_memory_object::remove(shMemName);
484       throw;
485    }
486    shared_memory_object::remove(shMemName);
487 
488    return true;
489 }
490 
491 }}}   //namespace boost { namespace interprocess { namespace test {
492 
493 #include <boost/interprocess/detail/config_end.hpp>
494 
495 #endif   //BOOST_INTERPROCESS_NAMED_ALLOCATION_TEST_TEMPLATE_HEADER
496