1 //=============================================================================
3 * @file Process_Mutex_Test.cpp
5 * Tests an <ACE_Process_Mutex> shared between multiple child processes.
7 * @author Irfan Pyarali <irfan@cs.wustl.edu>
9 //=============================================================================
11 #include "test_config.h"
12 #include "ace/Mutex.h"
13 #include "ace/Process.h"
14 #include "ace/Process_Mutex.h"
15 #include "ace/Get_Opt.h"
17 #include "ace/OS_NS_stdio.h"
18 #include "ace/OS_NS_string.h"
19 #include "ace/OS_NS_fcntl.h"
20 #include "ace/os_include/os_dirent.h"
22 static int release_mutex
= 1;
23 static int child_process
= 0;
24 static const ACE_TCHAR
*mutex_name
= ACE_DEFAULT_MUTEX
;
25 #if defined (__Lynx__)
26 static const u_int n_processes
= 4;
27 #else /* ! __Lynx__ */
28 static const u_int n_processes
= ACE_MAX_PROCESSES
;
29 #endif /* ! __Lynx__ */
31 // Explain usage and exit.
33 print_usage_and_die ()
36 ACE_TEXT ("usage: %n [-d (don't release mutex)] ")
37 ACE_TEXT ("[-c (child process)] [-n mutex name]\n")));
41 // Parse the command-line arguments and set options.
43 parse_args (int argc
, ACE_TCHAR
*argv
[])
45 ACE_Get_Opt
get_opt (argc
, argv
, ACE_TEXT("dcn:"));
49 while ((c
= get_opt ()) != -1)
59 mutex_name
= get_opt
.opt_arg ();
62 print_usage_and_die ();
70 ACE_Process_Mutex
mutex (mutex_name
);
72 // Make sure the constructor succeeded
73 ACE_TEST_ASSERT (ACE_LOG_MSG
->op_status () == 0);
75 // To see if we really are the only holder of the mutex below,
76 // we'll try to create a file with exclusive access. If the file
77 // already exists, we're not the only one holding the mutex.
78 ACE_TCHAR mutex_check
[MAXPATHLEN
+1];
79 ACE_OS::strncpy (mutex_check
, mutex_name
, MAXPATHLEN
);
80 ACE_OS::strncat (mutex_check
, ACE_TEXT ("_checker"), MAXPATHLEN
);
83 int mutex_acq
= mutex
.acquire ();
84 ACE_TEST_ASSERT (mutex_acq
== 0);
87 ACE_TEXT ("(%P) Mutex acquired %s\n"),
90 ACE_HANDLE checker_handle
= ACE_OS::open (mutex_check
, O_CREAT
| O_EXCL
);
91 if (checker_handle
== ACE_INVALID_HANDLE
)
93 ACE_DEBUG ((LM_WARNING
, ACE_TEXT ("(%P): %p\n"),
94 ACE_TEXT ("checker file open")));
95 ACE_TEST_ASSERT (errno
!= EEXIST
);
98 ACE_OS::close (checker_handle
);
100 ACE_DEBUG ((LM_DEBUG
,
101 ACE_TEXT ("(%P) Working....\n")));
103 // Do some "work", i.e., just sleep for a couple of seconds.
106 // Free up the check file for the next acquirer.
107 ACE_OS::unlink (mutex_check
);
109 // Check if we need to release the mutex
110 if (release_mutex
== 1)
112 ACE_DEBUG ((LM_DEBUG
,
113 ACE_TEXT ("(%P) Releasing the mutex %s\n"),
115 int mutex_release
= mutex
.release ();
116 ACE_TEST_ASSERT (mutex_release
== 0);
121 run_main (int argc
, ACE_TCHAR
*argv
[])
123 parse_args (argc
, argv
);
125 // Child process code.
128 ACE_TCHAR lognm
[MAXPATHLEN
];
129 int mypid (ACE_OS::getpid ());
130 ACE_OS::snprintf (lognm
, MAXPATHLEN
,
131 ACE_TEXT ("Process_Mutex_Test-child-%d"), mypid
);
133 ACE_START_TEST (lognm
);
139 ACE_START_TEST (ACE_TEXT ("Process_Mutex_Test"));
140 # if !defined( ACE_HAS_SYSV_IPC) || defined(ACE_USES_MUTEX_FOR_PROCESS_MUTEX)
141 // When Process_Mutex is pthreads based, then the owner of mutex destroys it
142 // in destructor. This may disturb the other processes which still uses the
143 // mutex. It is safer then to hold the mutex in main process, and destroy it after
144 // children finish. This is temporary solution, and in future pthread base
145 // Process_Mutex shall control the destruction of mutex better.
146 ACE_Process_Mutex
mutex( mutex_name
);
149 ACE_Process_Options options
;
151 #ifndef ACE_LACKS_VA_FUNCTIONS
152 options
.command_line (ACE_TEXT ("%") ACE_TEXT_PRIs
153 ACE_TEXT (" -c -n %") ACE_TEXT_PRIs
154 ACE_TEXT ("%") ACE_TEXT_PRIs
,
155 argc
> 0 ? argv
[0] : ACE_TEXT ("Process_Mutex_Test"), mutex_name
,
156 release_mutex
== 0 ? ACE_TEXT (" -d") : ACE_TEXT (""));
159 #ifdef ACE_HAS_PROCESS_SPAWN
160 // Spawn <n_processes> child processes that will contend for the
162 ACE_Process children
[n_processes
];
169 // Spawn the child process.
170 if (children
[i
].spawn (options
) == -1)
172 ACE_ERROR_RETURN ((LM_ERROR
,
173 ACE_TEXT ("spawn of client %d failed\n"),
179 ACE_DEBUG ((LM_DEBUG
,
180 ACE_TEXT ("Parent spawned child process with pid = %d.\n"),
181 children
[i
].getpid ()));
184 // Give the newly spawned child process a chance to start...
185 // David Levine thinks this sleep() is required because
186 // calling ::waitpid () before a fork'ed child has actually
187 // been created may be a problem on some platforms. It's
188 // not enough for fork() to have returned to the parent.
192 for (i
= 0; i
< n_processes
; i
++)
194 ACE_exitcode child_status
;
195 // Wait for the child processes we created to exit.
196 int wait_result
= children
[i
].wait (&child_status
);
197 ACE_TEST_ASSERT (wait_result
!= -1);
198 if (child_status
== 0)
199 ACE_DEBUG ((LM_DEBUG
,
200 ACE_TEXT ("Child %d finished ok\n"),
201 children
[i
].getpid ()));
203 ACE_ERROR ((LM_ERROR
,
204 ACE_TEXT ("Child %d finished with status %d\n"),
205 children
[i
].getpid (), child_status
));
208 #endif // ACE_HAS_PROCESS_SPAWN
209 ACE_Process_Mutex::unlink (mutex_name
);