Merge pull request #2301 from sonndinh/remove-dup-reactor-functions
[ACE_TAO.git] / ACE / tests / Malloc_Test.cpp
blob2240e1648fe443ee0394ad9104030ea2f1bc3923
2 //=============================================================================
3 /**
4 * @file Malloc_Test.cpp
6 * This is a test of the position-independent <ACE_Malloc> memory
7 * manager using the <ACE_MMAP_Memory_Pool> and <ACE_Process_Mutex>.
9 * @author Douglas C. Schmidt <d.schmidt@vanderbilt.edu>
11 //=============================================================================
14 #include "test_config.h"
15 #include "Malloc_Test.h"
17 #include "ace/Malloc_T.h"
18 #include "ace/MMAP_Memory_Pool.h"
19 #include "ace/Process.h"
20 #include <memory>
21 #include "ace/Process_Mutex.h"
22 #include "ace/PI_Malloc.h"
23 #include "ace/RW_Thread_Mutex.h"
24 #include "ace/Time_Value.h"
25 #include "ace/OS_NS_unistd.h"
28 #if defined (ACE_HAS_PROCESS_SPAWN)
30 #if (ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1)
31 using MALLOC = ACE_Malloc_T<ACE_MMAP_Memory_Pool, ACE_Process_Mutex, ACE_PI_Control_Block>;
32 #else
33 typedef ACE_Malloc<ACE_MMAP_MEMORY_POOL, ACE_Process_Mutex> MALLOC;
34 #endif /* ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1 */
35 #define MMAP_FILENAME ACE_TEXT ("test_file")
36 #define MUTEX_NAME ACE_TEXT ("test_lock")
38 #if !defined (ACE_LINUX) \
39 && !defined (ACE_ANDROID) \
40 && !(defined (ACE_WIN32) \
41 && (defined (ghs) || defined (__MINGW32__) )) \
42 && !(defined (__OpenBSD__) && defined (ACE_HAS_PTHREADS))
43 #define ACE_TEST_REMAP_ON_FAULT
44 // Linux seems to have problem when calling mmap from the signal handler.
45 // The Green Hills Native x86 compiler does not support structural exceptions.
46 // Mingw's gcc does not support structural exceptions.
47 // Win9x doesn't support remaps.
48 // OpenBSD causes this test to hang in the child when pthreads are enabled.
49 // On these platforms, we make sure the remapping will never occur.
50 #endif /* ACE_LINUX && Win32 GHS*/
52 #if defined (ACE_WIN32)
53 // When looking for the file to execute a process on Win32, the directory from
54 // containing the parent process file is searched first. Since certain Win32
55 // configurations (e.g. Borland C++Builder) put the output files in a different
56 // directory we will use this feature rather than specifying '.\'.
57 # define EXE_LOCATION ACE_TEXT ("")
58 #else
59 # define EXE_LOCATION ACE_TEXT (".") ACE_DIRECTORY_SEPARATOR_STR
60 #endif /*ACE_WIN32*/
62 // Parents <ACE_Malloc> base address in shared memory.
63 static const void *PARENT_BASE_ADDR = ACE_DEFAULT_BASE_ADDR;
65 // If the platform supports position-independent malloc, choose
66 // another base address that's 1M higher so that <ACE_Malloc> will be
67 // mapped into a different address in the child's virtual memory.
68 // Note that on HP-UX on PA-RISC hardware, a single range of a file
69 // cannot be mapped into multiple virtual address ranges, even across
70 // processes. So, though the whole PI pointer thing is tested here,
71 // it isn't actually using multiple address ranges.
73 #if (ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1)
74 # define CHILD_ADDR_DELTA (1024*1024)
75 #else
76 # define CHILD_ADDR_DELTA 0
77 #endif /* CHILD_ADDR_DELTA */
79 static const void *CHILD_BASE_ADDR =
80 (const void *)(CHILD_ADDR_DELTA + ACE_DEFAULT_BASE_ADDR);
82 // Shared memory allocator. Hide the allocator inside this function
83 // so that it doesn't get constructed until after the
84 // <ACE_Object_Manager> gets constructed, even with
85 // <ACE_HAS_NONSTATIC_OBJECT_MANAGER>.
87 static MALLOC *
88 myallocator (const void *base_addr = 0)
90 static std::unique_ptr<MALLOC> static_allocator;
92 if (static_allocator.get () == 0)
94 ACE_MMAP_Memory_Pool_Options options (base_addr);
96 #if !defined (ACE_TEST_REMAP_ON_FAULT)
97 options.minimum_bytes_ = 512 * 1024;
98 #endif /* ACE_TEST_REMAP_ON_FAULT */
100 MALLOC *ptr = new MALLOC (MMAP_FILENAME,
101 MUTEX_NAME,
102 &options);
103 static_allocator.reset (ptr);
105 return static_allocator.get ();
108 static void
109 init_test (const void *base_addr = 0)
111 // Cleanup the MMAP file so we won't trip over the leftover mmap
112 // file from the previous crash.
113 ACE_MMAP_Memory_Pool_Options options (base_addr);
114 //FUZZ: disable check_for_lack_ACE_OS
115 ACE_MMAP_Memory_Pool mmap (MMAP_FILENAME, &options);
116 //FUZZ: enable check_for_lack_ACE_OS
118 size_t rbyte = 0;
119 int ft = 0;
120 mmap.init_acquire (1024, rbyte, ft);
121 mmap.release ();
124 static Test_Data *
125 initialize (MALLOC *allocator)
127 double *temp = 0;
128 ACE_ALLOCATOR_RETURN (temp,
129 (double *) allocator->malloc (sizeof (double)),
131 // Make sure that doubles work!
132 *temp = 5.0;
133 allocator->free (temp);
135 void *ptr = 0;
136 ACE_ALLOCATOR_RETURN (ptr,
137 allocator->malloc (sizeof (Test_Data)),
139 Test_Data *data1 = new (ptr) Test_Data;
141 data1->i1_ = 111;
142 data1->i2_ = 222;
143 data1->i3_ = 333;
144 data1->d1_ = 87.5;
146 void *gap = 0;
147 ACE_ALLOCATOR_RETURN (gap,
148 allocator->malloc (sizeof (256)),
150 allocator->free (gap);
153 ACE_ALLOCATOR_RETURN (ptr,
154 allocator->malloc (sizeof (Test_Data)),
156 Test_Data *data2 = new (ptr) Test_Data;
158 data1->next_ = 0;
159 data2->next_ = data1;
160 data2->i1_ = -111;
161 data2->i2_ = -222;
162 data2->i3_ = -333;
163 data2->d1_ = 77.34;
165 // Test in shared memory using long (array/pointer)
166 ACE_ALLOCATOR_RETURN (ptr,
167 allocator->malloc (sizeof (Long_Test)),
169 Long_Test *lt = new (ptr) Long_Test;
171 lt->array_[0] = 1000;
172 lt->array_[1] = 1001;
173 lt->array_[2] = 1002;
174 lt->array_[3] = 1003;
175 lt->array_[4] = 1004;
176 lt->bpl_ = lt->array_;
178 data1->long_test_= lt;
180 long long_cont_1 = *lt->bpl_;
181 long long_cont_2 = lt->bpl_[3];
183 ACE_TEST_ASSERT (long_cont_1 == 1000);
184 ACE_TEST_ASSERT (long_cont_2 == 1003);
186 ACE_ALLOCATOR_RETURN (ptr,
187 allocator->malloc (sizeof (Long_Test)),
189 lt = new (ptr) Long_Test;
191 lt->array_[0] = 2000;
192 lt->array_[1] = 2001;
193 lt->array_[2] = 2002;
194 lt->array_[3] = 2003;
195 lt->array_[4] = 2004;
196 lt->bpl_ = lt->array_;
198 data2->long_test_= lt;
200 long long_cont_3 = *lt->bpl_;
201 long long_cont_4 = lt->bpl_[4];
203 ACE_TEST_ASSERT (long_cont_3 == 2000);
204 ACE_TEST_ASSERT (long_cont_4 == 2004);
206 return data2;
209 static void
210 print (const char *process_name,
211 Test_Data *data)
213 for (Test_Data *t = data; t != 0; t = t->next_)
215 ACE_DEBUG ((LM_DEBUG,
216 ACE_TEXT ("<<<< (%P) %C\ni1_ = %d, i2_ = %d, i3_ = %d, d1_ = %f\n"),
217 process_name,
218 t->i1_,
219 t->i2_,
220 t->i3_,
221 t->d1_));
222 ACE_DEBUG ((LM_DEBUG,
223 ACE_TEXT ("*t->bpl_ = %d, t->long_test_->array_[0] = ")
224 ACE_TEXT ("%d\n>>>>\n"),
225 *t->long_test_->bpl_,
226 t->long_test_->array_[0]));
230 static int
231 parent (Test_Data *data)
233 MALLOC *myalloc = myallocator ();
236 ACE_GUARD_RETURN (ACE_Process_Mutex, guard, myalloc->mutex (), -1);
237 print ("parent", data);
240 // Sleep for a 200 msecs so that the child will have a chance to spin!
241 ACE_OS::sleep (ACE_Time_Value (0, 200 * 1000));
243 #if defined (ACE_TEST_REMAP_ON_FAULT)
244 char *small_buf[1024];
245 int cntr;
247 for (cntr = 0 ; cntr < 1024; ++cntr)
248 small_buf[cntr] = (char *) myalloc->malloc (1);
249 char *big_buf = (char *) myalloc->malloc (1024 * 4069);
250 #endif /* ACE_TEST_REMAP_ON_FAULT */
252 int result = myalloc->bind ("bar", data);
254 #if defined (ACE_TEST_REMAP_ON_FAULT)
255 myalloc->free (big_buf);
256 for (cntr = 0 ; cntr < 1024; ++cntr)
257 myalloc->free (small_buf[cntr]);
258 #endif /* ACE_TEST_REMAP_ON_FAULT */
260 ACE_TEST_ASSERT (result != -1);
261 return 0;
264 static int
265 child ()
267 void *bar = 0;
268 // Perform "busy waiting" here until the parent stores data under a
269 // new name called "bar" in <ACE_Malloc>. This isn't a good design
270 // -- it's just to test that synchronization is working across
271 // processes via <ACE_Malloc>.
272 for (ACE_Time_Value timeout (0, 1000 * 10);
273 myallocator ()->find ("bar",
274 bar) == -1;
277 ACE_DEBUG ((LM_DEBUG,
278 ACE_TEXT ("(%P) sleeping for 10 milliseconds!\n")));
279 ACE_OS::sleep (timeout);
282 print ("child",
283 reinterpret_cast<Test_Data *> (bar));
284 return 0;
287 #if defined (ACE_HAS_WIN32_GETVERSION)
288 // On Win9x/Me, a shared address needs to be on the shared arena,
289 // between the second and third megabyte in the virtual address space
290 // of the process. Also, a mapped view of a file is shared on the same
291 // virtual address on every 32 bit process. On WinNT/2k, memory above
292 // 2Gb is reserved for the system. So, we need to check at runtime
293 // (we want an ACE_HAS_WINNT4 == 0 ace to run on either).
294 // To catch any odd case arising from Pharlap, do the
295 // run time check and run the NT4-or-better code unless we're on
296 // CE or something other than NT4 (Pharlap reports itself as NT 3.51).
297 static void
298 get_base_addrs ()
300 # if defined(__clang__)
301 # pragma clang diagnostic push
302 # pragma clang diagnostic ignored "-Wdeprecated-declarations"
303 # endif /* __clang__ */
304 OSVERSIONINFO vinfo;
305 vinfo.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
306 if (::GetVersionEx(&vinfo) == 0)
307 return;
308 # if defined(__clang__)
309 # pragma clang diagnostic pop
310 # endif /* __clang__ */
312 if (vinfo.dwPlatformId == VER_PLATFORM_WIN32_NT &&
313 vinfo.dwMajorVersion >= 4)
314 PARENT_BASE_ADDR = (char*) (64 * 1024*1024);
315 else
316 PARENT_BASE_ADDR = (char*) ((2048UL + 512UL)*(1024UL*1024UL));
318 CHILD_BASE_ADDR = CHILD_ADDR_DELTA + (char*) PARENT_BASE_ADDR;
320 #endif /* defined (ACE_HAS_WIN32_GETVERSION) */
323 run_main (int argc, ACE_TCHAR *argv[])
325 #if defined (ACE_HAS_WIN32_GETVERSION)
326 get_base_addrs();
327 #endif
329 if (argc == 1)
331 ACE_START_TEST (ACE_TEXT ("Malloc_Test"));
332 ACE_INIT_LOG (ACE_TEXT ("Malloc_Test-child"));
334 init_test (PARENT_BASE_ADDR);
336 ACE_Control_Block::print_alignment_info ();
337 # if (ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1)
338 ACE_PI_Control_Block::print_alignment_info ();
339 # endif /* ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1 */
341 // No arguments means we're the parent process.
342 ACE_Process_Options options (1);
344 options.command_line (ACE_TEXT ("%") ACE_TEXT_PRIs
345 ACE_TEXT ("%") ACE_TEXT_PRIs
346 ACE_TEXT ("%") ACE_TEXT_PRIs,
347 EXE_LOCATION,
348 argc > 0 ? argv[0] : ACE_TEXT ("Malloc_Test"),
349 ACE_TEXT (" run_as_test"));
351 MALLOC *myalloc = myallocator (PARENT_BASE_ADDR);
353 Test_Data *data = initialize (myalloc);
354 ACE_TEST_ASSERT (data != 0);
356 ACE_DEBUG ((LM_DEBUG,
357 ACE_TEXT ("(%P) PARENT allocator at = %@, ")
358 ACE_TEXT ("data allocated at %@\n"),
359 myalloc,
360 data));
361 myalloc->dump ();
362 int result = myalloc->bind ("foo", data);
363 ACE_TEST_ASSERT (result != -1);
365 ACE_Process p;
366 pid_t pid = p.spawn (options);
367 if (pid == -1)
368 ACE_ERROR_RETURN ((LM_ERROR,
369 ACE_TEXT ("%p\n"),
370 ACE_TEXT ("spawn")), 1);
372 parent (data);
374 // Synchronize on the exit of the child.
375 result = p.wait ();
376 if (result == -1)
377 ACE_ERROR_RETURN ((LM_ERROR,
378 ACE_TEXT ("%p\n"),
379 ACE_TEXT ("wait")), 1);
380 ACE_TEST_ASSERT (myalloc->ref_counter () == 1);
381 myalloc->remove ();
382 ACE_Process_Mutex::unlink (MUTEX_NAME);
383 ACE_END_TEST;
384 return 0;
386 else
388 // In this case we're the child process.
389 ACE_APPEND_LOG (ACE_TEXT ("Malloc_Test-child"));
391 void *data = 0;
392 MALLOC *myalloc = myallocator (CHILD_BASE_ADDR);
393 int result = myalloc->find ("foo", data);
394 ACE_TEST_ASSERT (result != -1);
396 ACE_DEBUG ((LM_DEBUG,
397 ACE_TEXT ("(%P) CHILD allocator at = %@, ")
398 ACE_TEXT ("data allocated at %@\n"),
399 myalloc,
400 data));
401 myalloc->dump ();
402 child ();
403 myalloc->release ();
404 ACE_END_LOG;
405 return 0;
409 #else
411 run_main (int, ACE_TCHAR *[])
413 ACE_START_TEST (ACE_TEXT ("Malloc_Test"));
414 ACE_ERROR ((LM_INFO,
415 ACE_TEXT ("process creation is not supported on this ")
416 ACE_TEXT ("platform\n")));
417 ACE_END_TEST;
418 return 0;
420 #endif /* ACE_HAS_PROCESS_SPAWN */