Cleanup ACE_HAS_PTHREAD_SIGMASK_PROTOTYPE, all platforms support it so far as I can...
[ACE_TAO.git] / ACE / tests / Upgradable_RW_Test.cpp
blobd6ef8d0b60790a9ed316151658de235982ac5754
2 //=============================================================================
3 /**
4 * @file Upgradable_RW_Test.cpp
6 * This test program verifies the functionality of the ACE_OS
7 * implementation of readers/writer locks on Win32 and Posix
8 * pthreads. Use the RW_Mutex define switch to use
9 * readers/writer mutexes or regular mutexes.
11 * @author Michael Kircher <mk1@cs.wustl.edu>
13 //=============================================================================
16 #include "Upgradable_RW_Test.h"
17 #include "ace/OS_NS_stdio.h"
18 #include "ace/OS_NS_sys_time.h"
19 #include "ace/Atomic_Op.h"
22 #if defined (ACE_HAS_THREADS)
24 // Default number of iterations.
25 static int n_iterations = 50;
27 // Maximum string length used
28 static const size_t MAX_STRING_SIZE = 200;
30 // switch on RW mutexes, else use ordinary mutexes
31 // #define RW_MUTEX 1
33 // Default number of readers.
34 static u_int n_readers = 10;
36 // Default number of writers.
37 static u_int n_writers = 0;
39 // Number of entries in the hash map
40 static u_int n_entries = 10;
42 // Try to upgrade to a write lock, by default don't try.
43 static u_int use_try_upgrade = 0;
45 // number of readers, which were able to upgrade
46 static u_int upgraded = 0;
48 // count the number of find calls
49 static u_int find_called = 0;
51 // number of readers, failing or not allowed to upgrade
52 static u_int not_upgraded = 0;
54 // Thread creation flags.
55 static long thr_flags = THR_NEW_LWP;
57 // Lock for shared_data (upgraded, not_upgraded, hash_Map)
58 #if defined (RW_MUTEX)
59 static ACE_RW_Thread_Mutex rw_mutex;
60 #else
61 static ACE_Thread_Mutex mutex;
62 #endif /* RW_MUTEX */
64 // Count of the number of readers and writers.
65 static ACE_Atomic_Op<ACE_Thread_Mutex, int> current_readers;
66 static ACE_Atomic_Op<ACE_Thread_Mutex, int> current_writers;
68 static Linked_List *linked_list_ptr;
70 // Returns 1 if found,
71 // 0 if not found,
72 // -1 on an error
73 static int
74 find_last ()
76 find_called++;
78 char search_string[MAX_STRING_SIZE];
79 ACE_OS::snprintf (search_string, MAX_STRING_SIZE, "%d", n_entries - 1);
80 ACE_CString cString (search_string);
81 Element *element_ptr = 0;
83 for (ACE_Double_Linked_List_Iterator<Element> iterator (*linked_list_ptr);
84 !iterator.done ();
85 iterator.advance ())
87 element_ptr = iterator.next ();
88 if (element_ptr)
89 if (*element_ptr->value () == cString)
90 return 1;
93 return 0;
96 // Explain usage and exit.
97 static void
98 print_usage_and_die ()
100 ACE_DEBUG ((LM_DEBUG,
101 ACE_TEXT ("usage: %n [-r n_readers] [-w n_writers]\n")
102 ACE_TEXT (" [-e max_entries] [-u try update] ")
103 ACE_TEXT ("[-n iteration_count] [-f for FIFO threads]\n")));
104 ACE_OS::exit (1);
107 static void
108 parse_args (int argc, ACE_TCHAR *argv[])
110 ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("e:fr:w:n:u"));
112 int c;
114 while ((c = get_opt ()) != -1)
115 switch (c)
117 case 'e':
118 n_entries = ACE_OS::atoi (get_opt.opt_arg ());
119 break;
120 case 'f':
121 thr_flags = THR_BOUND | THR_SCHED_FIFO;
122 break;
123 case 'r':
124 n_readers = ACE_OS::atoi (get_opt.opt_arg ());
125 break;
126 case 'w':
127 n_writers = ACE_OS::atoi (get_opt.opt_arg ());
128 break;
129 case 'n':
130 n_iterations = ACE_OS::atoi (get_opt.opt_arg ());
131 break;
132 case 'u':
133 use_try_upgrade = 1;
134 break;
135 default:
136 print_usage_and_die ();
137 break;
141 // Iterate <n_iterations> each time checking that nobody modifies the data
142 // while we have a read lock.
145 Reader_Task::svc ()
147 ACE_Profile_Timer timer;
148 ACE_Profile_Timer::ACE_Elapsed_Time elapsed_time;
150 barrier_.wait ();
151 // Wait at the barrier.
153 // We start an ACE_Profile_Timer here...
154 timer.start ();
156 for (int iterations = 1;
157 iterations <= n_iterations;
158 iterations++)
160 ACE_Thread::yield ();
162 int result = 0;
165 #if defined (RW_MUTEX)
166 ACE_READ_GUARD_RETURN (ACE_RW_Thread_Mutex, g, rw_mutex, 1);
167 #else
168 ACE_GUARD_RETURN (ACE_Thread_Mutex, g, mutex, 1);
169 #endif /* RW_MUTEX */
170 find_last ();
171 #if defined (RW_MUTEX)
172 if (use_try_upgrade)
173 result =
174 rw_mutex.tryacquire_write_upgrade ();
175 #endif /* RW_MUTEX */
177 // True, when we were able to upgrade.
178 if (result == 0 && use_try_upgrade)
180 //find_last (); try to find something which is not in
181 //there
182 upgraded++;
183 continue;
187 if ((result == -1 && errno == EBUSY) // we tried and failed
188 || !use_try_upgrade) // we did not try at all
190 #if defined (RW_MUTEX)
191 ACE_WRITE_GUARD (ACE_RW_Thread_Mutex, g, rw_mutex, 1);
192 #else
193 ACE_GUARD_RETURN (ACE_Thread_Mutex, g, mutex, 1);
194 #endif /* RW_MUTEX */
196 not_upgraded++;
197 find_last ();
199 else if (result == -1 && errno != EBUSY)
201 ACE_ERROR ((LM_ERROR,
202 ACE_TEXT (" (%t) failure in upgrading to write lock!\n"),
203 1));
207 // Stop the timer.
208 timer.stop ();
209 timer.elapsed_time (elapsed_time);
211 this->time_Calculation_.report_time (elapsed_time);
213 return 0;
216 // Iterate <n_iterations> each time modifying the global data and
217 // checking that nobody steps on it while we can write it.
220 Writer_Task::svc ()
222 ACE_Profile_Timer timer;
223 ACE_Profile_Timer::ACE_Elapsed_Time elapsed_time;
225 barrier_.wait ();
226 // Wait at the barrier
228 // We start an ACE_Profile_Timer here...
229 timer.start ();
231 for (int iterations = 1;
232 iterations <= n_iterations;
233 iterations++)
235 ACE_Thread::yield ();
237 #if defined (RW_MUTEX)
238 ACE_WRITE_GUARD (ACE_RW_Thread_Mutex, g, rw_mutex, 0);
239 #else
240 ACE_GUARD_RETURN (ACE_Thread_Mutex, g, mutex, 0);
241 #endif /* RW_MUTEX */
243 find_last ();
245 current_writers--;
248 // Stop the timer.
249 timer.stop ();
250 timer.elapsed_time (elapsed_time);
252 this->time_Calculation_.report_time (elapsed_time);
254 return 0;
257 void
258 Time_Calculation::report_time (ACE_Profile_Timer::ACE_Elapsed_Time &elapsed_time)
260 ACE_GUARD (ACE_Thread_Mutex, g, mutex_);
262 this->times_.real_time += elapsed_time.real_time;
263 this->times_.user_time += elapsed_time.user_time;
264 this->times_.system_time += elapsed_time.system_time;
266 this->reported_times_++;
269 void
270 Time_Calculation ::print_stats ()
272 ACE_Profile_Timer::ACE_Elapsed_Time elapsed_time = this->times_;
273 u_int iterations = 1;
275 if (iterations > 0)
277 elapsed_time.real_time *= ACE_ONE_SECOND_IN_MSECS;
278 elapsed_time.user_time *= ACE_ONE_SECOND_IN_MSECS;
279 elapsed_time.system_time *= ACE_ONE_SECOND_IN_MSECS;
281 elapsed_time.real_time /= iterations;
282 elapsed_time.user_time /= iterations;
283 elapsed_time.system_time /= iterations;
285 double tmp = 0.0;
287 if (!ACE::is_equal (elapsed_time.real_time, 0.0))
288 tmp = 1000 / elapsed_time.real_time;
290 ACE_DEBUG ((LM_DEBUG,
291 ACE_TEXT ("\n")
292 ACE_TEXT ("\treal_time\t = %0.06f ms,\n")
293 ACE_TEXT ("\tuser_time\t = %0.06f ms,\n")
294 ACE_TEXT ("\tsystem_time\t = %0.06f ms,\n")
295 ACE_TEXT ("\t%0.00f calls/second\n"),
296 elapsed_time.real_time < 0.0 ? 0.0 : elapsed_time.real_time,
297 elapsed_time.user_time < 0.0 ? 0.0 : elapsed_time.user_time,
298 elapsed_time.system_time < 0.0 ? 0.0 : elapsed_time.system_time,
299 tmp < 0.0 ? 0.0 : tmp));
301 ACE_DEBUG ((LM_DEBUG,
302 ACE_TEXT ("Number of reported times: %d\n"),
303 this->reported_times_));
305 else
306 ACE_ERROR ((LM_ERROR,
307 ACE_TEXT ("\tNo time stats printed. Zero iterations or error occurred.\n")));
310 static int
311 init ()
313 char entry[MAX_STRING_SIZE];
314 ACE_CString *cString_ptr = 0;
315 Element *element_ptr = 0;
317 ACE_NEW_RETURN (linked_list_ptr,
318 Linked_List,
319 -1);
321 for (u_int i = 0; i < n_entries; i++)
323 ACE_OS::snprintf (entry, MAX_STRING_SIZE, "%d", i);
324 ACE_NEW_RETURN (cString_ptr,
325 ACE_CString (entry),
326 -1);
327 ACE_NEW_RETURN (element_ptr,
328 Element (cString_ptr),
329 -1);
330 linked_list_ptr->insert_tail (element_ptr);
332 return 0;
335 #endif /* ACE_HAS_THREADS */
337 // Spawn off threads.
340 run_main (int argc, ACE_TCHAR *argv[])
342 ACE_START_TEST (ACE_TEXT ("Upgradable_RW_Test"));
343 int status = 0;
345 #if defined (ACE_HAS_THREADS)
346 parse_args (argc, argv);
347 #if !defined (RW_MUTEX)
348 use_try_upgrade = 0;
349 // make sure that we have to acquire the write lock
350 #endif /* RW_MUTEX */
352 current_readers = 0; // Possibly already done
353 current_writers = 0; // Possibly already done
355 init ();
357 ACE_DEBUG ((LM_DEBUG,
358 ACE_TEXT (" (%t) main thread starting\n")));
360 Time_Calculation time_Calculation;
361 // for the time calculation
363 ACE_Barrier thread_barrier (n_readers + n_writers);
364 // for a nice start of all threads (for much contention)
366 // Initialize the readers.
367 Reader_Task **reader_tasks = 0;
369 ACE_NEW_RETURN (reader_tasks,
370 Reader_Task *[n_readers],
371 -1);
372 u_int i = 0;
374 for (i = 0;
375 i < n_readers;
376 i++)
378 ACE_NEW_RETURN (reader_tasks[i],
379 Reader_Task (time_Calculation,
380 thread_barrier),
381 -1);
383 reader_tasks[i]->activate (thr_flags,
386 ACE_DEFAULT_THREAD_PRIORITY);
389 // Create all the writers
390 Writer_Task **writer_tasks = 0;
392 ACE_NEW_RETURN (writer_tasks,
393 Writer_Task *[n_writers],
394 -1);
396 for (i = 0;
397 i < n_writers;
398 i++)
400 ACE_NEW_RETURN (writer_tasks[i],
401 Writer_Task (time_Calculation,
402 thread_barrier),
403 -1);
405 writer_tasks[i]->activate (thr_flags,
408 ACE_DEFAULT_THREAD_PRIORITY);
411 // Wait a maximum of 1 second per iteration.
412 const ACE_Time_Value max_wait (n_iterations * 1);
413 const ACE_Time_Value wait_time (ACE_OS::gettimeofday () + max_wait);
414 if (ACE_Thread_Manager::instance ()->wait (&wait_time) == -1)
416 if (errno == ETIME)
417 ACE_ERROR ((LM_ERROR,
418 ACE_TEXT ("maximum wait time of %d msec exceeded\n"),
419 max_wait.msec ()));
420 else
421 ACE_OS::perror (ACE_TEXT ("wait"));
423 status = -1;
426 // compute average time.
427 time_Calculation.print_stats ();
429 if (not_upgraded != 0 || upgraded != 0)
430 ACE_DEBUG ((LM_DEBUG,
431 ACE_TEXT ("upgraded to not upgraded ratio = %f\n"),
432 (float) upgraded / (float) (not_upgraded + upgraded)));
434 ACE_DEBUG ((LM_DEBUG,
435 ACE_TEXT ("Number of times, that find was called: %d\n"),
436 find_called));
439 ACE_DEBUG ((LM_DEBUG,
440 ACE_TEXT (" (%t) exiting main thread\n")));
442 // Delete the memory of the Double_Linked_List
443 ACE_CString *cString_ptr = 0;
444 Element *element_ptr = 0;
446 for (i = 0;
447 i < n_entries;
448 i++)
450 if (0 != (element_ptr = linked_list_ptr->delete_head ()))
452 cString_ptr = element_ptr->value ();
453 delete cString_ptr;
454 delete element_ptr;
458 delete linked_list_ptr;
460 for (i = 0;
461 i < n_writers;
462 i++)
463 delete writer_tasks[i];
465 delete [] writer_tasks;
467 for (i = 0;
468 i < n_readers;
469 i++)
470 delete reader_tasks [i];
472 delete [] reader_tasks;
473 #else
474 ACE_UNUSED_ARG (argc);
475 ACE_UNUSED_ARG (argv);
476 ACE_ERROR ((LM_INFO,
477 ACE_TEXT ("threads not supported on this platform\n")));
478 #endif /* ACE_HAS_THREADS */
480 ACE_END_TEST;
481 return status;