2 //=============================================================================
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"
32 static size_t counter
= 0;
35 class Time_Handler
: public ACE_Handler
38 /// Default constructor
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;
51 /// Stores the id of this timer.
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
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
;
85 Time_Handler::Time_Handler ()
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
)
97 ACE_TEXT ("Expected timer %d, not %d\n"),
101 ACE_DEBUG ((LM_DEBUG
,
102 ACE_TEXT ("[%@] Timer id %d with counter #%d|%d expired.\n"),
108 if (current_counter
== (ACE_MAX_TIMERS
- 1))
110 else if (counter
== ACE_MAX_TIMERS
- 1)
116 counter
+= (1 + odd
);
121 Time_Handler::timer_id () const
123 return this->timer_id_
;
127 Time_Handler::timer_id (long 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")));
137 ACE_ERROR ((LM_ERROR
,
138 ACE_TEXT ("Repeater expired %d times; should be 2\n"),
139 this->expirations_
));
143 Repeat_Timer_Handler::handle_time_out (const ACE_Time_Value
&, const void *)
145 // Let the first one go.
146 if (++this->expirations_
== 1)
149 if (this->expirations_
== 2)
151 ACE_OS::sleep (this->repeat_secs_
+ 1);
152 int canceled
= this->proactor ()->cancel_timer (*this);
155 ACE_ERROR ((LM_ERROR
,
156 ACE_TEXT ("Repeater cancel timer: %d; should be 1\n"),
163 ACE_ERROR ((LM_ERROR
,
164 ACE_TEXT ("Repeater expiration #%d; should get only 2\n"),
165 this->expirations_
));
171 test_registering_all_handlers ()
173 ACE_Trace
t (ACE_TEXT ("test_registering_all_handler"),
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
];
181 for ( ; i
< ACE_MAX_TIMERS
; i
++, secs
++)
185 ACE_Proactor::instance ()->schedule_timer
186 (rt
[i
], &which
[i
], ACE_Time_Value (2 * secs
+ 1));
188 ACE_ERROR ((LM_ERROR
, ACE_TEXT ("%p\n"), ACE_TEXT ("schedule_timer")));
189 rt
[i
].timer_id (t_id
[i
]);
193 ACE_Proactor::instance ()->handle_events ();
197 test_registering_one_handler ()
199 ACE_Trace
t (ACE_TEXT ("test_registering_one_handler"),
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
];
210 for ( ; i
< ACE_MAX_TIMERS
; i
++, secs
++)
214 ACE_Proactor::instance ()->schedule_timer
215 (rt
[0], &which
[i
], ACE_Time_Value (2 * secs
+ 1));
217 ACE_ERROR ((LM_ERROR
, ACE_TEXT ("%p\n"), ACE_TEXT ("schedule_timer")));
221 ACE_Proactor::instance ()->handle_events ();
225 test_canceling_odd_timers ()
227 ACE_Trace
t (ACE_TEXT ("test_canceling_odd_timers"),
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
];
239 for ( ; i
< ACE_MAX_TIMERS
; i
++, secs
++)
242 t_id
[i
] = ACE_Proactor::instance ()->schedule_timer
243 (rt
[i
], &which
[i
], ACE_Time_Value (2 * secs
+ 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")));
258 ACE_Proactor::instance ()->handle_events ();
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
);
270 ACE_ERROR ((LM_ERROR
,
272 ACE_TEXT ("schedule_repeating_timer")));
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().
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"));
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++
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
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
331 test_registering_one_handler ();
333 // Try canceling handlers with odd numbered timer ids.
334 test_canceling_odd_timers ();
336 test_cancel_repeat_timer ();
345 run_main (int, ACE_TCHAR
*[])
347 ACE_START_TEST (ACE_TEXT ("Proactor_Timer_Test"));
350 ACE_TEXT ("Asynchronous IO is unsupported.\n")
351 ACE_TEXT ("Proactor_Timer_Test will not be run.\n")));
358 #endif /* ACE_HAS_WIN32_OVERLAPPED_IO || ACE_HAS_AIO_CALLS */