2 //=============================================================================
4 * @file MT_Reactor_Timer_Test.cpp
6 * This is a simple test that illustrates the timer mechanism of
7 * the reactor scheduling timers, handling expired timers and
8 * cancelling scheduled timers from multiple threads. No command
9 * line arguments are needed to run the test.
11 * @author Steve Huston <shuston@riverace.com>
13 //=============================================================================
16 #include "test_config.h"
17 #include "MT_Reactor_Timer_Test.h"
19 #include "ace/OS_NS_unistd.h"
23 #if defined (ACE_HAS_THREADS)
25 // This test exercises the setting and cancelling of timers from a
26 // thread other than the one the reactor is running in. It sets up an
27 // initial set of timers (3, 4, 5 seconds) from the main thread. When
28 // the second thread starts, it cancels the 3 second timer and sets a
29 // 2-second timer and an already-expired timer, which should be the
30 // first to fire. It then sleeps for 3 seconds (letting the 2 second
31 // timer fire, and if things are slow, the 4 second timer will also
32 // fire. Then it sets 2 more timers at 10 and 12 seconds and cancels
33 // the original 5 second timer. Then returns, ending the thread. The
34 // destructor for Time_Handler insures that everything happened
37 Time_Handler::Time_Handler ()
40 i
< Time_Handler::TIMER_SLOTS
;
41 this->timer_id_
[i
++] = Time_Handler::TIMER_NOTSET
)
44 this->prev_timer_
= -1;
47 // Set up initial timer conditions. Timers set up at 3, 4, and 5
48 // seconds. The one at 3 seconds will get cancelled when the thread
52 Time_Handler::setup ()
54 ACE_Reactor
*r
= ACE_Reactor::instance ();
56 this->timer_id_
[2] = r
->schedule_timer (this,
59 this->timer_id_
[3] = r
->schedule_timer (this,
62 this->timer_id_
[4] = r
->schedule_timer (this,
69 Time_Handler::verify_results ()
71 ACE_TEST_ASSERT (this->timer_id_
[0] == Time_Handler::TIMER_FIRED
);
72 ACE_TEST_ASSERT (this->timer_id_
[1] == Time_Handler::TIMER_FIRED
);
73 ACE_TEST_ASSERT (this->timer_id_
[2] == Time_Handler::TIMER_CANCELLED
);
74 ACE_TEST_ASSERT (this->timer_id_
[3] == Time_Handler::TIMER_FIRED
);
75 ACE_TEST_ASSERT (this->timer_id_
[4] == Time_Handler::TIMER_CANCELLED
);
76 ACE_TEST_ASSERT (this->timer_id_
[5] == Time_Handler::TIMER_FIRED
);
77 ACE_TEST_ASSERT (this->timer_id_
[6] == Time_Handler::TIMER_FIRED
);
79 for (int i
= 7; i
< Time_Handler::TIMER_SLOTS
; i
++)
80 ACE_TEST_ASSERT (this->timer_id_
[i
] == Time_Handler::TIMER_NOTSET
);
88 ACE_Reactor
*r
= ACE_Reactor::instance ();
90 ACE_TEST_ASSERT (r
->cancel_timer (this->timer_id_
[2]) == 1);
91 this->timer_id_
[2] = Time_Handler::TIMER_CANCELLED
;
93 this->timer_id_
[1] = r
->schedule_timer(this,
96 // This one may get the callback before we return, so serialize.
97 this->lock_
.acquire ();
98 this->timer_id_
[0] = r
->schedule_timer(this,
100 ACE_Time_Value (0, -5));
101 this->lock_
.release ();
104 this->timer_id_
[5] = r
->schedule_timer(this,
106 ACE_Time_Value (10));
107 this->timer_id_
[6] = r
->schedule_timer(this,
109 ACE_Time_Value (12));
111 ACE_TEST_ASSERT (r
->cancel_timer (this->timer_id_
[4]) == 1);
112 this->timer_id_
[4] = Time_Handler::TIMER_CANCELLED
;
114 // Test that cancelling a timers through a nill ACE_Event_Handler
115 // pointer just does nothing instead of crash
116 ACE_Event_Handler_var timer_var
;
117 ACE_TEST_ASSERT (r
->cancel_timer (timer_var
.handler()) == 0);
123 Time_Handler::handle_timeout (const ACE_Time_Value
&tv
,
126 long time_tag
= static_cast <long> (reinterpret_cast <size_t> (arg
));
129 ACE_GUARD_RETURN (ACE_Thread_Mutex
, id_lock
, this->lock_
, 0);
131 ACE_DEBUG ((LM_DEBUG
,
132 ACE_TEXT ("%T (%t): Timer #%d (id #%d) expired\n"),
134 this->timer_id_
[time_tag
]));
136 ACE_TEST_ASSERT (time_tag
> this->prev_timer_
);
137 ACE_TEST_ASSERT (this->timer_id_
[time_tag
] != Time_Handler::TIMER_NOTSET
);
138 ACE_TEST_ASSERT (this->timer_id_
[time_tag
] != Time_Handler::TIMER_CANCELLED
);
139 ACE_TEST_ASSERT (this->timer_id_
[time_tag
] != Time_Handler::TIMER_FIRED
);
140 this->timer_id_
[time_tag
] = Time_Handler::TIMER_FIRED
;
141 this->prev_timer_
= time_tag
;
146 #endif /* ACE_HAS_THREADS */
148 Dispatch_Count_Handler::Dispatch_Count_Handler ()
151 ACE_Reactor
*r
= ACE_Reactor::instance ();
153 this->input_seen_
= this->notify_seen_
= 0;
154 this->timers_fired_
= 0;
156 // Initialize the pipe.
157 if (this->pipe_
.open () == -1)
158 ACE_ERROR ((LM_ERROR
,
160 ACE_TEXT ("ACE_Pipe::open")));
161 // Register the "read" end of the pipe.
162 else if (r
->register_handler (this->pipe_
.read_handle (),
164 ACE_Event_Handler::READ_MASK
) == -1)
165 ACE_ERROR ((LM_ERROR
,
167 ACE_TEXT ("register_handler")));
168 // Put something in our pipe and smoke it... ;-)
169 else if (ACE::send (this->pipe_
.write_handle (),
172 ACE_ERROR ((LM_ERROR
,
175 // Call notify to prime the pump for this, as well.
176 else if (r
->notify (this) == -1)
177 ACE_ERROR ((LM_ERROR
,
179 ACE_TEXT ("notify")));
183 Dispatch_Count_Handler::handle_close (ACE_HANDLE h
,
186 ACE_DEBUG ((LM_DEBUG
,
187 ACE_TEXT ("%T (%t): handle_close\n")));
189 ACE_TEST_ASSERT (h
== this->pipe_
.read_handle ()
190 && m
== ACE_Event_Handler::READ_MASK
);
196 Dispatch_Count_Handler::handle_input (ACE_HANDLE h
)
200 ACE_TEST_ASSERT (this->input_seen_
== 0);
201 this->input_seen_
= 1;
203 if (ACE::recv (h
, &c
, 1) != 1)
204 ACE_ERROR_RETURN ((LM_ERROR
,
209 ACE_TEST_ASSERT (c
== 'z');
210 ACE_DEBUG ((LM_DEBUG
,
211 ACE_TEXT ("%T (%t): handle_input\n")));
212 // Trigger the <handle_close> hook.
217 Dispatch_Count_Handler::handle_exception (ACE_HANDLE h
)
221 ACE_TEST_ASSERT (this->notify_seen_
== 0);
222 this->notify_seen_
= 1;
224 ACE_DEBUG ((LM_DEBUG
,
225 ACE_TEXT ("%T (%t): handle_exception\n")));
230 Dispatch_Count_Handler::handle_timeout (const ACE_Time_Value
&tv
,
235 ++this->timers_fired_
;
237 long value
= static_cast <long> (reinterpret_cast <size_t> (arg
));
239 // This case just tests to make sure the Reactor is counting timer
240 // expiration correctly.
241 ACE_DEBUG ((LM_DEBUG
,
242 ACE_TEXT ("%T (%t): expiration %d\n"),
248 Dispatch_Count_Handler::verify_results ()
252 if (this->input_seen_
!= 1)
254 ACE_ERROR ((LM_ERROR
,
255 ACE_TEXT ("input_seen_ is not 1 but %d\n"),
260 if (this->notify_seen_
!= 1)
262 ACE_ERROR ((LM_ERROR
,
263 ACE_TEXT ("notify_seen_ is not 1 but %d\n"),
268 if (this->timers_fired_
!= ACE_MAX_TIMERS
)
270 ACE_ERROR ((LM_ERROR
,
271 ACE_TEXT ("timers fired not equal max timers: %d != %d\n"),
281 run_main (int, ACE_TCHAR
*[])
283 ACE_START_TEST (ACE_TEXT ("MT_Reactor_Timer_Test"));
288 ACE_Reactor
*r
= ACE_Reactor::instance ();
290 Dispatch_Count_Handler callback
;
292 for (int i
= ACE_MAX_TIMERS
; i
> 0; i
--)
293 // Schedule a timeout to expire immediately.
294 if (r
->schedule_timer (&callback
,
295 reinterpret_cast <const void *> (static_cast <size_t> (i
)),
296 ACE_Time_Value (0)) == -1)
297 ACE_ERROR_RETURN ((LM_ERROR
,
299 ACE_TEXT ("schedule_timer")),
302 ACE_Time_Value
no_waiting (0);
307 int result
= r
->handle_events (no_waiting
);
313 // Make sure there were no errors.
314 ACE_TEST_ASSERT (result
!= -1);
319 // All <ACE_MAX_TIMERS> + 2 I/O dispatches (one for <handle_input>
320 // and the other for <handle_exception>) should be counted in
322 if (events
< ACE_MAX_TIMERS
+ 2)
324 ACE_ERROR ((LM_ERROR
,
325 ACE_TEXT ("expected %d events, got %d instead\n"),
330 status
= callback
.verify_results ();
333 ACE_ERROR ((LM_ERROR
,
334 ACE_TEXT ("Dispatch counting test failed.\n")));
338 #if defined (ACE_HAS_THREADS)
340 Time_Handler other_thread
;
341 ACE_Time_Value
time_limit (30);
343 // Set up initial set of timers.
344 other_thread
.setup ();
346 other_thread
.activate (THR_NEW_LWP
| THR_JOINABLE
);
347 status
= ACE_Reactor::instance()->run_reactor_event_loop (time_limit
);
348 // Should have returned only because the time limit is up...
349 ACE_TEST_ASSERT (status
!= -1);
350 ACE_TEST_ASSERT (time_limit
.sec () == 0);
352 status
= other_thread
.wait ();
355 ACE_ERROR ((LM_ERROR
,
356 ACE_TEXT ("%p, errno is %d\n"),
359 ACE_TEST_ASSERT (status
!= -1);
362 status
= other_thread
.verify_results ();
368 ACE_TEXT ("threads not supported on this platform\n")));
369 #endif /* ACE_HAS_THREADS */