2 //=============================================================================
4 * @file Monotonic_Task_Test.cpp
6 * This is a test that verifies the time policy features of the
8 * A template instantiation based on the ACE_Monotonic_Time_Policy
9 * is used to demonstrate the ability for making the task message queue
10 * timeouts independent from system time changes (time shift).
11 * Also demonstrated is how to instantiate a thread manager which is time
12 * shift independent (for its wait timeouts) using time policy support for
15 * @author Martin Corino <mcorino@remedy.nl>
17 //=============================================================================
20 #include "test_config.h"
21 #include "ace/Reactor.h"
22 #include "ace/Timer_Queue.h"
23 #include "ace/Thread_Manager.h"
24 #include "ace/Message_Queue.h"
25 #include "ace/Monotonic_Time_Policy.h"
26 #include "ace/Synch_Traits.h"
27 #include "ace/Timer_Heap_T.h"
28 #include "ace/Event_Handler_Handle_Timeout_Upcall.h"
29 #include "ace/TP_Reactor.h"
30 #include "ace/Task_T.h"
31 #include "ace/Truncate.h"
32 #include "ace/OS_NS_stdio.h"
33 #include "ace/OS_NS_string.h"
34 #include "ace/OS_NS_sys_time.h"
35 #include "ace/OS_NS_time.h"
36 #include "ace/OS_NS_unistd.h"
38 #if defined (ACE_HAS_MONOTONIC_TIME_POLICY) && defined (ACE_HAS_MONOTONIC_CONDITIONS)
40 # if defined (ACE_WIN32)
41 # include "ace/Date_Time.h"
44 # if defined (ACE_HAS_THREADS)
46 void set_system_time(const ACE_Time_Value
& tv
)
48 # if defined (ACE_WIN32)
49 ACE_Date_Time
curdt (tv
);
51 sys_time
.wDay
= ACE_Utils::truncate_cast
<WORD
> (curdt
.day ());
52 sys_time
.wMonth
= ACE_Utils::truncate_cast
<WORD
> (curdt
.month ());
53 sys_time
.wYear
= ACE_Utils::truncate_cast
<WORD
> (curdt
.year ());
54 sys_time
.wHour
= ACE_Utils::truncate_cast
<WORD
> (curdt
.hour ());
55 sys_time
.wMinute
= ACE_Utils::truncate_cast
<WORD
> (curdt
.minute ());
56 sys_time
.wSecond
= ACE_Utils::truncate_cast
<WORD
> (curdt
.second ());
57 sys_time
.wMilliseconds
= ACE_Utils::truncate_cast
<WORD
> (curdt
.microsec () / 1000);
58 if (!::SetLocalTime (&sys_time
))
62 if (ACE_OS::clock_settime (CLOCK_REALTIME
, &curts
) != 0)
66 "(%P|%t) Unable to reset OS time. Insufficient privileges or not supported.\n"));
70 class MyTask
: public ACE_Task
<ACE_MT_SYNCH
, ACE_Monotonic_Time_Policy
>
75 tm_ (monotonic_cond_attr_
),
76 cond_ (lock_
, monotonic_cond_attr_
),
79 // set monotonic timer aware thread manager for this task
80 this->thr_mgr (&this->tm_
);
83 ~MyTask () override
{ stop (); }
93 int status () { return this->status_
; }
97 ACE_Condition_Attributes_T
<ACE_Monotonic_Time_Policy
> monotonic_cond_attr_
;
98 ACE_Thread_Manager tm_
;
99 ACE_Thread_Mutex lock_
;
100 ACE_Condition
<ACE_Thread_Mutex
> cond_
;
107 ACE_DEBUG ((LM_DEBUG
, ACE_TEXT (" (%P|%t) Starting MyTask\n")));
109 ACE_GUARD_RETURN (ACE_Thread_Mutex
, ace_mon
, this->lock_
, -1);
111 if (this->activate (THR_NEW_LWP
, 1) == -1)
112 ACE_ERROR_RETURN ((LM_ERROR
,
114 ACE_TEXT ("unable to activate thread")),
117 if (this->cond_
.wait () != 0) // wait for task to start
119 ACE_ERROR_RETURN ((LM_ERROR
,
120 ACE_TEXT ("Failed waiting for thread")),
128 MyTask::put_message ()
130 const char S1
[] = "message";
132 ACE_GUARD_RETURN (ACE_Thread_Mutex
, ace_mon
, this->lock_
, -1);
134 // Now (according to task time policy = monotonic time)
135 ACE_Time_Value_T
<ACE_Monotonic_Time_Policy
> tv (this->gettimeofday ());
136 tv
+= ACE_Time_Value (5,0); // Now + 5 sec
138 // wait for signal; should not come causing us to sleep 5 sec (monotonic)
139 if (this->cond_
.wait (&tv
) == 0)
141 ACE_ERROR_RETURN ((LM_ERROR
,
142 ACE_TEXT ("(%P|%t) MyTask::put_message - Received signal from thread before timeout\n")),
146 ACE_DEBUG ((LM_DEBUG
, "(%P|%t) MyTask::put_message - queueing message\n"));
148 ACE_Message_Block
* mb1
= new ACE_Message_Block(S1
, sizeof S1
);
150 if (this->putq (mb1
) < 0)
152 ACE_ERROR_RETURN ((LM_ERROR
,
153 ACE_TEXT ("(%P|%t) MyTask::put_message - Failed to queue message\n")),
163 ACE_DEBUG ((LM_DEBUG
, ACE_TEXT (" (%P|%t) Stopping MyTask\n")));
166 ACE_GUARD_RETURN (ACE_Thread_Mutex
, ace_mon
, this->lock_
, -1);
170 if (this->cond_
.signal () != 0)
172 ACE_ERROR_RETURN ((LM_ERROR
,
173 ACE_TEXT ("Failed signalling thread\n")),
178 return this->wait ();
184 ACE_DEBUG ((LM_DEBUG
, ACE_TEXT (" (%P|%t) MyTask::svc started\n")));
186 // Now (according to task time policy = monotonic time)
187 ACE_Time_Value_T
<ACE_Monotonic_Time_Policy
> tv (this->gettimeofday ());
190 ACE_GUARD_RETURN (ACE_Thread_Mutex
, ace_mon
, this->lock_
, -1);
192 ACE_DEBUG ((LM_DEBUG
, ACE_TEXT (" (%P|%t) MyTask::svc - signalling waiter\n")));
194 this->cond_
.signal (); // signal waiter we have started
195 // waiter will shift system time back 4 sec after this which would mess
196 // up the first wait for a message if we were not using monotonic time
199 if (!this->msg_queue ()->is_empty ())
201 ACE_ERROR ((LM_ERROR
,
202 ACE_TEXT ("New task queue is not empty!\n")));
207 ACE_Message_Block
*b
;
208 tv
+= ACE_Time_Value (3,0); // Now + 3 sec
210 if (this->getq (b
, &tv
) != -1)
212 ACE_ERROR ((LM_ERROR
,
213 ACE_TEXT ("Dequeued before timeout elapsed!\n")));
216 else if (errno
!= EWOULDBLOCK
)
218 ACE_ERROR ((LM_ERROR
,
220 ACE_TEXT ("Dequeue timeout should be EWOULDBLOCK, got")));
225 ACE_Time_Value_T
<ACE_Monotonic_Time_Policy
> tv_now (this->gettimeofday ());
227 ACE_DEBUG ((LM_DEBUG
,
228 ACE_TEXT ("First getq timed out at %#T (timeout was %#T)\n"), &tv_now
, &tv
));
230 tv
= this->gettimeofday () + ACE_Time_Value (4,0); // Now (monotonic time) + 3 sec
231 if (this->getq (b
, &tv
) != -1)
235 ACE_DEBUG ((LM_DEBUG
,
236 ACE_TEXT ("Second getq succeeded at %#T\n"), &tv_now
));
241 ACE_ERROR ((LM_ERROR
,
242 ACE_TEXT ("Second getq timed out!\n")));
249 ACE_GUARD_RETURN (ACE_Thread_Mutex
, ace_mon
, this->lock_
, -1);
251 ACE_DEBUG ((LM_DEBUG
, ACE_TEXT (" (%P|%t) MyTask::svc - waiting for stop\n")));
257 ACE_DEBUG ((LM_DEBUG
, ACE_TEXT (" (%t) MyTask finished\n")));
261 # endif /* ACE_HAS_THREADS */
264 run_main (int , ACE_TCHAR
*[])
266 ACE_START_TEST (ACE_TEXT ("Monotonic_Task_Test"));
270 # if defined (ACE_HAS_THREADS)
273 if (my_task
.start () == 0)
275 // shift back in time 4 sec; this would mess up timeouts if
276 // monotonic timer was not used
277 ACE_Time_Value
tv_shift (4, 0);
278 set_system_time (ACE_OS::gettimeofday () - tv_shift
);
280 if (my_task
.put_message () == 0)
282 // task should now have finished dequeueing and started waiting for stop signal
283 // wait (2sec) on thread manager should timeout
285 // use the time policy aware gettimeofday()
286 // method of the task to get current time
287 ACE_Time_Value_T
<ACE_Monotonic_Time_Policy
> tv (my_task
.gettimeofday ());
288 tv
+= ACE_Time_Value (2, 0);
290 // shift another 3 sec back in time; without monotonic timer support in
291 // thread manager this would mess up the timed wait
292 tv_shift
+= ACE_Time_Value (3, 0);
293 set_system_time (ACE_OS::gettimeofday () - ACE_Time_Value (3,0));
295 if (my_task
.thr_mgr ()->wait (&tv
) == 0)
297 ACE_ERROR ((LM_ERROR
, ACE_TEXT ("Thread manager did not time out\n")));
302 ACE_Time_Value_T
<ACE_Monotonic_Time_Policy
> tv_now (my_task
.gettimeofday ());
304 ACE_DEBUG ((LM_INFO
, ACE_TEXT ("Thread manager timed out at %#T\n"), &tv_now
));
311 if (my_task
.stop () != 0)
313 ACE_ERROR ((LM_ERROR
, ACE_TEXT ("Failed to stop task\n")));
318 set_system_time (ACE_OS::gettimeofday () + tv_shift
);
323 # endif /* ACE_HAS_THREADS */
332 run_main (int , ACE_TCHAR
*[])
334 ACE_START_TEST (ACE_TEXT ("Monotonic_Task_Test"));
336 "(%P|%t) ACE not compiled with monotonic time.\n"));