ACE+TAO-7_0_8
[ACE_TAO.git] / ACE / tests / MT_Reactor_Timer_Test.cpp
blob85cedf6f5c446da608058015e06a9defc389a437
2 //=============================================================================
3 /**
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"
18 #include "ace/ACE.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
35 // correctly.
37 Time_Handler::Time_Handler ()
39 for (int i = 0;
40 i < Time_Handler::TIMER_SLOTS;
41 this->timer_id_[i++] = Time_Handler::TIMER_NOTSET)
42 continue;
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
49 // starts.
51 void
52 Time_Handler::setup ()
54 ACE_Reactor *r = ACE_Reactor::instance ();
56 this->timer_id_[2] = r->schedule_timer (this,
57 (const void *) 2,
58 ACE_Time_Value (3));
59 this->timer_id_[3] = r->schedule_timer (this,
60 (const void *) 3,
61 ACE_Time_Value (4));
62 this->timer_id_[4] = r->schedule_timer (this,
63 (const void *) 4,
64 ACE_Time_Value (5));
65 return;
68 int
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);
82 return 0;
85 int
86 Time_Handler::svc ()
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,
94 (const void *) 1,
95 ACE_Time_Value (2));
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,
99 (const void *) 0,
100 ACE_Time_Value (0, -5));
101 this->lock_.release ();
102 ACE_OS::sleep(3);
104 this->timer_id_[5] = r->schedule_timer(this,
105 (const void *)5,
106 ACE_Time_Value (10));
107 this->timer_id_[6] = r->schedule_timer(this,
108 (const void *)6,
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);
119 return 0;
123 Time_Handler::handle_timeout (const ACE_Time_Value &tv,
124 const void *arg)
126 long time_tag = static_cast <long> (reinterpret_cast <size_t> (arg));
127 ACE_UNUSED_ARG(tv);
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"),
133 time_tag,
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;
143 return 0;
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,
159 ACE_TEXT ("%p\n"),
160 ACE_TEXT ("ACE_Pipe::open")));
161 // Register the "read" end of the pipe.
162 else if (r->register_handler (this->pipe_.read_handle (),
163 this,
164 ACE_Event_Handler::READ_MASK) == -1)
165 ACE_ERROR ((LM_ERROR,
166 ACE_TEXT ("%p\n"),
167 ACE_TEXT ("register_handler")));
168 // Put something in our pipe and smoke it... ;-)
169 else if (ACE::send (this->pipe_.write_handle (),
170 "z",
171 1) == -1)
172 ACE_ERROR ((LM_ERROR,
173 ACE_TEXT ("%p\n"),
174 ACE_TEXT ("send")));
175 // Call notify to prime the pump for this, as well.
176 else if (r->notify (this) == -1)
177 ACE_ERROR ((LM_ERROR,
178 ACE_TEXT ("%p\n"),
179 ACE_TEXT ("notify")));
183 Dispatch_Count_Handler::handle_close (ACE_HANDLE h,
184 ACE_Reactor_Mask m)
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);
192 return 0;
196 Dispatch_Count_Handler::handle_input (ACE_HANDLE h)
198 char c;
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,
205 ACE_TEXT ("%p\n"),
206 ACE_TEXT ("recv")),
207 -1);
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.
213 return -1;
217 Dispatch_Count_Handler::handle_exception (ACE_HANDLE h)
219 ACE_UNUSED_ARG (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")));
226 return 0;
230 Dispatch_Count_Handler::handle_timeout (const ACE_Time_Value &tv,
231 const void *arg)
233 ACE_UNUSED_ARG (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"),
243 value));
244 return 0;
248 Dispatch_Count_Handler::verify_results ()
250 int result = 0;
252 if (this->input_seen_ != 1)
254 ACE_ERROR ((LM_ERROR,
255 ACE_TEXT ("input_seen_ is not 1 but %d\n"),
256 input_seen_));
257 result = -1;
260 if (this->notify_seen_ != 1)
262 ACE_ERROR ((LM_ERROR,
263 ACE_TEXT ("notify_seen_ is not 1 but %d\n"),
264 notify_seen_));
265 result = -1;
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"),
272 this->timers_fired_,
273 ACE_MAX_TIMERS));
274 result = -1;
277 return result;
281 run_main (int, ACE_TCHAR *[])
283 ACE_START_TEST (ACE_TEXT ("MT_Reactor_Timer_Test"));
285 int status = 0;
286 int test_result = 0;
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,
298 ACE_TEXT ("%p\n"),
299 ACE_TEXT ("schedule_timer")),
302 ACE_Time_Value no_waiting (0);
303 size_t events = 0;
305 while (1)
307 int result = r->handle_events (no_waiting);
309 // Timeout.
310 if (result == 0)
311 break;
313 // Make sure there were no errors.
314 ACE_TEST_ASSERT (result != -1);
316 events += result;
319 // All <ACE_MAX_TIMERS> + 2 I/O dispatches (one for <handle_input>
320 // and the other for <handle_exception>) should be counted in
321 // events.
322 if (events < ACE_MAX_TIMERS + 2)
324 ACE_ERROR ((LM_ERROR,
325 ACE_TEXT ("expected %d events, got %d instead\n"),
326 ACE_MAX_TIMERS + 2,
327 events));
330 status = callback.verify_results ();
331 if (status != 0)
333 ACE_ERROR ((LM_ERROR,
334 ACE_TEXT ("Dispatch counting test failed.\n")));
335 test_result = 1;
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 ();
353 if (status == -1)
355 ACE_ERROR ((LM_ERROR,
356 ACE_TEXT ("%p, errno is %d\n"),
357 "wait ()",
358 ACE_ERRNO_GET));
359 ACE_TEST_ASSERT (status != -1);
362 status = other_thread.verify_results ();
363 if (status != 0)
364 test_result = 1;
366 #else
367 ACE_ERROR ((LM_INFO,
368 ACE_TEXT ("threads not supported on this platform\n")));
369 #endif /* ACE_HAS_THREADS */
371 ACE_END_TEST;
372 return test_result;