ACE+TAO-7_0_8
[ACE_TAO.git] / ACE / tests / Malloc_Test.cpp
blob037e5744ddb46909e6d3e13b33891eccdd1922fa
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 "ace/Auto_Ptr.h"
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) && !defined (ACE_OPENVMS) \
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 && !defined (HPUX))
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)
95 #if defined (ACE_HAS_WINCE) || defined (ACE_OPENVMS)
96 // WinCE cannot do fixed base, ever.
97 ACE_UNUSED_ARG (base_addr);
98 ACE_MMAP_Memory_Pool_Options options
99 (0,
100 ACE_MMAP_Memory_Pool_Options::NEVER_FIXED);
101 #else
102 ACE_MMAP_Memory_Pool_Options options (base_addr);
103 #endif /* ACE_HAS_WINCE */
105 #if !defined (ACE_TEST_REMAP_ON_FAULT)
106 options.minimum_bytes_ = 512 * 1024;
107 #endif /* ACE_TEST_REMAP_ON_FAULT */
109 MALLOC *ptr = new MALLOC (MMAP_FILENAME,
110 MUTEX_NAME,
111 &options);
112 static_allocator.reset (ptr);
114 return static_allocator.get ();
117 static void
118 init_test (const void *base_addr = 0)
120 // Cleanup the MMAP file so we won't trip over the leftover mmap
121 // file from the previous crash.
122 #if defined (ACE_HAS_WINCE) || defined (ACE_OPENVMS)
123 // WinCE cannot do fixed base, ever.
124 ACE_UNUSED_ARG (base_addr);
125 ACE_MMAP_Memory_Pool_Options options
127 ACE_MMAP_Memory_Pool_Options::NEVER_FIXED);
128 #else
129 ACE_MMAP_Memory_Pool_Options options (base_addr);
130 #endif /* ACE_HAS_WINCE */
131 //FUZZ: disable check_for_lack_ACE_OS
132 ACE_MMAP_Memory_Pool mmap (MMAP_FILENAME, &options);
133 //FUZZ: enable check_for_lack_ACE_OS
135 size_t rbyte = 0;
136 int ft = 0;
137 mmap.init_acquire (1024, rbyte, ft);
138 mmap.release ();
141 static Test_Data *
142 initialize (MALLOC *allocator)
144 double *temp = 0;
145 ACE_ALLOCATOR_RETURN (temp,
146 (double *) allocator->malloc (sizeof (double)),
148 // Make sure that doubles work!
149 *temp = 5.0;
150 allocator->free (temp);
152 void *ptr = 0;
153 ACE_ALLOCATOR_RETURN (ptr,
154 allocator->malloc (sizeof (Test_Data)),
156 Test_Data *data1 = new (ptr) Test_Data;
158 data1->i1_ = 111;
159 data1->i2_ = 222;
160 data1->i3_ = 333;
161 data1->d1_ = 87.5;
163 void *gap = 0;
164 ACE_ALLOCATOR_RETURN (gap,
165 allocator->malloc (sizeof (256)),
167 allocator->free (gap);
170 ACE_ALLOCATOR_RETURN (ptr,
171 allocator->malloc (sizeof (Test_Data)),
173 Test_Data *data2 = new (ptr) Test_Data;
175 data1->next_ = 0;
176 data2->next_ = data1;
177 data2->i1_ = -111;
178 data2->i2_ = -222;
179 data2->i3_ = -333;
180 data2->d1_ = 77.34;
182 // Test in shared memory using long (array/pointer)
183 ACE_ALLOCATOR_RETURN (ptr,
184 allocator->malloc (sizeof (Long_Test)),
186 Long_Test *lt = new (ptr) Long_Test;
188 lt->array_[0] = 1000;
189 lt->array_[1] = 1001;
190 lt->array_[2] = 1002;
191 lt->array_[3] = 1003;
192 lt->array_[4] = 1004;
193 lt->bpl_ = lt->array_;
195 data1->long_test_= lt;
197 long long_cont_1 = *lt->bpl_;
198 long long_cont_2 = lt->bpl_[3];
200 ACE_TEST_ASSERT (long_cont_1 == 1000);
201 ACE_TEST_ASSERT (long_cont_2 == 1003);
203 ACE_ALLOCATOR_RETURN (ptr,
204 allocator->malloc (sizeof (Long_Test)),
206 lt = new (ptr) Long_Test;
208 lt->array_[0] = 2000;
209 lt->array_[1] = 2001;
210 lt->array_[2] = 2002;
211 lt->array_[3] = 2003;
212 lt->array_[4] = 2004;
213 lt->bpl_ = lt->array_;
215 data2->long_test_= lt;
217 long long_cont_3 = *lt->bpl_;
218 long long_cont_4 = lt->bpl_[4];
220 ACE_TEST_ASSERT (long_cont_3 == 2000);
221 ACE_TEST_ASSERT (long_cont_4 == 2004);
223 return data2;
226 static void
227 print (const char *process_name,
228 Test_Data *data)
230 for (Test_Data *t = data; t != 0; t = t->next_)
232 ACE_DEBUG ((LM_DEBUG,
233 ACE_TEXT ("<<<< (%P) %C\ni1_ = %d, i2_ = %d, i3_ = %d, d1_ = %f\n"),
234 process_name,
235 t->i1_,
236 t->i2_,
237 t->i3_,
238 t->d1_));
239 ACE_DEBUG ((LM_DEBUG,
240 ACE_TEXT ("*t->bpl_ = %d, t->long_test_->array_[0] = ")
241 ACE_TEXT ("%d\n>>>>\n"),
242 *t->long_test_->bpl_,
243 t->long_test_->array_[0]));
247 static int
248 parent (Test_Data *data)
250 MALLOC *myalloc = myallocator ();
253 ACE_GUARD_RETURN (ACE_Process_Mutex, guard, myalloc->mutex (), -1);
254 print ("parent", data);
257 // Sleep for a 200 msecs so that the child will have a chance to spin!
258 ACE_OS::sleep (ACE_Time_Value (0, 200 * 1000));
260 #if defined (ACE_TEST_REMAP_ON_FAULT)
261 char *small_buf[1024];
262 int cntr;
264 for (cntr = 0 ; cntr < 1024; ++cntr)
265 small_buf[cntr] = (char *) myalloc->malloc (1);
266 char *big_buf = (char *) myalloc->malloc (1024 * 4069);
267 #endif /* ACE_TEST_REMAP_ON_FAULT */
269 int result = myalloc->bind ("bar", data);
271 #if defined (ACE_TEST_REMAP_ON_FAULT)
272 myalloc->free (big_buf);
273 for (cntr = 0 ; cntr < 1024; ++cntr)
274 myalloc->free (small_buf[cntr]);
275 #endif /* ACE_TEST_REMAP_ON_FAULT */
277 ACE_TEST_ASSERT (result != -1);
278 return 0;
281 static int
282 child ()
284 void *bar = 0;
285 // Perform "busy waiting" here until the parent stores data under a
286 // new name called "bar" in <ACE_Malloc>. This isn't a good design
287 // -- it's just to test that synchronization is working across
288 // processes via <ACE_Malloc>.
289 for (ACE_Time_Value timeout (0, 1000 * 10);
290 myallocator ()->find ("bar",
291 bar) == -1;
294 ACE_DEBUG ((LM_DEBUG,
295 ACE_TEXT ("(%P) sleeping for 10 milliseconds!\n")));
296 ACE_OS::sleep (timeout);
299 print ("child",
300 reinterpret_cast<Test_Data *> (bar));
301 return 0;
304 #if defined (ACE_HAS_WIN32_GETVERSION)
305 // On Win9x/Me, a shared address needs to be on the shared arena,
306 // between the second and third megabyte in the virtual address space
307 // of the process. Also, a mapped view of a file is shared on the same
308 // virtual address on every 32 bit process. On WinNT/2k, memory above
309 // 2Gb is reserved for the system. So, we need to check at runtime
310 // (we want an ACE_HAS_WINNT4 == 0 ace to run on either).
311 // To catch any odd case arising from Pharlap and/or WinCE, do the
312 // run time check and run the NT4-or-better code unless we're on
313 // CE or something other than NT4 (Pharlap reports itself as NT 3.51).
314 static void
315 get_base_addrs (void)
317 # if defined(__clang__)
318 # pragma clang diagnostic push
319 # pragma clang diagnostic ignored "-Wdeprecated-declarations"
320 # endif /* __clang__ */
321 OSVERSIONINFO vinfo;
322 vinfo.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
323 if (::GetVersionEx(&vinfo) == 0)
324 return;
325 # if defined(__clang__)
326 # pragma clang diagnostic pop
327 # endif /* __clang__ */
329 if (vinfo.dwPlatformId == VER_PLATFORM_WIN32_NT &&
330 vinfo.dwMajorVersion >= 4)
331 PARENT_BASE_ADDR = (char*) (64 * 1024*1024);
332 else
333 PARENT_BASE_ADDR = (char*) ((2048UL + 512UL)*(1024UL*1024UL));
335 CHILD_BASE_ADDR = CHILD_ADDR_DELTA + (char*) PARENT_BASE_ADDR;
337 #endif /* defined (ACE_HAS_WIN32_GETVERSION) */
340 run_main (int argc, ACE_TCHAR *argv[])
342 #if defined (ACE_HAS_WIN32_GETVERSION)
343 get_base_addrs();
344 #endif
346 if (argc == 1)
348 ACE_START_TEST (ACE_TEXT ("Malloc_Test"));
349 ACE_INIT_LOG (ACE_TEXT ("Malloc_Test-child"));
351 init_test (PARENT_BASE_ADDR);
353 ACE_Control_Block::print_alignment_info ();
354 # if (ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1)
355 ACE_PI_Control_Block::print_alignment_info ();
356 # endif /* ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1 */
358 // No arguments means we're the parent process.
359 ACE_Process_Options options (1);
361 #if !defined (ACE_WIN32) && defined (ACE_USES_WCHAR)
362 static const ACE_TCHAR* format = ACE_TEXT ("%ls%ls%ls");
363 #else
364 static const ACE_TCHAR* format = ACE_TEXT ("%s%s%s");
365 #endif /* !ACE_WIN32 && ACE_USES_WCHAR */
366 options.command_line (format, EXE_LOCATION,
367 argc > 0 ? argv[0] : ACE_TEXT ("Malloc_Test"),
368 ACE_TEXT (" run_as_test"));
370 MALLOC *myalloc = myallocator (PARENT_BASE_ADDR);
372 Test_Data *data = initialize (myalloc);
373 ACE_TEST_ASSERT (data != 0);
375 ACE_DEBUG ((LM_DEBUG,
376 ACE_TEXT ("(%P) PARENT allocator at = %@, ")
377 ACE_TEXT ("data allocated at %@\n"),
378 myalloc,
379 data));
380 myalloc->dump ();
381 int result = myalloc->bind ("foo", data);
382 ACE_TEST_ASSERT (result != -1);
384 ACE_Process p;
385 pid_t pid = p.spawn (options);
386 if (pid == -1)
387 ACE_ERROR_RETURN ((LM_ERROR,
388 ACE_TEXT ("%p\n"),
389 ACE_TEXT ("spawn")), 1);
391 parent (data);
393 // Synchronize on the exit of the child.
394 result = p.wait ();
395 if (result == -1)
396 ACE_ERROR_RETURN ((LM_ERROR,
397 ACE_TEXT ("%p\n"),
398 ACE_TEXT ("wait")), 1);
399 ACE_TEST_ASSERT (myalloc->ref_counter () == 1);
400 myalloc->remove ();
401 ACE_Process_Mutex::unlink (MUTEX_NAME);
402 ACE_END_TEST;
403 return 0;
405 else
407 // In this case we're the child process.
408 ACE_APPEND_LOG (ACE_TEXT ("Malloc_Test-child"));
410 void *data = 0;
411 MALLOC *myalloc = myallocator (CHILD_BASE_ADDR);
412 int result = myalloc->find ("foo", data);
413 ACE_TEST_ASSERT (result != -1);
415 ACE_DEBUG ((LM_DEBUG,
416 ACE_TEXT ("(%P) CHILD allocator at = %@, ")
417 ACE_TEXT ("data allocated at %@\n"),
418 myalloc,
419 data));
420 myalloc->dump ();
421 child ();
422 myalloc->release ();
423 ACE_END_LOG;
424 return 0;
428 #else
430 run_main (int, ACE_TCHAR *[])
432 ACE_START_TEST (ACE_TEXT ("Malloc_Test"));
433 ACE_ERROR ((LM_INFO,
434 ACE_TEXT ("process creation is not supported on this ")
435 ACE_TEXT ("platform\n")));
436 ACE_END_TEST;
437 return 0;
439 #endif /* ACE_HAS_PROCESS_SPAWN */