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