Changes to attempt to silence bcc64x
[ACE_TAO.git] / ACE / tests / Proactor_Timer_Test.cpp
blobdad2adb5388b37d4df35b0cc2e58111755580e75
2 //=============================================================================
3 /**
4 * @file Proactor_Timer_Test.cpp
6 * This is a simple test that illustrates the timer mechanism of
7 * the <ACE_Proactor>. Scheduling timers, handling expired timers and
8 * cancelling scheduled timers are all exercised in this test.
10 * @author Prashant Jain <pjain@cs.wustl.edu>
11 * @author Douglas C. Schmidt <d.schmidt@vanderbilt.edu>
12 * @author and Miljenko Norsic <Miljenko.Norsic@etk.ericsson.se>
14 //=============================================================================
17 #include "test_config.h"
18 #include "ace/Trace.h"
20 #if defined (ACE_HAS_WIN32_OVERLAPPED_IO) || defined (ACE_HAS_AIO_CALLS)
21 // This only works on Win32 platforms and on Unix platforms
22 // supporting POSIX aio calls.
24 #include "ace/OS_NS_unistd.h"
25 #include "ace/Proactor.h"
26 #include "ace/High_Res_Timer.h"
27 #include "ace/Asynch_IO.h"
28 #include "ace/Timer_Heap.h"
29 #include <memory>
31 static int done = 0;
32 static size_t counter = 0;
33 static int odd = 0;
35 class Time_Handler : public ACE_Handler
37 public:
38 /// Default constructor
39 Time_Handler ();
41 /// Handle the timeout.
42 void handle_time_out (const ACE_Time_Value &tv, const void *arg) override;
44 /// Return our timer id.
45 long timer_id () const;
47 /// Set our timer id;
48 void timer_id (long);
50 private:
51 /// Stores the id of this timer.
52 long timer_id_;
56 * Need a variant of this that will track if a repeating timer is working
57 * correctly. This class should be scheduled with a repeating timer that
58 * repeats on a specified number of seconds. This class will let two
59 * expirations happen then wait in handle_time_out() longer than the repeat
60 * time to cause at least one timer expiration to be queued up while we're
61 * waiting; then cancel the timer.
63 class Repeat_Timer_Handler : public ACE_Handler
65 public:
66 static const int REPEAT_INTERVAL = 2;
68 // Constructor arg tells how many seconds we intend to do the repeat with.
69 // The internals will use this to tell how long to wait in order to cause
70 // a timer expiration to be missed and queued up.
71 Repeat_Timer_Handler (const int repeat_time = REPEAT_INTERVAL)
72 : repeat_secs_ (repeat_time), expirations_ (0) {};
74 ~Repeat_Timer_Handler () override;
76 // Handle the timeout.
77 void handle_time_out (const ACE_Time_Value &tv, const void *arg) override;
79 private:
80 int repeat_secs_;
81 int expirations_;
85 Time_Handler::Time_Handler ()
86 : timer_id_ (-1)
88 // Nothing
91 void
92 Time_Handler::handle_time_out (const ACE_Time_Value &, const void *arg)
94 size_t current_counter = *(reinterpret_cast<const size_t *> (arg));
95 if (current_counter != counter)
96 ACE_ERROR ((LM_ERROR,
97 ACE_TEXT ("Expected timer %d, not %d\n"),
98 counter,
99 current_counter));
101 ACE_DEBUG ((LM_DEBUG,
102 ACE_TEXT ("[%@] Timer id %d with counter #%d|%d expired.\n"),
103 this,
104 this->timer_id (),
105 counter,
106 current_counter));
108 if (current_counter == (ACE_MAX_TIMERS - 1))
109 done = 1;
110 else if (counter == ACE_MAX_TIMERS - 1)
112 done = 1;
113 return;
116 counter += (1 + odd);
117 return;
120 long
121 Time_Handler::timer_id () const
123 return this->timer_id_;
126 void
127 Time_Handler::timer_id (long t)
129 this->timer_id_ = t;
132 Repeat_Timer_Handler::~Repeat_Timer_Handler ()
134 if (this->expirations_ == 2)
135 ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Repeater expired twice; correct\n")));
136 else
137 ACE_ERROR ((LM_ERROR,
138 ACE_TEXT ("Repeater expired %d times; should be 2\n"),
139 this->expirations_));
142 void
143 Repeat_Timer_Handler::handle_time_out (const ACE_Time_Value &, const void *)
145 // Let the first one go.
146 if (++this->expirations_ == 1)
147 return;
149 if (this->expirations_ == 2)
151 ACE_OS::sleep (this->repeat_secs_ + 1);
152 int canceled = this->proactor ()->cancel_timer (*this);
153 if (canceled != 1)
155 ACE_ERROR ((LM_ERROR,
156 ACE_TEXT ("Repeater cancel timer: %d; should be 1\n"),
157 canceled));
159 delete this;
161 else
163 ACE_ERROR ((LM_ERROR,
164 ACE_TEXT ("Repeater expiration #%d; should get only 2\n"),
165 this->expirations_));
167 return;
170 static void
171 test_registering_all_handlers ()
173 ACE_Trace t (ACE_TEXT ("test_registering_all_handler"),
174 __LINE__,
175 ACE_TEXT_CHAR_TO_TCHAR (__FILE__));
176 Time_Handler rt[ACE_MAX_TIMERS];
177 long t_id[ACE_MAX_TIMERS];
178 size_t which[ACE_MAX_TIMERS];
179 long secs = 0;
180 size_t i = 0;
181 for ( ; i < ACE_MAX_TIMERS; i++, secs++)
183 which[i] = i;
184 t_id[i] =
185 ACE_Proactor::instance ()->schedule_timer
186 (rt[i], &which[i], ACE_Time_Value (2 * secs + 1));
187 if (t_id[i] == -1)
188 ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("schedule_timer")));
189 rt[i].timer_id (t_id[i]);
192 while (!done)
193 ACE_Proactor::instance ()->handle_events ();
196 static void
197 test_registering_one_handler ()
199 ACE_Trace t (ACE_TEXT ("test_registering_one_handler"),
200 __LINE__,
201 ACE_TEXT_CHAR_TO_TCHAR (__FILE__));
202 Time_Handler rt[ACE_MAX_TIMERS];
203 long t_id[ACE_MAX_TIMERS];
204 size_t which[ACE_MAX_TIMERS];
206 done = 0;
207 counter = 0;
208 long secs = 0;
209 size_t i = 0;
210 for ( ; i < ACE_MAX_TIMERS; i++, secs++)
212 which[i] = i;
213 t_id[i] =
214 ACE_Proactor::instance ()->schedule_timer
215 (rt[0], &which[i], ACE_Time_Value (2 * secs + 1));
216 if (t_id[i] == -1)
217 ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("schedule_timer")));
220 while (!done)
221 ACE_Proactor::instance ()->handle_events ();
224 static void
225 test_canceling_odd_timers ()
227 ACE_Trace t (ACE_TEXT ("test_canceling_odd_timers"),
228 __LINE__,
229 ACE_TEXT_CHAR_TO_TCHAR (__FILE__));
230 Time_Handler rt[ACE_MAX_TIMERS];
231 long t_id[ACE_MAX_TIMERS];
232 size_t which[ACE_MAX_TIMERS];
234 done = 0;
235 counter = 1;
236 odd = 1;
237 size_t i = 0;
238 long secs = 0;
239 for ( ; i < ACE_MAX_TIMERS; i++, secs++)
241 which[i] = i;
242 t_id[i] = ACE_Proactor::instance ()->schedule_timer
243 (rt[i], &which[i], ACE_Time_Value (2 * secs + 1));
244 if (t_id[i] == -1)
245 ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("schedule_timer")));
246 rt[i].timer_id (t_id[i]);
249 for (i = 0; i < ACE_MAX_TIMERS; i++)
250 // Cancel handlers with odd numbered timer ids.
251 if (ACE_ODD (rt[i].timer_id ()))
253 if (ACE_Proactor::instance ()->cancel_timer (rt[i].timer_id ()) == -1)
254 ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("cancel_timer")));
257 while (!done)
258 ACE_Proactor::instance ()->handle_events ();
261 static void
262 test_cancel_repeat_timer ()
264 Repeat_Timer_Handler *handler = new Repeat_Timer_Handler;
265 ACE_Time_Value timeout (Repeat_Timer_Handler::REPEAT_INTERVAL);
266 long t_id = ACE_Proactor::instance ()->schedule_repeating_timer
267 (*handler, 0, timeout);
268 if (t_id == -1)
270 ACE_ERROR ((LM_ERROR,
271 ACE_TEXT ("%p\n"),
272 ACE_TEXT ("schedule_repeating_timer")));
273 delete handler;
274 return;
277 ACE_Time_Value test_timer (4 * Repeat_Timer_Handler::REPEAT_INTERVAL);
278 if (-1 == ACE_Proactor::instance ()->proactor_run_event_loop (test_timer))
279 ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("proactor loop fail")));
281 // handler should be deleted by its own handle_time_out().
282 return;
286 // If any command line arg is given, run the test with high res timer
287 // queue. Else run it normally.
289 run_main (int argc, ACE_TCHAR *[])
291 ACE_START_TEST (ACE_TEXT ("Proactor_Timer_Test"));
293 if (argc > 1)
295 ACE_DEBUG ((LM_DEBUG,
296 ACE_TEXT ("Running with high-res timer queue\n")));
297 ACE_Proactor *r = ACE_Proactor::instance ();
299 (void) ACE_High_Res_Timer::global_scale_factor ();
301 // Change the source of time in the Proactor to the
302 // high-resolution timer. Why does this test require such
303 // precision for a 1 second timer is beyond me ... I think it
304 // is a cut&paste error.
306 // The use of auto_ptr<> is optional, ACE uses dangerous memory
307 // management idioms everywhere, I thought I could demonstrate how
308 // to do it right in at least one test. Notice the lack of
309 // ACE_NEW_RETURN, that monstrosity has no business in proper C++
310 // code ...
311 using Timer_Queue = ACE_Timer_Heap_T<ACE_Handler *, ACE_Proactor_Handle_Timeout_Upcall, ACE_MT_SYNCH::RECURSIVE_MUTEX, ACE_FPointer_Time_Policy>;
313 std::unique_ptr<Timer_Queue> tq(new Timer_Queue);
314 // ... notice how the policy is in the derived timer queue type.
315 // The abstract timer queue does not have a time policy ...
316 tq->set_time_policy(&ACE_High_Res_Timer::gettimeofday_hr);
317 // ... and then the timer queue is replaced. Strangely, the
318 // Proactor does *not* copy the timers, it just deletes the
319 // existing timer queue ....
320 r->timer_queue(tq.get());
321 // ... the Proactor has assumed ownership, release the
322 // auto_ptr<> ...
323 tq.release();
326 // Register all different handlers, i.e., one per timer.
327 test_registering_all_handlers ();
329 // Now try multiple timers for ONE event handler (should produce the
330 // same result).
331 test_registering_one_handler ();
333 // Try canceling handlers with odd numbered timer ids.
334 test_canceling_odd_timers ();
336 test_cancel_repeat_timer ();
338 ACE_END_TEST;
339 return 0;
342 #else
345 run_main (int, ACE_TCHAR *[])
347 ACE_START_TEST (ACE_TEXT ("Proactor_Timer_Test"));
349 ACE_DEBUG ((LM_INFO,
350 ACE_TEXT ("Asynchronous IO is unsupported.\n")
351 ACE_TEXT ("Proactor_Timer_Test will not be run.\n")));
353 ACE_END_TEST;
355 return 0;
358 #endif /* ACE_HAS_WIN32_OVERLAPPED_IO || ACE_HAS_AIO_CALLS */