1 //=============================================================================
3 * @file Bug_4055_Regression_Test.cpp
5 * @author Johnny Willemsen (jwillemsen@remedy.nl)
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"
33 // Create timer queue with hr support
37 ACE_Timer_Queue
* tmq
= 0;
39 using timer_queue_type
= ACE_Timer_Heap_T
<ACE_Event_Handler
*, ACE_Event_Handler_Handle_Timeout_Upcall
, ACE_MT_SYNCH::RECURSIVE_MUTEX
, ACE_HR_Time_Policy
>;
40 ACE_NEW_RETURN (tmq
, timer_queue_type (), 0);
45 class MyTask
: public ACE_Task
<ACE_MT_SYNCH
>
48 MyTask () : my_reactor_ (0), my_tq_ (0) {}
50 ~MyTask () override
{ stop (); }
54 int start (int num_threads
);
56 ACE_Reactor
* get_reactor ();
57 int create_reactor ();
60 int delete_reactor ();
62 ACE_SYNCH_RECURSIVE_MUTEX lock_
;
63 ACE_Reactor
*my_reactor_
;
64 ACE_Timer_Queue
*my_tq_
;
68 MyTask::get_reactor ()
74 MyTask::create_reactor ()
76 ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX
,
81 ACE_TEST_ASSERT (this->my_reactor_
== 0);
83 this->my_tq_
= create_timer_queue ();
85 ACE_TP_Reactor
* pImpl
= 0;
86 ACE_NEW_RETURN (pImpl
,ACE_TP_Reactor (0, this->my_tq_
), -1);
88 ACE_NEW_RETURN (my_reactor_
,
89 ACE_Reactor (pImpl
,1),
93 ACE_TEXT (" (%t) Create TP_Reactor\n")));
95 this->reactor (my_reactor_
);
101 MyTask::delete_reactor ()
103 ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX
,
108 ACE_DEBUG ((LM_DEBUG
,
109 ACE_TEXT (" (%t) Delete TP_Reactor\n")));
112 delete this->my_reactor_
;
113 this->my_reactor_
= 0;
120 MyTask::start (int num_threads
)
122 if (this->activate (THR_NEW_LWP
, num_threads
) == -1)
123 ACE_ERROR_RETURN ((LM_ERROR
,
125 ACE_TEXT ("unable to activate thread pool")),
135 if (this->my_reactor_
!= 0)
137 ACE_DEBUG ((LM_DEBUG
,
138 ACE_TEXT ("End TP_Reactor event loop\n")));
140 this->my_reactor_
->end_reactor_event_loop ();
143 if (this->wait () == -1)
144 ACE_ERROR ((LM_ERROR
,
146 ACE_TEXT ("unable to stop thread pool")));
148 if (this->delete_reactor () == -1)
149 ACE_ERROR ((LM_ERROR
,
151 ACE_TEXT ("unable to delete reactor")));
159 ACE_DEBUG ((LM_DEBUG
, ACE_TEXT (" (%P|%t) MyTask started\n")));
161 while (this->my_reactor_
->reactor_event_loop_done () == 0)
162 this->my_reactor_
->run_reactor_event_loop ();
164 ACE_DEBUG ((LM_DEBUG
, ACE_TEXT (" (%t) MyTask finished\n")));
169 : public ACE_Event_Handler
172 TestHandler (ACE_Reactor
* reactor
)
173 : reactor_ (reactor
),
174 timeout_triggered_ (false)
177 int handle_timeout (const ACE_Time_Value
&tv
,
178 const void *arg
) override
;
180 bool trigger_in(const ACE_Time_Value
&delay
);
182 bool timeout_triggered () { return this->timeout_triggered_
; }
185 ACE_Reactor
* reactor_
;
186 bool timeout_triggered_
;
189 int TestHandler::handle_timeout (const ACE_Time_Value
&,
192 ACE_DEBUG ((LM_DEBUG
, "(%P|%t) TestHandler::handle_timeout - timeout triggered\n"));
193 this->timeout_triggered_
= true;
197 bool TestHandler::trigger_in(const ACE_Time_Value
&delay
)
199 ACE_DEBUG ((LM_DEBUG
, "(%P|%t) TestHandler::trigger_in - scheduling timer\n"));
200 return -1 != reactor_
->schedule_timer (this, 0, delay
, ACE_Time_Value (0));
203 bool test_timer (ACE_Condition_Thread_Mutex
& condition_
, ACE_Time_Value
& waittime
, bool monotonic
= false)
207 task1
.create_reactor ();
209 TestHandler
test_handler (task1
.get_reactor ());
211 // The second reactor that uses a hrtimer will trigger a timeout in
212 // 5 seconds. At the same moment we calculate a timeout for the condition
213 // 3 seconds in the future. Than we set the time 4 seconds back.
214 // at the moment now the condition timeouts the trigger should have not
215 // been executed. This is because with hrtime the trigger will call in 5
216 // seconds and the condition in 3 seconds, independent of any time change
217 // meaning that the timeout should trigger
218 if (!test_handler
.trigger_in (ACE_Time_Value (5, 0)))
219 ACE_ERROR_RETURN ((LM_ERROR
,
220 "(%P|%t) Unable to schedule trigger.\n"),
223 waittime
+= ACE_Time_Value (3,0);
225 // reset system clock 4 seconds backwards
226 ACE_Time_Value curtime
= ACE_OS::gettimeofday ();
227 curtime
-= ACE_Time_Value (4, 0);
228 # if defined (ACE_WIN32)
229 ACE_Date_Time
curdt (curtime
);
231 sys_time
.wDay
= ACE_Utils::truncate_cast
<WORD
> (curdt
.day ());
232 sys_time
.wMonth
= ACE_Utils::truncate_cast
<WORD
> (curdt
.month ());
233 sys_time
.wYear
= ACE_Utils::truncate_cast
<WORD
> (curdt
.year ());
234 sys_time
.wHour
= ACE_Utils::truncate_cast
<WORD
> (curdt
.hour ());
235 sys_time
.wMinute
= ACE_Utils::truncate_cast
<WORD
> (curdt
.minute ());
236 sys_time
.wSecond
= ACE_Utils::truncate_cast
<WORD
> (curdt
.second ());
237 sys_time
.wMilliseconds
= ACE_Utils::truncate_cast
<WORD
> (curdt
.microsec () / 1000);
238 if (!::SetLocalTime (&sys_time
))
242 if (ACE_OS::clock_settime (CLOCK_REALTIME
, &curts
) != 0)
246 "(%P|%t) Unable to reset OS time. Insufficient privileges or not supported.\n"));
251 "(%P|%t) Going to wait on condition until %#T.\n", &waittime
));
252 if (condition_
.wait (&waittime
) != -1 || errno
!= ETIME
)
254 ACE_ERROR ((LM_ERROR
, "ERROR: No errno or return -1\n"));
258 "(%P|%t) Condition wait returned at %#T.\n", &waittime
));
260 if (test_handler
.timeout_triggered ())
264 ACE_ERROR ((LM_ERROR
, "(%P|%t) ERROR: timer handler shouldn't have "
265 "triggered because we used monotonic condition timing!\n"));
269 ACE_DEBUG ((LM_INFO
, "(%P|%t) timer handler "
270 "triggered because we used non-monotonic condition timing!\n"));
276 ACE_ERROR ((LM_ERROR
, "(%P|%t) ERROR: timer handler should have "
277 "triggered because we used non-monotonic condition timing!\n"));
281 ACE_DEBUG ((LM_INFO
, "(%P|%t) timer handler has not "
282 "triggered because we used monotonic condition timing!\n"));
285 // reset system clock to correct time
286 curtime
= ACE_OS::gettimeofday ();
287 curtime
+= ACE_Time_Value (4, 0);
288 # if defined (ACE_WIN32)
289 curdt
.update (curtime
);
291 sys_time
.wDay
= ACE_Utils::truncate_cast
<WORD
> (curdt
.day ());
292 sys_time
.wMonth
= ACE_Utils::truncate_cast
<WORD
> (curdt
.month ());
293 sys_time
.wYear
= ACE_Utils::truncate_cast
<WORD
> (curdt
.year ());
294 sys_time
.wHour
= ACE_Utils::truncate_cast
<WORD
> (curdt
.hour ());
295 sys_time
.wMinute
= ACE_Utils::truncate_cast
<WORD
> (curdt
.minute ());
296 sys_time
.wSecond
= ACE_Utils::truncate_cast
<WORD
> (curdt
.second ());
297 sys_time
.wMilliseconds
= ACE_Utils::truncate_cast
<WORD
> (curdt
.microsec () / 1000);
298 if (!::SetLocalTime (&sys_time
))
301 if (ACE_OS::clock_settime (CLOCK_REALTIME
, &curts
) != 0)
305 "(%P|%t) Unable to reset OS time. Insufficient privileges or not supported.\n"));
310 "(%P|%t) Asking worker thread to finish.\n"));
313 ACE_Thread_Manager::instance ()->wait ();
320 run_main (int , ACE_TCHAR
*[])
322 ACE_START_TEST (ACE_TEXT ("Bug_4055_Regression_Test"));
323 # if defined (ACE_HAS_THREADS)
326 ACE_Thread_Mutex mutex_
;
327 ACE_Condition_Thread_Mutex
condition_ (mutex_
);
328 ACE_Condition_Attributes_T
<ACE_Monotonic_Time_Policy
> monotonic_cond_attr_
;
329 ACE_Condition_Thread_Mutex
monotonic_condition_ (mutex_
, monotonic_cond_attr_
);
331 if (mutex_
.acquire () != 0)
333 ACE_ERROR ((LM_ERROR
, "(%P|%t) ERROR: Failed to acquire mutex.\n"));
337 ACE_Time_Value waittime
;
338 waittime
= waittime
.now ();
339 if (test_timer (condition_
, waittime
))
341 ACE_Time_Value_T
<ACE_Monotonic_Time_Policy
> monotonic_waittime
;
342 monotonic_waittime
= monotonic_waittime
.now ();
343 if (test_timer (monotonic_condition_
, monotonic_waittime
, true))
357 run_main (int , ACE_TCHAR
*[])
359 ACE_START_TEST (ACE_TEXT ("Bug_4055_Regression_Test"));
361 "(%P|%t) ACE not compiled with monotonic time.\n"));