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"
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) \
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)
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)
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
,
103 static_allocator
.reset (ptr
);
105 return static_allocator
.get ();
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
120 mmap
.init_acquire (1024, rbyte
, ft
);
125 initialize (MALLOC
*allocator
)
128 ACE_ALLOCATOR_RETURN (temp
,
129 (double *) allocator
->malloc (sizeof (double)),
131 // Make sure that doubles work!
133 allocator
->free (temp
);
136 ACE_ALLOCATOR_RETURN (ptr
,
137 allocator
->malloc (sizeof (Test_Data
)),
139 Test_Data
*data1
= new (ptr
) Test_Data
;
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
;
159 data2
->next_
= data1
;
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);
210 print (const char *process_name
,
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"),
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]));
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];
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);
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",
277 ACE_DEBUG ((LM_DEBUG
,
278 ACE_TEXT ("(%P) sleeping for 10 milliseconds!\n")));
279 ACE_OS::sleep (timeout
);
283 reinterpret_cast<Test_Data
*> (bar
));
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).
300 # if defined(__clang__)
301 # pragma clang diagnostic push
302 # pragma clang diagnostic ignored "-Wdeprecated-declarations"
303 # endif /* __clang__ */
305 vinfo
.dwOSVersionInfoSize
= sizeof (OSVERSIONINFO
);
306 if (::GetVersionEx(&vinfo
) == 0)
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);
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)
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
,
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"),
362 int result
= myalloc
->bind ("foo", data
);
363 ACE_TEST_ASSERT (result
!= -1);
366 pid_t pid
= p
.spawn (options
);
368 ACE_ERROR_RETURN ((LM_ERROR
,
370 ACE_TEXT ("spawn")), 1);
374 // Synchronize on the exit of the child.
377 ACE_ERROR_RETURN ((LM_ERROR
,
379 ACE_TEXT ("wait")), 1);
380 ACE_TEST_ASSERT (myalloc
->ref_counter () == 1);
382 ACE_Process_Mutex::unlink (MUTEX_NAME
);
388 // In this case we're the child process.
389 ACE_APPEND_LOG (ACE_TEXT ("Malloc_Test-child"));
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"),
411 run_main (int, ACE_TCHAR
*[])
413 ACE_START_TEST (ACE_TEXT ("Malloc_Test"));
415 ACE_TEXT ("process creation is not supported on this ")
416 ACE_TEXT ("platform\n")));
420 #endif /* ACE_HAS_PROCESS_SPAWN */