ACE+TAO-7_0_8
[ACE_TAO.git] / ACE / tests / Recursive_Mutex_Test.cpp
blob891cf42b6df06de5d96e8499f475431876fbf667
2 //=============================================================================
3 /**
4 * @file Recursive_Mutex_Test.cpp
6 * This test program verifies the functionality of the ACE_OS
7 * implementation of recursive mutexes on Win32 and Posix
8 * pthreads.
10 * @author Prashant Jain <pjain@cs.wustl.edu> and Douglas C. Schmidt <d.schmidt@vanderbilt.edu>
12 //=============================================================================
15 #include "test_config.h"
16 #include "ace/Get_Opt.h"
17 #include "ace/Thread_Manager.h"
18 #include "ace/OS_NS_time.h"
19 #include "ace/OS_NS_sys_time.h"
20 #include "ace/OS_NS_unistd.h"
21 #include "ace/Recursive_Thread_Mutex.h"
25 #if defined (ACE_HAS_THREADS)
27 #include "ace/Guard_T.h"
29 // For all platforms except for Windows use the
30 // ACE_Recursive_Thread_Mutex. Since Windows only supports timed
31 // recursive process mutexes and not timed recursive thread mutexes,
32 // use ACE_Process_Mutex.
33 #if defined (ACE_HAS_WTHREADS)
34 # include "ace/Process_Mutex.h"
35 typedef ACE_Process_Mutex ACE_TEST_MUTEX;
36 #else
37 # include "ace/Thread_Mutex.h"
38 using ACE_TEST_MUTEX = ACE_Recursive_Thread_Mutex;
39 #endif
41 #if !defined (ACE_HAS_MUTEX_TIMEOUTS)
42 static int reported_notsup = 0;
43 #endif /* ACE_HAS_MUTEX_TIMEOUTS */
45 // Total number of iterations.
46 static int const n_iterations = 100;
47 static size_t n_threads = ACE_MAX_THREADS;
49 // ACE_Recursive_Thread_Mutex::get_nesting_level() will return a
50 // meaningful value.
51 #if !defined (ACE_HAS_WTHREADS)
52 static bool nesting_level_supported = false;
53 #endif
55 static void
56 test_recursion_depth (int nesting_level,
57 ACE_TEST_MUTEX *rm)
59 if (nesting_level < n_iterations)
61 #if !defined (ACE_HAS_WTHREADS)
62 // This will work for Windows, too, if ACE_TEST_MUTEX is
63 // ACE_Recursive_Thread_Mutex instead of ACE_Process_Mutex.
64 if (nesting_level_supported
65 && nesting_level != 0
66 && nesting_level != rm->get_nesting_level ())
68 ACE_ERROR ((LM_ERROR,
69 ACE_TEXT ("(%P|%t) Pre-mutex acquire nesting ")
70 ACE_TEXT ("levels do not match.\n")));
72 #endif /* !ACE_HAS_WTHREADS */
73 int result = rm->acquire ();
74 ACE_TEST_ASSERT (result == 0);
75 #if !defined (ACE_HAS_WTHREADS)
76 if (nesting_level_supported
77 && (nesting_level + 1) != rm->get_nesting_level ())
79 ACE_ERROR ((LM_ERROR,
80 ACE_TEXT ("(%P|%t) Post-mutex acquire nesting ")
81 ACE_TEXT ("levels do not match.\n")));
84 ACE_DEBUG ((LM_DEBUG,
85 ACE_TEXT ("(%P|%t) = acquired, nesting = %d, thread id = %u\n"),
86 rm->get_nesting_level (),
87 rm->get_thread_id ()));
88 #endif /* !ACE_HAS_WTHREADS */
90 test_recursion_depth (nesting_level + 1,
91 rm);
93 #if !defined (ACE_HAS_WTHREADS)
94 if (nesting_level_supported
95 && (nesting_level + 1) != rm->get_nesting_level ())
97 ACE_ERROR ((LM_ERROR,
98 ACE_TEXT ("(%P|%t) Post recursion nesting ")
99 ACE_TEXT ("levels do not match.\n")));
101 #endif /* !ACE_HAS_WTHREADS */
102 result = rm->release ();
103 ACE_TEST_ASSERT (result == 0);
104 #if !defined (ACE_HAS_WTHREADS)
105 ACE_DEBUG ((LM_DEBUG,
106 ACE_TEXT ("(%P|%t) = released, nesting = %d, thread id = %u\n"),
107 rm->get_nesting_level (),
108 rm->get_thread_id ()));
110 if (nesting_level_supported
111 && nesting_level != 0
112 && nesting_level != rm->get_nesting_level ())
114 ACE_ERROR ((LM_ERROR,
115 ACE_TEXT ("(%P|%t) Post-mutex release nesting ")
116 ACE_TEXT ("levels do not match.\n")));
118 #endif /* !ACE_HAS_WTHREADS */
122 static void
123 test_timed_wait (int nesting_level,
124 ACE_TEST_MUTEX *rm)
126 // Make sure that we're inside of a recursive level.
127 if (nesting_level == 0)
128 test_timed_wait (nesting_level + 1,
129 rm);
130 else
132 u_int seed = (u_int) ACE_OS::time (0);
134 for (size_t i = 0; i < ACE_MAX_ITERATIONS / 2; i++)
136 int result = 0;
138 // First attempt to acquire the mutex with a timeout to verify
139 // that mutex timeouts are working.
141 ACE_DEBUG ((LM_DEBUG,
142 ACE_TEXT ("(%P|%t) = trying timed acquire on ")
143 ACE_TEXT ("iteration %d\n"),
144 i));
146 ACE_Time_Value delta (1, 0); // One second timeout
147 ACE_Time_Value timeout = ACE_OS::gettimeofday ();
148 timeout += delta; // Must pass absolute time to acquire().
150 if (rm->acquire (timeout) != 0)
152 if (errno == ETIME)
153 ACE_DEBUG ((LM_DEBUG,
154 ACE_TEXT ("(%P|%t) = mutex acquisition ")
155 ACE_TEXT ("timed out\n")));
156 else if (errno == ENOTSUP)
158 #if !defined (ACE_HAS_MUTEX_TIMEOUTS)
159 if (!reported_notsup)
161 ACE_DEBUG ((LM_INFO,
162 ACE_TEXT ("(%P|%t) %p, but ACE_HAS_MUTEX_TIMEOUTS is not defined - Ok\n"),
163 ACE_TEXT ("mutex timed acquire")));
164 reported_notsup = 1;
166 #else
167 ACE_DEBUG ((LM_ERROR,
168 ACE_TEXT ("(%P|%t) %p - maybe ACE_HAS_MUTEX_TIMEOUTS should not be defined?\n"),
169 ACE_TEXT ("mutex timed acquire")));
170 #endif /* ACE_HAS_MUTEX_TIMEOUTS */
172 else
174 ACE_ERROR ((LM_ERROR,
175 ACE_TEXT ("(%P|%t) %p\n%a"),
176 ACE_TEXT ("mutex timeout failed\n")));
177 return;
180 else
182 result = rm->release ();
183 ACE_TEST_ASSERT (result == 0);
186 // Now try the standard mutex.
188 ACE_DEBUG ((LM_DEBUG,
189 ACE_TEXT ("(%P|%t) = trying to acquire on iteration %d\n"),
190 i));
191 result = rm->acquire ();
192 ACE_TEST_ASSERT (result == 0);
193 ACE_DEBUG ((LM_DEBUG,
194 ACE_TEXT ("(%P|%t) = acquired on iteration %d\n"),
195 i));
197 // Sleep for a random amount of time between 0 and 2 seconds.
198 // Note that it's ok to use rand() here because we are running
199 // within the critical section defined by the Thread_Mutex.
200 ACE_OS::sleep (ACE_OS::rand_r (&seed) % 2);
202 result = rm->release ();
203 ACE_TEST_ASSERT (result == 0);
204 ACE_DEBUG ((LM_DEBUG,
205 ACE_TEXT ("(%P|%t) = released on iteration %d\n"),
206 i));
208 // FUZZ: disable check_for_ACE_Guard
209 // Basic ACE_Guard usage - automatically acquire the mutex on
210 // guard construction and automatically release it on
211 // destruction.
213 // Construct an ACE_Guard to implicitly acquire the mutex.
214 ACE_Guard<ACE_TEST_MUTEX> guard (*rm);
215 ACE_TEST_ASSERT (guard.locked () != 0);
217 // Perform some operation which might exit the current scope
218 // prematurely, e.g. by returning or throwing an exception.
219 // ...
221 // ACE_Guard object is destroyed when exiting scope and guard
222 // destructor automatically releases mutex.
225 // Use an ACE_Guard to automatically acquire a mutex, but release
226 // the mutex early.
228 // Construct an ACE_Guard to implicitly acquire the mutex.
229 ACE_Guard<ACE_TEST_MUTEX> guard (*rm);
230 ACE_TEST_ASSERT (guard.locked () != 0);
232 // Perform some operation which might exit the current scope
233 // prematurely, e.g. by returning or throwing an exception.
234 // ...
236 // Release the mutex since we no longer need it.
237 guard.release ();
238 ACE_TEST_ASSERT (guard.locked () == 0);
240 // Do something else which does not require the mutex to be locked.
241 // ...
243 // ACE_Guard object's destructor will not release the mutex.
246 // Use an ACE_Guard to automatically acquire a mutex, but
247 // relinquish ownership of the lock so that the mutex is not
248 // automatically released on guard destruction. This is useful
249 // when an operation might not release the mutex in some
250 // conditions, in which case responsibility for releasing it is
251 // passed to someone else.
253 // Construct an ACE_Guard to implicitly acquire the mutex.
254 ACE_Guard<ACE_TEST_MUTEX> guard (*rm);
255 ACE_TEST_ASSERT (guard.locked () != 0);
257 // Perform some operation which might exit the current scope
258 // prematurely, e.g. by returning or throwing an exception.
259 // ...
261 // Relinquish ownership of the mutex lock. Someone else must
262 // now release it.
263 guard.disown ();
264 ACE_TEST_ASSERT (guard.locked () == 0);
266 // ACE_Guard object's destructor will not release the mutex.
268 // We are now responsible for releasing the mutex.
269 result = rm->release ();
270 ACE_TEST_ASSERT (result == 0);
272 // Construct an ACE_Guard without automatically acquiring the lock.
274 // Construct an ACE_Guard object without automatically
275 // acquiring the mutex or taking ownership of an existing
276 // lock. The third parameter tells the guard that the mutex
277 // has not been locked.
278 ACE_Guard<ACE_TEST_MUTEX> guard (*rm, 0, 0);
279 ACE_TEST_ASSERT (guard.locked () == 0);
281 // Conditionally acquire the mutex.
282 if (i % 2 == 0)
284 guard.acquire ();
285 ACE_TEST_ASSERT (guard.locked () != 0);
288 // Perform some operation that might exit the current scope
289 // prematurely, e.g. by returning or throwing an exception.
290 // ...
292 // ACE_Guard object is destroyed when exiting scope and guard
293 // destructor automatically releases if it was acquired above.
296 // Use an ACE_Guard to take ownership of a previously acquired
297 // mutex.
298 timeout = ACE_OS::gettimeofday ();
299 timeout += delta; // Must pass absolute time to acquire().
300 if (rm->acquire (timeout) == 0)
302 // Construct an ACE_Guard object without automatically
303 // acquiring the mutex, but instead take ownership of the
304 // existing lock. The third parameter tells the guard that
305 // the mutex has already been locked.
306 ACE_Guard<ACE_TEST_MUTEX> guard (*rm, 0, 1);
307 ACE_TEST_ASSERT (guard.locked () != 0);
309 // Perform some operation which might exit the current scope
310 // prematurely, e.g. by returning or throwing an exception.
311 // ...
313 // ACE_Guard object is destroyed when exiting scope and guard
314 // destructor automatically releases mutex.
316 // FUZZ: enable check_for_ACE_Guard
319 return;
323 static void *
324 recursion_worker (void *arg)
326 ACE_TEST_MUTEX *rm =
327 reinterpret_cast<ACE_TEST_MUTEX *> (arg);
329 ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%P|%t) Starting test of recursion depth\n")));
330 test_recursion_depth (0, rm);
332 return 0;
335 static void *
336 timed_worker (void *arg)
338 ACE_TEST_MUTEX *rm =
339 reinterpret_cast<ACE_TEST_MUTEX *> (arg);
341 ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%P|%t) Starting test of timed wait\n")));
342 test_timed_wait (0, rm);
344 return 0;
347 #endif /* ACE_HAS_THREADS */
350 run_main (int argc, ACE_TCHAR *argv[])
352 ACE_START_TEST (ACE_TEXT ("Recursive_Mutex_Test"));
354 #if defined (ACE_HAS_THREADS)
355 if (argc > 1)
357 n_threads = ACE_OS::atoi (argv[1]);
360 ACE_TEST_MUTEX rm;
362 #if !defined (ACE_HAS_WTHREADS)
363 // This will work for Windows, too, if ACE_TEST_MUTEX is
364 // ACE_Recursive_Thread_Mutex instead of ACE_Process_Mutex.
365 nesting_level_supported =
366 (rm.get_nesting_level () != -1 || errno != ENOTSUP);
367 #endif /* !ACE_HAS_WTHREADS */
369 ACE_Thread_Manager::instance ()->spawn_n (n_threads,
370 ACE_THR_FUNC (recursion_worker),
371 (void *) &rm);
372 ACE_Thread_Manager::instance ()->wait ();
374 ACE_Thread_Manager::instance ()->spawn_n (n_threads,
375 ACE_THR_FUNC (timed_worker),
376 (void *) &rm);
377 ACE_Thread_Manager::instance ()->wait ();
378 #else
379 ACE_UNUSED_ARG (argc);
380 ACE_UNUSED_ARG (argv);
381 ACE_ERROR ((LM_ERROR,
382 ACE_TEXT ("ACE doesn't support recursive process ")
383 ACE_TEXT ("mutexes on this platform\n")));
384 #endif /* ACE_HAS_THREADS */
385 ACE_END_TEST;
386 return 0;