1 #ifndef ACE_TIMER_QUEUE_T_CPP
2 #define ACE_TIMER_QUEUE_T_CPP
4 #include "ace/config-all.h"
6 #if !defined (ACE_LACKS_PRAGMA_ONCE)
8 #endif /* ACE_LACKS_PRAGMA_ONCE */
11 * Hook to specialize to add includes
13 //@@ REACTOR_SPL_INCLUDE_FORWARD_DECL_ADD_HOOK
15 #include "ace/Timer_Queue_T.h"
16 #include "ace/Guard_T.h"
17 #include "ace/Reverse_Lock_T.h"
18 #include "ace/Log_Category.h"
19 #include "ace/Null_Mutex.h"
20 #include "ace/OS_NS_sys_time.h"
21 #include "ace/Functor.h"
23 #if !defined (__ACE_INLINE__)
24 #include "ace/Timer_Queue_T.inl"
25 #endif /* __ACE_INLINE__ */
27 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
29 // This fudge factor can be overriden for timers that need it, such as on
30 // Solaris, by defining the ACE_TIMER_SKEW symbol in the appropriate config
32 #if !defined (ACE_TIMER_SKEW)
33 # define ACE_TIMER_SKEW 0
34 #endif /* ACE_TIMER_SKEW */
36 template <class TYPE
, class FUNCTOR
> ACE_INLINE
37 ACE_Timer_Queue_Upcall_Base
<TYPE
, FUNCTOR
>::ACE_Timer_Queue_Upcall_Base (FUNCTOR
* upcall_functor
)
38 : ACE_Abstract_Timer_Queue
<TYPE
>()
40 , upcall_functor_(upcall_functor
)
41 , delete_upcall_functor_ (upcall_functor
== 0)
43 ACE_TRACE ("ACE_Timer_Queue_Upcall_Base::ACE_Timer_Queue_Upcall_Base");
45 if (upcall_functor
!= 0)
50 ACE_NEW (upcall_functor_
, FUNCTOR
);
53 template <class TYPE
, class FUNCTOR
> ACE_INLINE
54 ACE_Timer_Queue_Upcall_Base
<TYPE
, FUNCTOR
>::~ACE_Timer_Queue_Upcall_Base ()
56 ACE_TRACE ("ACE_Timer_Queue_Upcall_Base::~ACE_Timer_Queue_Upcall_Base");
57 if (this->delete_upcall_functor_
)
59 delete this->upcall_functor_
;
63 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> ACE_Time_Value
64 ACE_Timer_Queue_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::gettimeofday()
66 return this->gettimeofday_static();
69 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> void
70 ACE_Timer_Queue_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::gettimeofday (ACE_Time_Value (*gettimeofday
)(void))
72 this->time_policy_
.set_gettimeofday (gettimeofday
);
75 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> ACE_Time_Value
*
76 ACE_Timer_Queue_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::calculate_timeout (ACE_Time_Value
*max_wait_time
)
78 ACE_TRACE ("ACE_Timer_Queue_T::calculate_timeout");
79 ACE_MT (ACE_GUARD_RETURN (ACE_LOCK
, ace_mon
, this->mutex_
, max_wait_time
));
81 if (this->is_empty ())
82 // Nothing on the Timer_Queue, so use whatever the caller gave us.
86 ACE_Time_Value
const cur_time
= this->gettimeofday_static ();
88 if (this->earliest_time () > cur_time
)
90 // The earliest item on the Timer_Queue is still in the
91 // future. Therefore, use the smaller of (1) caller's wait
92 // time or (2) the delta time between now and the earliest
93 // time on the Timer_Queue.
95 this->timeout_
= this->earliest_time () - cur_time
;
96 if (max_wait_time
== 0 || *max_wait_time
> timeout_
)
97 return &this->timeout_
;
103 // The earliest item on the Timer_Queue is now in the past.
104 // Therefore, we've got to "poll" the Reactor, i.e., it must
105 // just check the descriptors and then dispatch timers, etc.
106 this->timeout_
= ACE_Time_Value::zero
;
107 return &this->timeout_
;
112 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> ACE_Time_Value
*
113 ACE_Timer_Queue_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::calculate_timeout (ACE_Time_Value
*max_wait_time
,
114 ACE_Time_Value
*the_timeout
)
116 ACE_TRACE ("ACE_Timer_Queue_T::calculate_timeout");
118 if (the_timeout
== 0)
121 ACE_MT (ACE_GUARD_RETURN (ACE_LOCK
, ace_mon
, this->mutex_
, max_wait_time
));
123 if (this->is_empty ())
125 // Nothing on the Timer_Queue, so use whatever the caller gave us.
127 *the_timeout
= *max_wait_time
;
133 ACE_Time_Value cur_time
= this->gettimeofday_static ();
135 if (this->earliest_time () > cur_time
)
137 // The earliest item on the Timer_Queue is still in the
138 // future. Therefore, use the smaller of (1) caller's wait
139 // time or (2) the delta time between now and the earliest
140 // time on the Timer_Queue.
142 *the_timeout
= this->earliest_time () - cur_time
;
143 if (!(max_wait_time
== 0 || *max_wait_time
> *the_timeout
))
144 *the_timeout
= *max_wait_time
;
148 // The earliest item on the Timer_Queue is now in the past.
149 // Therefore, we've got to "poll" the Reactor, i.e., it must
150 // just check the descriptors and then dispatch timers, etc.
151 *the_timeout
= ACE_Time_Value::zero
;
157 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> ACE_Time_Value
158 ACE_Timer_Queue_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::current_time()
160 ACE_Time_Value tv
= this->gettimeofday_static ();
161 tv
+= this->timer_skew();
165 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> void
166 ACE_Timer_Queue_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::dump (void) const
168 #if defined (ACE_HAS_DUMP)
169 ACE_TRACE ("ACE_Timer_Queue_T::dump");
170 ACELIB_DEBUG ((LM_DEBUG
, ACE_BEGIN_DUMP
, this));
171 this->timeout_
.dump ();
172 this->timer_skew_
.dump ();
173 ACELIB_DEBUG ((LM_DEBUG
, ACE_END_DUMP
));
174 #endif /* ACE_HAS_DUMP */
177 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
>
178 ACE_Timer_Queue_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::ACE_Timer_Queue_T (FUNCTOR
*upcall_functor
,
179 ACE_Free_List
<ACE_Timer_Node_T
<TYPE
> > *freelist
,
180 TIME_POLICY
const & time_policy
)
181 : ACE_Timer_Queue_Upcall_Base
<TYPE
,FUNCTOR
>(upcall_functor
),
182 time_policy_ (time_policy
),
183 delete_free_list_ (freelist
== 0),
184 timer_skew_ (0, ACE_TIMER_SKEW
)
186 ACE_TRACE ("ACE_Timer_Queue_T::ACE_Timer_Queue_T");
190 (ACE_Locked_Free_List
<ACE_Timer_Node_T
<TYPE
>,ACE_Null_Mutex
>));
192 free_list_
= freelist
;
195 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
>
196 ACE_Timer_Queue_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::~ACE_Timer_Queue_T (void)
198 ACE_TRACE ("ACE_Timer_Queue_T::~ACE_Timer_Queue_T");
200 // Cleanup the free_list on the way out
201 if (this->delete_free_list_
)
202 delete this->free_list_
;
205 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> ACE_Timer_Node_T
<TYPE
> *
206 ACE_Timer_Queue_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::alloc_node (void)
208 return this->free_list_
->remove ();
211 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> void
212 ACE_Timer_Queue_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::free_node (ACE_Timer_Node_T
<TYPE
> *node
)
214 this->free_list_
->add (node
);
217 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> ACE_LOCK
&
218 ACE_Timer_Queue_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::mutex (void)
223 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> long
224 ACE_Timer_Queue_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::schedule (const TYPE
&type
,
226 const ACE_Time_Value
&future_time
,
227 const ACE_Time_Value
&interval
)
229 ACE_MT (ACE_GUARD_RETURN (ACE_LOCK
, ace_mon
, this->mutex_
, -1));
231 // Schedule the timer.
233 this->schedule_i (type
,
238 // Return on failure.
242 // Inform upcall functor of successful registration.
243 this->upcall_functor ().registration (*this,
251 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> int
252 ACE_Timer_Queue_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::expire (void)
254 // We can't check here is the timer queue is empty, in some
255 // implementations (like the timer heap) calling is_empty()
256 // would at that moment access member variables without having
257 // locked ourself for thread safety
258 return this->expire (this->gettimeofday_static () + timer_skew_
);
261 // Run the <handle_timeout> method for all Timers whose values are <=
263 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> int
264 ACE_Timer_Queue_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::expire (const ACE_Time_Value
&cur_time
)
266 ACE_TRACE ("ACE_Timer_Queue_T::expire");
267 ACE_MT (ACE_GUARD_RETURN (ACE_LOCK
, ace_mon
, this->mutex_
, -1));
269 // Keep looping while there are timers remaining and the earliest
270 // timer is <= the <cur_time> passed in to the method.
272 if (this->is_empty ())
275 int number_of_timers_expired
= 0;
278 ACE_Timer_Node_Dispatch_Info_T
<TYPE
> info
;
280 while ((result
= this->dispatch_info_i (cur_time
, info
)) != 0)
282 ACE_MT (ACE_Reverse_Lock
<ACE_LOCK
> rev_lk(this->mutex_
));
283 ACE_MT (ACE_GUARD_RETURN (ACE_Reverse_Lock
<ACE_LOCK
>, rmon
, rev_lk
, -1));
285 const void *upcall_act
= 0;
287 this->preinvoke (info
, cur_time
, upcall_act
);
289 this->upcall (info
, cur_time
);
291 this->postinvoke (info
, cur_time
, upcall_act
);
293 ++number_of_timers_expired
;
297 ACE_UNUSED_ARG (result
);
298 return number_of_timers_expired
;
301 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> void
302 ACE_Timer_Queue_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::recompute_next_abs_interval_time
303 (ACE_Timer_Node_T
<TYPE
> *expired
,
304 const ACE_Time_Value
&cur_time
)
306 if ( expired
->get_timer_value () <= cur_time
)
309 * Somehow the current time is past when this time was
310 * supposed to expire (e.g., timer took too long,
311 * somebody changed system time, etc.). There used to
312 * be a simple loop here that skipped ahead one timer
313 * interval at a time, but that was horribly inefficient
314 * (an O(n) algorithm) when the timer duration was small
315 * relative to the amount of time skipped.
317 * So, we replace the loop with a simple computation,
318 * which also happens to be O(1). All times get
319 * normalized in the computation to microseconds.
321 * For reference, the loop looked like this:
324 * expired->set_timer_value (expired->get_timer_value () +
325 * expired->get_interval ());
326 * while (expired->get_timer_value () <= cur_time);
330 // Compute the duration of the timer's interval
331 ACE_UINT64 interval_usec
;
332 expired
->get_interval ().to_usec (interval_usec
);
334 // Compute the span between the current time and when
335 // the timer would have expired in the past (and
336 // normalize to microseconds).
337 ACE_Time_Value old_diff
= cur_time
- expired
->get_timer_value ();
338 ACE_UINT64 old_diff_usec
;
339 old_diff
.to_usec (old_diff_usec
);
341 // Compute the delta time in the future when the timer
342 // should fire as if it had advanced incrementally. The
343 // modulo arithmetic accomodates the likely case that
344 // the current time doesn't fall precisely on a timer
346 ACE_UINT64 new_timer_usec
=
347 interval_usec
- (old_diff_usec
% interval_usec
);
349 // Compute the absolute time in the future when this
350 // interval timer should expire.
351 ACE_Time_Value new_timer_value
353 + static_cast<time_t>(new_timer_usec
/ ACE_ONE_SECOND_IN_USECS
),
355 + static_cast<suseconds_t
>(new_timer_usec
% ACE_ONE_SECOND_IN_USECS
));
357 expired
->set_timer_value (new_timer_value
);
361 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> int
362 ACE_Timer_Queue_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::expire_single (
363 ACE_Command_Base
& pre_dispatch_command
)
365 ACE_TRACE ("ACE_Timer_Queue_T::expire_single");
366 ACE_Timer_Node_Dispatch_Info_T
<TYPE
> info
;
367 ACE_Time_Value cur_time
;
369 // Create a scope for the lock ...
370 ACE_MT (ACE_GUARD_RETURN (ACE_LOCK
, ace_mon
, this->mutex_
, -1));
372 if (this->is_empty ())
375 // Get the current time
376 cur_time
= this->gettimeofday_static () + this->timer_skew ();
378 // Look for a node in the timer queue whose timer <= the present
380 if (!this->dispatch_info_i (cur_time
, info
))
385 // We do not need the lock anymore, all these operations take place
386 // with local variables.
387 const void *upcall_act
= 0;
389 // Preinvoke (handles refcount if needed, etc.)
390 this->preinvoke (info
, cur_time
, upcall_act
);
392 // Release the token before expiration upcall.
393 pre_dispatch_command
.execute();
396 this->upcall (info
, cur_time
);
398 // Postinvoke (undo refcount if needed, etc.)
399 this->postinvoke (info
, cur_time
, upcall_act
);
401 // We have dispatched a timer
405 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> int
406 ACE_Timer_Queue_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::dispatch_info_i (const ACE_Time_Value
&cur_time
,
407 ACE_Timer_Node_Dispatch_Info_T
<TYPE
> &info
)
409 ACE_TRACE ("ACE_Timer_Queue_T::dispatch_info_i");
411 if (this->is_empty ())
414 if (this->earliest_time () <= cur_time
)
416 ACE_Timer_Node_T
<TYPE
> *expired
= this->remove_first ();
418 // Get the dispatch info
419 expired
->get_dispatch_info (info
);
421 // Check if this is an interval timer.
422 if (expired
->get_interval () > ACE_Time_Value::zero
)
424 // Make sure that we skip past values that have already
426 this->recompute_next_abs_interval_time (expired
, cur_time
);
428 // Since this is an interval timer, we need to reschedule
430 this->reschedule (expired
);
434 // Call the factory method to free up the node.
435 this->free_node (expired
);
444 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> void
445 ACE_Timer_Queue_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::return_node (ACE_Timer_Node_T
<TYPE
> *node
)
447 ACE_MT (ACE_GUARD (ACE_LOCK
, ace_mon
, this->mutex_
));
448 this->free_node (node
);
451 ACE_END_VERSIONED_NAMESPACE_DECL
453 #endif /* ACE_TIMER_QUEUE_T_CPP */