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 */
10 #include "ace/Timer_Queue_T.h"
11 #include "ace/Guard_T.h"
12 #include "ace/Reverse_Lock_T.h"
13 #include "ace/Log_Category.h"
14 #include "ace/Null_Mutex.h"
15 #include "ace/OS_NS_sys_time.h"
16 #include "ace/Functor.h"
18 #if !defined (__ACE_INLINE__)
19 #include "ace/Timer_Queue_T.inl"
20 #endif /* __ACE_INLINE__ */
22 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
24 // This fudge factor can be overriden for timers that need it
25 // by defining the ACE_TIMER_SKEW symbol in the appropriate config
27 #if !defined (ACE_TIMER_SKEW)
28 # define ACE_TIMER_SKEW 0
29 #endif /* ACE_TIMER_SKEW */
31 template <class TYPE
, class FUNCTOR
> ACE_INLINE
32 ACE_Timer_Queue_Upcall_Base
<TYPE
, FUNCTOR
>::ACE_Timer_Queue_Upcall_Base (FUNCTOR
* upcall_functor
)
33 : ACE_Abstract_Timer_Queue
<TYPE
>()
35 , upcall_functor_(upcall_functor
)
36 , delete_upcall_functor_ (upcall_functor
== 0)
38 ACE_TRACE ("ACE_Timer_Queue_Upcall_Base::ACE_Timer_Queue_Upcall_Base");
40 if (upcall_functor
!= 0)
45 ACE_NEW (upcall_functor_
, FUNCTOR
);
48 template <class TYPE
, class FUNCTOR
> ACE_INLINE
49 ACE_Timer_Queue_Upcall_Base
<TYPE
, FUNCTOR
>::~ACE_Timer_Queue_Upcall_Base ()
51 ACE_TRACE ("ACE_Timer_Queue_Upcall_Base::~ACE_Timer_Queue_Upcall_Base");
52 if (this->delete_upcall_functor_
)
54 delete this->upcall_functor_
;
58 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> ACE_Time_Value
59 ACE_Timer_Queue_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::gettimeofday()
61 return this->gettimeofday_static();
64 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> void
65 ACE_Timer_Queue_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::gettimeofday (ACE_Time_Value (*gettimeofday
)())
67 this->time_policy_
.set_gettimeofday (gettimeofday
);
70 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> ACE_Time_Value
*
71 ACE_Timer_Queue_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::calculate_timeout (ACE_Time_Value
*max_wait_time
)
73 ACE_TRACE ("ACE_Timer_Queue_T::calculate_timeout");
74 ACE_MT (ACE_GUARD_RETURN (ACE_LOCK
, ace_mon
, this->mutex_
, max_wait_time
));
76 if (this->is_empty ())
77 // Nothing on the Timer_Queue, so use whatever the caller gave us.
81 ACE_Time_Value
const cur_time
= this->gettimeofday_static ();
83 if (this->earliest_time () > cur_time
)
85 // The earliest item on the Timer_Queue is still in the
86 // future. Therefore, use the smaller of (1) caller's wait
87 // time or (2) the delta time between now and the earliest
88 // time on the Timer_Queue.
90 this->timeout_
= this->earliest_time () - cur_time
;
91 if (max_wait_time
== 0 || *max_wait_time
> timeout_
)
92 return &this->timeout_
;
98 // The earliest item on the Timer_Queue is now in the past.
99 // Therefore, we've got to "poll" the Reactor, i.e., it must
100 // just check the descriptors and then dispatch timers, etc.
101 this->timeout_
= ACE_Time_Value::zero
;
102 return &this->timeout_
;
107 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> ACE_Time_Value
*
108 ACE_Timer_Queue_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::calculate_timeout (ACE_Time_Value
*max_wait_time
,
109 ACE_Time_Value
*the_timeout
)
111 ACE_TRACE ("ACE_Timer_Queue_T::calculate_timeout");
113 if (the_timeout
== 0)
116 ACE_MT (ACE_GUARD_RETURN (ACE_LOCK
, ace_mon
, this->mutex_
, max_wait_time
));
118 if (this->is_empty ())
120 // Nothing on the Timer_Queue, so use whatever the caller gave us.
122 *the_timeout
= *max_wait_time
;
128 ACE_Time_Value cur_time
= this->gettimeofday_static ();
130 if (this->earliest_time () > cur_time
)
132 // The earliest item on the Timer_Queue is still in the
133 // future. Therefore, use the smaller of (1) caller's wait
134 // time or (2) the delta time between now and the earliest
135 // time on the Timer_Queue.
137 *the_timeout
= this->earliest_time () - cur_time
;
138 if (!(max_wait_time
== 0 || *max_wait_time
> *the_timeout
))
139 *the_timeout
= *max_wait_time
;
143 // The earliest item on the Timer_Queue is now in the past.
144 // Therefore, we've got to "poll" the Reactor, i.e., it must
145 // just check the descriptors and then dispatch timers, etc.
146 *the_timeout
= ACE_Time_Value::zero
;
152 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> ACE_Time_Value
153 ACE_Timer_Queue_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::current_time()
155 ACE_Time_Value tv
= this->gettimeofday_static ();
156 tv
+= this->timer_skew();
160 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> void
161 ACE_Timer_Queue_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::dump () const
163 #if defined (ACE_HAS_DUMP)
164 ACE_TRACE ("ACE_Timer_Queue_T::dump");
165 ACELIB_DEBUG ((LM_DEBUG
, ACE_BEGIN_DUMP
, this));
166 this->timeout_
.dump ();
167 this->timer_skew_
.dump ();
168 ACELIB_DEBUG ((LM_DEBUG
, ACE_END_DUMP
));
169 #endif /* ACE_HAS_DUMP */
172 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
>
173 ACE_Timer_Queue_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::ACE_Timer_Queue_T (FUNCTOR
*upcall_functor
,
174 ACE_Free_List
<ACE_Timer_Node_T
<TYPE
> > *freelist
,
175 TIME_POLICY
const & time_policy
)
176 : ACE_Timer_Queue_Upcall_Base
<TYPE
,FUNCTOR
>(upcall_functor
),
177 time_policy_ (time_policy
),
178 delete_free_list_ (freelist
== 0),
179 timer_skew_ (0, ACE_TIMER_SKEW
)
181 ACE_TRACE ("ACE_Timer_Queue_T::ACE_Timer_Queue_T");
185 (ACE_Locked_Free_List
<ACE_Timer_Node_T
<TYPE
>,ACE_Null_Mutex
>));
187 free_list_
= freelist
;
190 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
>
191 ACE_Timer_Queue_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::~ACE_Timer_Queue_T ()
193 ACE_TRACE ("ACE_Timer_Queue_T::~ACE_Timer_Queue_T");
195 // Cleanup the free_list on the way out
196 if (this->delete_free_list_
)
197 delete this->free_list_
;
200 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> ACE_Timer_Node_T
<TYPE
> *
201 ACE_Timer_Queue_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::alloc_node ()
203 return this->free_list_
->remove ();
206 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> void
207 ACE_Timer_Queue_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::free_node (ACE_Timer_Node_T
<TYPE
> *node
)
209 this->free_list_
->add (node
);
212 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> ACE_LOCK
&
213 ACE_Timer_Queue_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::mutex ()
218 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> long
219 ACE_Timer_Queue_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::schedule (const TYPE
&type
,
221 const ACE_Time_Value
&future_time
,
222 const ACE_Time_Value
&interval
)
224 ACE_MT (ACE_GUARD_RETURN (ACE_LOCK
, ace_mon
, this->mutex_
, -1));
226 // Schedule the timer.
228 this->schedule_i (type
,
233 // Return on failure.
237 // Inform upcall functor of successful registration.
238 this->upcall_functor ().registration (*this,
246 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> int
247 ACE_Timer_Queue_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::expire ()
249 // We can't check here is the timer queue is empty, in some
250 // implementations (like the timer heap) calling is_empty()
251 // would at that moment access member variables without having
252 // locked ourself for thread safety
253 return this->expire (this->gettimeofday_static () + timer_skew_
);
256 // Run the <handle_timeout> method for all Timers whose values are <=
258 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> int
259 ACE_Timer_Queue_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::expire (const ACE_Time_Value
&cur_time
)
261 ACE_TRACE ("ACE_Timer_Queue_T::expire");
262 ACE_MT (ACE_GUARD_RETURN (ACE_LOCK
, ace_mon
, this->mutex_
, -1));
264 // Keep looping while there are timers remaining and the earliest
265 // timer is <= the <cur_time> passed in to the method.
267 if (this->is_empty ())
270 int number_of_timers_expired
= 0;
273 ACE_Timer_Node_Dispatch_Info_T
<TYPE
> info
;
275 while ((result
= this->dispatch_info_i (cur_time
, info
)) != 0)
277 ACE_MT (ACE_Reverse_Lock
<ACE_LOCK
> rev_lk(this->mutex_
));
278 ACE_MT (ACE_GUARD_RETURN (ACE_Reverse_Lock
<ACE_LOCK
>, rmon
, rev_lk
, -1));
280 const void *upcall_act
= 0;
282 this->preinvoke (info
, cur_time
, upcall_act
);
284 this->upcall (info
, cur_time
);
286 this->postinvoke (info
, cur_time
, upcall_act
);
288 ++number_of_timers_expired
;
291 ACE_UNUSED_ARG (result
);
292 return number_of_timers_expired
;
295 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> void
296 ACE_Timer_Queue_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::recompute_next_abs_interval_time
297 (ACE_Timer_Node_T
<TYPE
> *expired
,
298 const ACE_Time_Value
&cur_time
)
300 if ( expired
->get_timer_value () <= cur_time
)
303 * Somehow the current time is past when this time was
304 * supposed to expire (e.g., timer took too long,
305 * somebody changed system time, etc.). There used to
306 * be a simple loop here that skipped ahead one timer
307 * interval at a time, but that was horribly inefficient
308 * (an O(n) algorithm) when the timer duration was small
309 * relative to the amount of time skipped.
311 * So, we replace the loop with a simple computation,
312 * which also happens to be O(1). All times get
313 * normalized in the computation to microseconds.
315 * For reference, the loop looked like this:
318 * expired->set_timer_value (expired->get_timer_value () +
319 * expired->get_interval ());
320 * while (expired->get_timer_value () <= cur_time);
324 // Compute the duration of the timer's interval
325 ACE_UINT64 interval_usec
;
326 expired
->get_interval ().to_usec (interval_usec
);
328 // Compute the span between the current time and when
329 // the timer would have expired in the past (and
330 // normalize to microseconds).
331 ACE_Time_Value old_diff
= cur_time
- expired
->get_timer_value ();
332 ACE_UINT64 old_diff_usec
;
333 old_diff
.to_usec (old_diff_usec
);
335 // Compute the delta time in the future when the timer
336 // should fire as if it had advanced incrementally. The
337 // modulo arithmetic accomodates the likely case that
338 // the current time doesn't fall precisely on a timer
340 ACE_UINT64 new_timer_usec
=
341 interval_usec
- (old_diff_usec
% interval_usec
);
343 // Compute the absolute time in the future when this
344 // interval timer should expire.
345 ACE_Time_Value new_timer_value
347 + static_cast<time_t>(new_timer_usec
/ ACE_ONE_SECOND_IN_USECS
),
349 + static_cast<suseconds_t
>(new_timer_usec
% ACE_ONE_SECOND_IN_USECS
));
351 expired
->set_timer_value (new_timer_value
);
355 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> int
356 ACE_Timer_Queue_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::expire_single (
357 ACE_Command_Base
& pre_dispatch_command
)
359 ACE_TRACE ("ACE_Timer_Queue_T::expire_single");
360 ACE_Timer_Node_Dispatch_Info_T
<TYPE
> info
;
361 ACE_Time_Value cur_time
;
363 // Create a scope for the lock ...
364 ACE_MT (ACE_GUARD_RETURN (ACE_LOCK
, ace_mon
, this->mutex_
, -1));
366 if (this->is_empty ())
369 // Get the current time
370 cur_time
= this->gettimeofday_static () + this->timer_skew ();
372 // Look for a node in the timer queue whose timer <= the present
374 if (!this->dispatch_info_i (cur_time
, info
))
379 // We do not need the lock anymore, all these operations take place
380 // with local variables.
381 const void *upcall_act
= 0;
383 // Preinvoke (handles refcount if needed, etc.)
384 this->preinvoke (info
, cur_time
, upcall_act
);
386 // Release the token before expiration upcall.
387 pre_dispatch_command
.execute();
390 this->upcall (info
, cur_time
);
392 // Postinvoke (undo refcount if needed, etc.)
393 this->postinvoke (info
, cur_time
, upcall_act
);
395 // We have dispatched a timer
399 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> int
400 ACE_Timer_Queue_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::dispatch_info_i (const ACE_Time_Value
&cur_time
,
401 ACE_Timer_Node_Dispatch_Info_T
<TYPE
> &info
)
403 ACE_TRACE ("ACE_Timer_Queue_T::dispatch_info_i");
405 if (this->is_empty ())
408 if (this->earliest_time () <= cur_time
)
410 ACE_Timer_Node_T
<TYPE
> *expired
= this->remove_first ();
412 // Get the dispatch info
413 expired
->get_dispatch_info (info
);
415 // Check if this is an interval timer.
416 if (expired
->get_interval () > ACE_Time_Value::zero
)
418 // Make sure that we skip past values that have already
420 this->recompute_next_abs_interval_time (expired
, cur_time
);
422 // Since this is an interval timer, we need to reschedule
424 this->reschedule (expired
);
428 // Call the factory method to free up the node.
429 this->free_node (expired
);
438 template <class TYPE
, class FUNCTOR
, class ACE_LOCK
, typename TIME_POLICY
> void
439 ACE_Timer_Queue_T
<TYPE
, FUNCTOR
, ACE_LOCK
, TIME_POLICY
>::return_node (ACE_Timer_Node_T
<TYPE
> *node
)
441 ACE_MT (ACE_GUARD (ACE_LOCK
, ace_mon
, this->mutex_
));
442 this->free_node (node
);
445 ACE_END_VERSIONED_NAMESPACE_DECL
447 #endif /* ACE_TIMER_QUEUE_T_CPP */