2 //=============================================================================
4 * @file MM_Shared_Memory_Test.cpp
6 * This is a simple test of <ACE_Shared_Memory_MM>. The test
7 * forks two processes or spawns two threads (depending upon the
8 * platform) and then executes child and parent allowing them to
9 * exchange data using shared memory. No user input is required as
10 * far as command line arguments are concerned.
12 * @author Prashant Jain <pjain@cs.wustl.edu> and Douglas C. Schmidt <d.schmidt@vanderbilt.edu>
14 //=============================================================================
16 #include "test_config.h"
17 #include "ace/Shared_Memory_MM.h"
18 #include "ace/SV_Semaphore_Simple.h"
19 #include "ace/Process_Semaphore.h"
20 #include "ace/Thread_Manager.h"
21 #include "ace/Lib_Find.h"
22 #include "ace/OS_NS_string.h"
23 #include "ace/OS_NS_unistd.h"
26 #if !defined (ACE_LACKS_MMAP)
28 static const char ACE_ALPHABET
[] = "abcdefghijklmnopqrstuvwxyz";
30 static ACE_TCHAR
*shm_key
;
32 #if defined (ACE_LACKS_FORK)
33 #include "ace/Thread_Semaphore.h"
34 typedef ACE_Thread_Semaphore SYNCHRONIZER
;
35 #define SYNC_EXTRA_ARGS
36 #elif defined (ACE_HAS_POSIX_SEM) && defined(ACE_HAS_SYSV_IPC)
40 * @brief If the platform has native cross-process POSIX semaphores, we
41 * must *force* this test to use the System V Semaphores in order
42 * to get the right semantics.
44 class SYNCHRONIZER
: public ACE_SV_Semaphore_Simple
47 SYNCHRONIZER (int initial_value
)
48 : ACE_SV_Semaphore_Simple ((const char *) 0,
49 ACE_SV_Semaphore_Simple::ACE_CREATE
,
53 #define SYNC_EXTRA_ARGS
56 typedef ACE_Process_Semaphore SYNCHRONIZER
;
58 #define SYNC_EXTRA_ARGS , sem_name ()
59 ACE_TCHAR sem_name_
[ACE_UNIQUE_NAME_LEN
] = ACE_TEXT ("/");
61 const ACE_TCHAR
*sem_name ()
63 ACE::unique_name (sem_name_
, sem_name_
+ 1, ACE_UNIQUE_NAME_LEN
- 1);
66 #endif /* !defined (ACE_LACKS_FORK) */
68 // Synchronize the start of the parent and the child.
69 static SYNCHRONIZER
*synchronizer
= 0;
76 // Wait for the parent to be initialized.
77 result
= synchronizer
->acquire ();
78 ACE_TEST_ASSERT (result
!= -1);
80 const char *t
= ACE_ALPHABET
;
81 ACE_Shared_Memory_MM shm_child
;
83 result
= shm_child
.open (shm_key
);
84 ACE_TEST_ASSERT (result
!= -1);
86 char *shm
= (char *) shm_child
.malloc ();
88 ACE_TEST_ASSERT (shm
!= 0);
90 for (char *s
= shm
; *s
!= '\0'; s
++)
92 ACE_TEST_ASSERT (*t
== s
[0]);
96 // Indicate to the parent that we're done.
106 ACE_Shared_Memory_MM shm_parent
;
108 result
= shm_parent
.open (shm_key
, SHMSZ
);
109 ACE_TEST_ASSERT (result
!= -1);
111 char *shm
= (char *) shm_parent
.malloc ();
113 ACE_TEST_ASSERT (shm
!= 0);
117 for (const char *c
= ACE_ALPHABET
; *c
!= '\0'; c
++)
122 // Allow the child to proceed.
123 result
= synchronizer
->release ();
124 ACE_TEST_ASSERT (result
!= -1);
126 // Perform a "busy wait" until the child sets the character to '*'.
128 ACE_DEBUG ((LM_DEBUG
,
129 ACE_TEXT ("(%P) spinning in parent!\n")));
131 result
= shm_parent
.remove ();
132 ACE_TEST_ASSERT (result
!= -1);
134 ACE_OS::unlink (shm_key
);
141 // Create the synchronizer before spawning the child process/thread,
142 // to avoid race condition between the creation in the parent and
144 ACE_NEW_RETURN (synchronizer
,
145 SYNCHRONIZER (0u /*locked*/ SYNC_EXTRA_ARGS
),
148 #if !defined (ACE_LACKS_FORK)
149 switch (ACE_OS::fork (ACE_TEXT ("child")))
152 ACE_ERROR_RETURN ((LM_ERROR
,
153 ACE_TEXT ("(%P|%t) %p\n"),
154 ACE_TEXT ("fork failed")),
159 // Remove the semaphore.
160 synchronizer
->remove ();
170 #elif defined (ACE_HAS_THREADS)
171 if (ACE_Thread_Manager::instance ()->spawn
172 (ACE_THR_FUNC (child
),
174 THR_NEW_LWP
| THR_DETACHED
) == -1)
175 ACE_ERROR_RETURN ((LM_ERROR
,
176 ACE_TEXT ("(%P|%t) %p\n"),
177 ACE_TEXT ("thread create failed")),
179 else if (ACE_Thread_Manager::instance ()->spawn
180 (ACE_THR_FUNC (parent
),
182 THR_NEW_LWP
| THR_DETACHED
) == -1)
183 ACE_ERROR_RETURN ((LM_ERROR
,
184 ACE_TEXT ("(%P|%t) %p\n"),
185 ACE_TEXT ("thread create failed")),
187 ACE_Thread_Manager::instance ()->wait ();
190 ACE_UNUSED_ARG (synchronizer
);
191 ACE_ERROR_RETURN ((LM_ERROR
,
192 ACE_TEXT ("only one thread may be run in a process on this platform\n")),
194 #endif /* ACE_HAS_THREADS */
197 #endif /* !ACE_LACKS_MMAP */
200 run_main (int, ACE_TCHAR
*[])
202 ACE_START_TEST (ACE_TEXT ("MM_Shared_Memory_Test"));
204 #if !defined (ACE_LACKS_MMAP) && !defined (ACE_DISABLE_MKTEMP)
205 ACE_TCHAR temp_file
[MAXPATHLEN
+ 1];
207 // Get the temporary directory,
208 // The - 24 is for the filename, mm_shared_mem_testXXXXXX
209 if (ACE::get_temp_dir (temp_file
, MAXPATHLEN
- 24) == -1)
210 ACE_ERROR_RETURN ((LM_ERROR
, ACE_TEXT ("Temporary path too long\n")), -1);
212 // Add the filename to the end
213 ACE_OS::strcat (temp_file
, ACE_TEXT ("mm_shared_mem_testXXXXXX"));
215 // Store in the global variable.
218 if (ACE_OS::mktemp (shm_key
) == 0
219 || (ACE_OS::unlink (shm_key
) == -1
221 ACE_ERROR_RETURN ((LM_ERROR
,
222 ACE_TEXT ("(%P|%t) %p\n"),
227 #else /* !ACE_LACKS_MMAP */
229 ACE_TEXT ("mmap and mktemp")
230 ACE_TEXT ("are required for this test\n")));
231 #endif /* !ACE_LACKS_MMAP */