2 //=============================================================================
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
>;
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 ("")
59 # define EXE_LOCATION ACE_TEXT (".") ACE_DIRECTORY_SEPARATOR_STR
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)
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>.
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
100 ACE_MMAP_Memory_Pool_Options::NEVER_FIXED
);
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
,
112 static_allocator
.reset (ptr
);
114 return static_allocator
.get ();
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
);
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
137 mmap
.init_acquire (1024, rbyte
, ft
);
142 initialize (MALLOC
*allocator
)
145 ACE_ALLOCATOR_RETURN (temp
,
146 (double *) allocator
->malloc (sizeof (double)),
148 // Make sure that doubles work!
150 allocator
->free (temp
);
153 ACE_ALLOCATOR_RETURN (ptr
,
154 allocator
->malloc (sizeof (Test_Data
)),
156 Test_Data
*data1
= new (ptr
) Test_Data
;
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
;
176 data2
->next_
= data1
;
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);
227 print (const char *process_name
,
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"),
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]));
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];
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);
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",
294 ACE_DEBUG ((LM_DEBUG
,
295 ACE_TEXT ("(%P) sleeping for 10 milliseconds!\n")));
296 ACE_OS::sleep (timeout
);
300 reinterpret_cast<Test_Data
*> (bar
));
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).
315 get_base_addrs (void)
317 # if defined(__clang__)
318 # pragma clang diagnostic push
319 # pragma clang diagnostic ignored "-Wdeprecated-declarations"
320 # endif /* __clang__ */
322 vinfo
.dwOSVersionInfoSize
= sizeof (OSVERSIONINFO
);
323 if (::GetVersionEx(&vinfo
) == 0)
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);
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)
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");
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"),
381 int result
= myalloc
->bind ("foo", data
);
382 ACE_TEST_ASSERT (result
!= -1);
385 pid_t pid
= p
.spawn (options
);
387 ACE_ERROR_RETURN ((LM_ERROR
,
389 ACE_TEXT ("spawn")), 1);
393 // Synchronize on the exit of the child.
396 ACE_ERROR_RETURN ((LM_ERROR
,
398 ACE_TEXT ("wait")), 1);
399 ACE_TEST_ASSERT (myalloc
->ref_counter () == 1);
401 ACE_Process_Mutex::unlink (MUTEX_NAME
);
407 // In this case we're the child process.
408 ACE_APPEND_LOG (ACE_TEXT ("Malloc_Test-child"));
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"),
430 run_main (int, ACE_TCHAR
*[])
432 ACE_START_TEST (ACE_TEXT ("Malloc_Test"));
434 ACE_TEXT ("process creation is not supported on this ")
435 ACE_TEXT ("platform\n")));
439 #endif /* ACE_HAS_PROCESS_SPAWN */