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"
22 #if defined (ACE_HAS_THREADS)
24 // This test exercises the setting and cancelling of timers from a
25 // thread other than the one the reactor is running in. It sets up an
26 // initial set of timers (3, 4, 5 seconds) from the main thread. When
27 // the second thread starts, it cancels the 3 second timer and sets a
28 // 2-second timer and an already-expired timer, which should be the
29 // first to fire. It then sleeps for 3 seconds (letting the 2 second
30 // timer fire, and if things are slow, the 4 second timer will also
31 // fire. Then it sets 2 more timers at 10 and 12 seconds and cancels
32 // the original 5 second timer. Then returns, ending the thread. The
33 // destructor for Time_Handler insures that everything happened
36 Time_Handler::Time_Handler ()
39 i
< Time_Handler::TIMER_SLOTS
;
40 this->timer_id_
[i
++] = Time_Handler::TIMER_NOTSET
)
43 this->prev_timer_
= -1;
46 // Set up initial timer conditions. Timers set up at 3, 4, and 5
47 // seconds. The one at 3 seconds will get cancelled when the thread
51 Time_Handler::setup ()
53 ACE_Reactor
*r
= ACE_Reactor::instance ();
55 this->timer_id_
[2] = r
->schedule_timer (this,
58 this->timer_id_
[3] = r
->schedule_timer (this,
61 this->timer_id_
[4] = r
->schedule_timer (this,
68 Time_Handler::verify_results ()
70 ACE_TEST_ASSERT (this->timer_id_
[0] == Time_Handler::TIMER_FIRED
);
71 ACE_TEST_ASSERT (this->timer_id_
[1] == Time_Handler::TIMER_FIRED
);
72 ACE_TEST_ASSERT (this->timer_id_
[2] == Time_Handler::TIMER_CANCELLED
);
73 ACE_TEST_ASSERT (this->timer_id_
[3] == Time_Handler::TIMER_FIRED
);
74 ACE_TEST_ASSERT (this->timer_id_
[4] == Time_Handler::TIMER_CANCELLED
);
75 ACE_TEST_ASSERT (this->timer_id_
[5] == Time_Handler::TIMER_FIRED
);
76 ACE_TEST_ASSERT (this->timer_id_
[6] == Time_Handler::TIMER_FIRED
);
78 for (int i
= 7; i
< Time_Handler::TIMER_SLOTS
; i
++)
79 ACE_TEST_ASSERT (this->timer_id_
[i
] == Time_Handler::TIMER_NOTSET
);
87 ACE_Reactor
*r
= ACE_Reactor::instance ();
89 ACE_TEST_ASSERT (r
->cancel_timer (this->timer_id_
[2]) == 1);
90 this->timer_id_
[2] = Time_Handler::TIMER_CANCELLED
;
92 this->timer_id_
[1] = r
->schedule_timer(this,
95 // This one may get the callback before we return, so serialize.
96 this->lock_
.acquire ();
97 this->timer_id_
[0] = r
->schedule_timer(this,
99 ACE_Time_Value (0, -5));
100 this->lock_
.release ();
103 this->timer_id_
[5] = r
->schedule_timer(this,
105 ACE_Time_Value (10));
106 this->timer_id_
[6] = r
->schedule_timer(this,
108 ACE_Time_Value (12));
110 ACE_TEST_ASSERT (r
->cancel_timer (this->timer_id_
[4]) == 1);
111 this->timer_id_
[4] = Time_Handler::TIMER_CANCELLED
;
113 // Test that cancelling a timers through a nill ACE_Event_Handler
114 // pointer just does nothing instead of crash
115 ACE_Event_Handler_var timer_var
;
116 ACE_TEST_ASSERT (r
->cancel_timer (timer_var
.handler()) == 0);
122 Time_Handler::handle_timeout (const ACE_Time_Value
&tv
,
125 long time_tag
= static_cast <long> (reinterpret_cast <size_t> (arg
));
128 ACE_GUARD_RETURN (ACE_Thread_Mutex
, id_lock
, this->lock_
, 0);
130 ACE_DEBUG ((LM_DEBUG
,
131 ACE_TEXT ("%T (%t): Timer #%d (id #%d) expired\n"),
133 this->timer_id_
[time_tag
]));
135 ACE_TEST_ASSERT (time_tag
> this->prev_timer_
);
136 ACE_TEST_ASSERT (this->timer_id_
[time_tag
] != Time_Handler::TIMER_NOTSET
);
137 ACE_TEST_ASSERT (this->timer_id_
[time_tag
] != Time_Handler::TIMER_CANCELLED
);
138 ACE_TEST_ASSERT (this->timer_id_
[time_tag
] != Time_Handler::TIMER_FIRED
);
139 this->timer_id_
[time_tag
] = Time_Handler::TIMER_FIRED
;
140 this->prev_timer_
= time_tag
;
145 #endif /* ACE_HAS_THREADS */
147 Dispatch_Count_Handler::Dispatch_Count_Handler ()
149 ACE_Reactor
*r
= ACE_Reactor::instance ();
151 this->input_seen_
= this->notify_seen_
= 0;
152 this->timers_fired_
= 0;
154 // Initialize the pipe.
155 if (this->pipe_
.open () == -1)
156 ACE_ERROR ((LM_ERROR
,
158 ACE_TEXT ("ACE_Pipe::open")));
159 // Register the "read" end of the pipe.
160 else if (r
->register_handler (this->pipe_
.read_handle (),
162 ACE_Event_Handler::READ_MASK
) == -1)
163 ACE_ERROR ((LM_ERROR
,
165 ACE_TEXT ("register_handler")));
166 // Put something in our pipe and smoke it... ;-)
167 else if (ACE::send (this->pipe_
.write_handle (),
170 ACE_ERROR ((LM_ERROR
,
173 // Call notify to prime the pump for this, as well.
174 else if (r
->notify (this) == -1)
175 ACE_ERROR ((LM_ERROR
,
177 ACE_TEXT ("notify")));
181 Dispatch_Count_Handler::handle_close (ACE_HANDLE h
,
184 ACE_DEBUG ((LM_DEBUG
,
185 ACE_TEXT ("%T (%t): handle_close\n")));
187 ACE_TEST_ASSERT (h
== this->pipe_
.read_handle ()
188 && m
== ACE_Event_Handler::READ_MASK
);
194 Dispatch_Count_Handler::handle_input (ACE_HANDLE h
)
198 ACE_TEST_ASSERT (this->input_seen_
== 0);
199 this->input_seen_
= 1;
201 if (ACE::recv (h
, &c
, 1) != 1)
202 ACE_ERROR_RETURN ((LM_ERROR
,
207 ACE_TEST_ASSERT (c
== 'z');
208 ACE_DEBUG ((LM_DEBUG
,
209 ACE_TEXT ("%T (%t): handle_input\n")));
210 // Trigger the <handle_close> hook.
215 Dispatch_Count_Handler::handle_exception (ACE_HANDLE h
)
219 ACE_TEST_ASSERT (this->notify_seen_
== 0);
220 this->notify_seen_
= 1;
222 ACE_DEBUG ((LM_DEBUG
,
223 ACE_TEXT ("%T (%t): handle_exception\n")));
228 Dispatch_Count_Handler::handle_timeout (const ACE_Time_Value
&tv
,
233 ++this->timers_fired_
;
235 long value
= static_cast <long> (reinterpret_cast <size_t> (arg
));
237 // This case just tests to make sure the Reactor is counting timer
238 // expiration correctly.
239 ACE_DEBUG ((LM_DEBUG
,
240 ACE_TEXT ("%T (%t): expiration %d\n"),
246 Dispatch_Count_Handler::verify_results ()
250 if (this->input_seen_
!= 1)
252 ACE_ERROR ((LM_ERROR
,
253 ACE_TEXT ("input_seen_ is not 1 but %d\n"),
258 if (this->notify_seen_
!= 1)
260 ACE_ERROR ((LM_ERROR
,
261 ACE_TEXT ("notify_seen_ is not 1 but %d\n"),
266 if (this->timers_fired_
!= ACE_MAX_TIMERS
)
268 ACE_ERROR ((LM_ERROR
,
269 ACE_TEXT ("timers fired not equal max timers: %d != %d\n"),
279 run_main (int, ACE_TCHAR
*[])
281 ACE_START_TEST (ACE_TEXT ("MT_Reactor_Timer_Test"));
286 ACE_Reactor
*r
= ACE_Reactor::instance ();
288 Dispatch_Count_Handler callback
;
290 for (int i
= ACE_MAX_TIMERS
; i
> 0; i
--)
291 // Schedule a timeout to expire immediately.
292 if (r
->schedule_timer (&callback
,
293 reinterpret_cast <const void *> (static_cast <size_t> (i
)),
294 ACE_Time_Value (0)) == -1)
295 ACE_ERROR_RETURN ((LM_ERROR
,
297 ACE_TEXT ("schedule_timer")),
300 ACE_Time_Value
no_waiting (0);
305 int result
= r
->handle_events (no_waiting
);
311 // Make sure there were no errors.
312 ACE_TEST_ASSERT (result
!= -1);
317 // All <ACE_MAX_TIMERS> + 2 I/O dispatches (one for <handle_input>
318 // and the other for <handle_exception>) should be counted in
320 if (events
< ACE_MAX_TIMERS
+ 2)
322 ACE_ERROR ((LM_ERROR
,
323 ACE_TEXT ("expected %d events, got %d instead\n"),
328 status
= callback
.verify_results ();
331 ACE_ERROR ((LM_ERROR
,
332 ACE_TEXT ("Dispatch counting test failed.\n")));
336 #if defined (ACE_HAS_THREADS)
338 Time_Handler other_thread
;
339 ACE_Time_Value
time_limit (30);
341 // Set up initial set of timers.
342 other_thread
.setup ();
344 other_thread
.activate (THR_NEW_LWP
| THR_JOINABLE
);
345 status
= ACE_Reactor::instance()->run_reactor_event_loop (time_limit
);
346 // Should have returned only because the time limit is up...
347 ACE_TEST_ASSERT (status
!= -1);
348 ACE_TEST_ASSERT (time_limit
.sec () == 0);
350 status
= other_thread
.wait ();
353 ACE_ERROR ((LM_ERROR
,
354 ACE_TEXT ("%p, errno is %d\n"),
357 ACE_TEST_ASSERT (status
!= -1);
360 status
= other_thread
.verify_results ();
366 ACE_TEXT ("threads not supported on this platform\n")));
367 #endif /* ACE_HAS_THREADS */