Merge pull request #1844 from jrw972/monterey
[ACE_TAO.git] / ACE / tests / Bug_4055_Regression_Test.cpp
blob4aa1d30a3c334184ee5815b71527404131803c62
1 //=============================================================================
2 /**
3 * @file Bug_4055_Regression_Test.cpp
5 * @author Johnny Willemsen (jwillemsen@remedy.nl)
6 */
7 //=============================================================================
9 #include "test_config.h"
10 #include "ace/Reactor.h"
11 #include "ace/Timer_Queue.h"
12 #include "ace/Time_Value_T.h"
13 #include "ace/Monotonic_Time_Policy.h"
14 #include "ace/Condition_Thread_Mutex.h"
15 #include "ace/Condition_Attributes.h"
16 #include "ace/OS_NS_sys_time.h"
17 #include "ace/High_Res_Timer.h"
18 #include "ace/Get_Opt.h"
19 #include "ace/Timer_Heap_T.h"
20 #include "ace/Event_Handler_Handle_Timeout_Upcall.h"
21 #include "ace/TP_Reactor.h"
22 #include "ace/Task_T.h"
23 #include "ace/Truncate.h"
25 #if defined (ACE_HAS_MONOTONIC_TIME_POLICY) && defined (ACE_HAS_MONOTONIC_CONDITIONS)
27 # if defined (ACE_HAS_THREADS)
29 # if defined (ACE_WIN32)
30 # include "ace/Date_Time.h"
31 # endif
33 // Create timer queue with hr support
34 ACE_Timer_Queue *
35 create_timer_queue (void)
37 ACE_Timer_Queue * tmq = 0;
39 typedef ACE_Timer_Heap_T<ACE_Event_Handler *,
40 ACE_Event_Handler_Handle_Timeout_Upcall,
41 ACE_SYNCH_RECURSIVE_MUTEX,
42 ACE_HR_Time_Policy> timer_queue_type;
43 ACE_NEW_RETURN (tmq, timer_queue_type (), 0);
45 return tmq;
48 class MyTask : public ACE_Task<ACE_MT_SYNCH>
50 public:
51 MyTask () : my_reactor_ (0), my_tq_ (0) {}
53 virtual ~MyTask () { stop (); }
55 virtual int svc (void);
57 int start (int num_threads);
58 int stop (void);
59 ACE_Reactor* get_reactor ();
60 int create_reactor (void);
62 private:
63 int delete_reactor (void);
65 ACE_SYNCH_RECURSIVE_MUTEX lock_;
66 ACE_Reactor *my_reactor_;
67 ACE_Timer_Queue *my_tq_;
70 ACE_Reactor*
71 MyTask::get_reactor ()
73 return my_reactor_;
76 int
77 MyTask::create_reactor (void)
79 ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX,
80 monitor,
81 this->lock_,
82 -1);
84 ACE_TEST_ASSERT (this->my_reactor_ == 0);
86 this->my_tq_ = create_timer_queue ();
88 ACE_TP_Reactor * pImpl = 0;
89 ACE_NEW_RETURN (pImpl,ACE_TP_Reactor (0, this->my_tq_), -1);
91 ACE_NEW_RETURN (my_reactor_,
92 ACE_Reactor (pImpl ,1),
93 -1);
95 ACE_DEBUG ((LM_DEBUG,
96 ACE_TEXT (" (%t) Create TP_Reactor\n")));
98 this->reactor (my_reactor_);
100 return 0;
104 MyTask::delete_reactor (void)
106 ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX,
107 monitor,
108 this->lock_,
109 -1);
111 ACE_DEBUG ((LM_DEBUG,
112 ACE_TEXT (" (%t) Delete TP_Reactor\n")));
114 this->reactor (0);
115 delete this->my_reactor_;
116 this->my_reactor_ = 0;
117 delete this->my_tq_;
118 this->my_tq_ = 0;
119 return 0;
123 MyTask::start (int num_threads)
125 if (this->activate (THR_NEW_LWP, num_threads) == -1)
126 ACE_ERROR_RETURN ((LM_ERROR,
127 ACE_TEXT ("%p.\n"),
128 ACE_TEXT ("unable to activate thread pool")),
129 -1);
131 return 0;
136 MyTask::stop (void)
138 if (this->my_reactor_ != 0)
140 ACE_DEBUG ((LM_DEBUG,
141 ACE_TEXT ("End TP_Reactor event loop\n")));
143 this->my_reactor_->end_reactor_event_loop ();
146 if (this->wait () == -1)
147 ACE_ERROR ((LM_ERROR,
148 ACE_TEXT ("%p.\n"),
149 ACE_TEXT ("unable to stop thread pool")));
151 if (this->delete_reactor () == -1)
152 ACE_ERROR ((LM_ERROR,
153 ACE_TEXT ("%p.\n"),
154 ACE_TEXT ("unable to delete reactor")));
156 return 0;
160 MyTask::svc (void)
162 ACE_DEBUG ((LM_DEBUG, ACE_TEXT (" (%P|%t) MyTask started\n")));
164 while (this->my_reactor_->reactor_event_loop_done () == 0)
165 this->my_reactor_->run_reactor_event_loop ();
167 ACE_DEBUG ((LM_DEBUG, ACE_TEXT (" (%t) MyTask finished\n")));
168 return 0;
171 class TestHandler
172 : public ACE_Event_Handler
174 public:
175 TestHandler (ACE_Reactor* reactor)
176 : reactor_ (reactor),
177 timeout_triggered_ (false)
180 virtual int handle_timeout (const ACE_Time_Value &tv,
181 const void *arg);
183 bool trigger_in(const ACE_Time_Value &delay);
185 bool timeout_triggered () { return this->timeout_triggered_; }
187 private:
188 ACE_Reactor* reactor_;
189 bool timeout_triggered_;
192 int TestHandler::handle_timeout (const ACE_Time_Value &,
193 const void *)
195 ACE_DEBUG ((LM_DEBUG, "(%P|%t) TestHandler::handle_timeout - timeout triggered\n"));
196 this->timeout_triggered_ = true;
197 return 0;
200 bool TestHandler::trigger_in(const ACE_Time_Value &delay)
202 ACE_DEBUG ((LM_DEBUG, "(%P|%t) TestHandler::trigger_in - scheduling timer\n"));
203 return -1 != reactor_->schedule_timer (this, 0, delay, ACE_Time_Value (0));
206 bool test_timer (ACE_Condition_Thread_Mutex& condition_, ACE_Time_Value& waittime, bool monotonic = false)
208 bool status = true;
209 MyTask task1;
210 task1.create_reactor ();
211 task1.start (1);
212 TestHandler test_handler (task1.get_reactor ());
214 // The second reactor that uses a hrtimer will trigger a timeout in
215 // 5 seconds. At the same moment we calculate a timeout for the condition
216 // 3 seconds in the future. Than we set the time 4 seconds back.
217 // at the moment now the condition timeouts the trigger should have not
218 // been executed. This is because with hrtime the trigger will call in 5
219 // seconds and the condition in 3 seconds, independent of any time change
220 // meaning that the timeout should trigger
221 if (!test_handler.trigger_in (ACE_Time_Value (5, 0)))
222 ACE_ERROR_RETURN ((LM_ERROR,
223 "(%P|%t) Unable to schedule trigger.\n"),
224 false);
226 waittime += ACE_Time_Value (3,0);
228 // reset system clock 4 seconds backwards
229 ACE_Time_Value curtime = ACE_OS::gettimeofday ();
230 curtime -= ACE_Time_Value (4, 0);
231 # if defined (ACE_WIN32)
232 ACE_Date_Time curdt (curtime);
233 SYSTEMTIME sys_time;
234 sys_time.wDay = ACE_Utils::truncate_cast <WORD> (curdt.day ());
235 sys_time.wMonth = ACE_Utils::truncate_cast <WORD> (curdt.month ());
236 sys_time.wYear = ACE_Utils::truncate_cast <WORD> (curdt.year ());
237 sys_time.wHour = ACE_Utils::truncate_cast <WORD> (curdt.hour ());
238 sys_time.wMinute = ACE_Utils::truncate_cast <WORD> (curdt.minute ());
239 sys_time.wSecond = ACE_Utils::truncate_cast <WORD> (curdt.second ());
240 sys_time.wMilliseconds = ACE_Utils::truncate_cast <WORD> (curdt.microsec () / 1000);
241 if (!::SetLocalTime (&sys_time))
242 # else
243 timespec_t curts;
244 curts = curtime;
245 if (ACE_OS::clock_settime (CLOCK_REALTIME, &curts) != 0)
246 # endif
248 ACE_DEBUG((LM_INFO,
249 "(%P|%t) Unable to reset OS time. Insufficient privileges or not supported.\n"));
251 else
253 ACE_DEBUG((LM_INFO,
254 "(%P|%t) Going to wait on condition until %#T.\n", &waittime));
255 if (condition_.wait (&waittime) != -1 || errno != ETIME)
257 ACE_ERROR ((LM_ERROR, "ERROR: No errno or return -1\n"));
258 status = 1;
260 ACE_DEBUG((LM_INFO,
261 "(%P|%t) Condition wait returned at %#T.\n", &waittime));
263 if (test_handler.timeout_triggered ())
265 if (monotonic)
267 ACE_ERROR ((LM_ERROR, "(%P|%t) ERROR: timer handler shouldn't have "
268 "triggered because we used monotonic condition timing!\n"));
269 status = false;
271 else
272 ACE_DEBUG ((LM_INFO, "(%P|%t) timer handler "
273 "triggered because we used non-monotonic condition timing!\n"));
275 else
277 if (!monotonic)
279 ACE_ERROR ((LM_ERROR, "(%P|%t) ERROR: timer handler should have "
280 "triggered because we used non-monotonic condition timing!\n"));
281 status = false;
283 else
284 ACE_DEBUG ((LM_INFO, "(%P|%t) timer handler has not "
285 "triggered because we used monotonic condition timing!\n"));
288 // reset system clock to correct time
289 curtime = ACE_OS::gettimeofday ();
290 curtime += ACE_Time_Value (4, 0);
291 # if defined (ACE_WIN32)
292 curdt.update (curtime);
293 SYSTEMTIME sys_time;
294 sys_time.wDay = ACE_Utils::truncate_cast <WORD> (curdt.day ());
295 sys_time.wMonth = ACE_Utils::truncate_cast <WORD> (curdt.month ());
296 sys_time.wYear = ACE_Utils::truncate_cast <WORD> (curdt.year ());
297 sys_time.wHour = ACE_Utils::truncate_cast <WORD> (curdt.hour ());
298 sys_time.wMinute = ACE_Utils::truncate_cast <WORD> (curdt.minute ());
299 sys_time.wSecond = ACE_Utils::truncate_cast <WORD> (curdt.second ());
300 sys_time.wMilliseconds = ACE_Utils::truncate_cast <WORD> (curdt.microsec () / 1000);
301 if (!::SetLocalTime (&sys_time))
302 # else
303 curts = curtime;
304 if (ACE_OS::clock_settime (CLOCK_REALTIME, &curts) != 0)
305 # endif
307 ACE_DEBUG((LM_INFO,
308 "(%P|%t) Unable to reset OS time. Insufficient privileges or not supported.\n"));
312 ACE_DEBUG((LM_INFO,
313 "(%P|%t) Asking worker thread to finish.\n"));
314 task1.stop ();
316 ACE_Thread_Manager::instance ()->wait ();
318 return status;
320 # endif
323 run_main (int , ACE_TCHAR *[])
325 ACE_START_TEST (ACE_TEXT ("Bug_4055_Regression_Test"));
326 # if defined (ACE_HAS_THREADS)
327 int status = 1;
329 ACE_Thread_Mutex mutex_;
330 ACE_Condition_Thread_Mutex condition_ (mutex_);
331 ACE_Condition_Attributes_T<ACE_Monotonic_Time_Policy> monotonic_cond_attr_;
332 ACE_Condition_Thread_Mutex monotonic_condition_ (mutex_, monotonic_cond_attr_);
334 if (mutex_.acquire () != 0)
336 ACE_ERROR ((LM_ERROR, "(%P|%t) ERROR: Failed to acquire mutex.\n"));
338 else
340 ACE_Time_Value waittime;
341 waittime = waittime.now ();
342 if (test_timer (condition_, waittime))
344 ACE_Time_Value_T<ACE_Monotonic_Time_Policy> monotonic_waittime;
345 monotonic_waittime = monotonic_waittime.now ();
346 if (test_timer (monotonic_condition_, monotonic_waittime, true))
347 status = 0;
350 # else
351 int status = 0;
352 # endif
353 ACE_END_TEST;
354 return status;
357 #else
360 run_main (int , ACE_TCHAR *[])
362 ACE_START_TEST (ACE_TEXT ("Bug_4055_Regression_Test"));
363 ACE_DEBUG((LM_INFO,
364 "(%P|%t) ACE not compiled with monotonic time.\n"));
365 ACE_END_TEST;
366 return 0;
369 #endif