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