server/dep/acelite/ace/Timer_Queue_T.cpp
Salja f4be15a7af Some missing from merge.
Signed-off-by: Salja <salja2012@hotmail.de>
2020-02-16 02:50:23 +00:00

457 lines
15 KiB
C++

// $Id: Timer_Queue_T.cpp 97644 2014-03-07 11:59:51Z johnnyw $
#ifndef ACE_TIMER_QUEUE_T_CPP
#define ACE_TIMER_QUEUE_T_CPP
#include "ace/config-all.h"
#if !defined (ACE_LACKS_PRAGMA_ONCE)
# pragma once
#endif /* ACE_LACKS_PRAGMA_ONCE */
/*
* Hook to specialize to add includes
*/
//@@ REACTOR_SPL_INCLUDE_FORWARD_DECL_ADD_HOOK
#include "ace/Timer_Queue_T.h"
#include "ace/Guard_T.h"
#include "ace/Reverse_Lock_T.h"
#include "ace/Log_Category.h"
#include "ace/Null_Mutex.h"
#include "ace/OS_NS_sys_time.h"
#include "ace/Functor.h"
#if !defined (__ACE_INLINE__)
#include "ace/Timer_Queue_T.inl"
#endif /* __ACE_INLINE__ */
ACE_BEGIN_VERSIONED_NAMESPACE_DECL
// This fudge factor can be overriden for timers that need it, such as on
// Solaris, by defining the ACE_TIMER_SKEW symbol in the appropriate config
// header.
#if !defined (ACE_TIMER_SKEW)
# define ACE_TIMER_SKEW 0
#endif /* ACE_TIMER_SKEW */
template <class TYPE, class FUNCTOR> ACE_INLINE
ACE_Timer_Queue_Upcall_Base<TYPE, FUNCTOR>::ACE_Timer_Queue_Upcall_Base (FUNCTOR * upcall_functor)
: ACE_Abstract_Timer_Queue<TYPE>()
, ACE_Copy_Disabled()
, upcall_functor_(upcall_functor)
, delete_upcall_functor_ (upcall_functor == 0)
{
ACE_TRACE ("ACE_Timer_Queue_Upcall_Base::ACE_Timer_Queue_Upcall_Base");
if (upcall_functor != 0)
{
return;
}
ACE_NEW (upcall_functor_, FUNCTOR);
}
template <class TYPE, class FUNCTOR> ACE_INLINE
ACE_Timer_Queue_Upcall_Base<TYPE, FUNCTOR>::~ACE_Timer_Queue_Upcall_Base ()
{
ACE_TRACE ("ACE_Timer_Queue_Upcall_Base::~ACE_Timer_Queue_Upcall_Base");
if (this->delete_upcall_functor_)
{
delete this->upcall_functor_;
}
}
template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> ACE_Time_Value
ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::gettimeofday()
{
return this->gettimeofday_static();
}
template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> void
ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::gettimeofday (ACE_Time_Value (*gettimeofday)(void))
{
this->time_policy_.set_gettimeofday (gettimeofday);
}
template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> ACE_Time_Value *
ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::calculate_timeout (ACE_Time_Value *max_wait_time)
{
ACE_TRACE ("ACE_Timer_Queue_T::calculate_timeout");
ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, max_wait_time));
if (this->is_empty ())
// Nothing on the Timer_Queue, so use whatever the caller gave us.
return max_wait_time;
else
{
ACE_Time_Value const cur_time = this->gettimeofday_static ();
if (this->earliest_time () > cur_time)
{
// The earliest item on the Timer_Queue is still in the
// future. Therefore, use the smaller of (1) caller's wait
// time or (2) the delta time between now and the earliest
// time on the Timer_Queue.
this->timeout_ = this->earliest_time () - cur_time;
if (max_wait_time == 0 || *max_wait_time > timeout_)
return &this->timeout_;
else
return max_wait_time;
}
else
{
// The earliest item on the Timer_Queue is now in the past.
// Therefore, we've got to "poll" the Reactor, i.e., it must
// just check the descriptors and then dispatch timers, etc.
this->timeout_ = ACE_Time_Value::zero;
return &this->timeout_;
}
}
}
template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> ACE_Time_Value *
ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::calculate_timeout (ACE_Time_Value *max_wait_time,
ACE_Time_Value *the_timeout)
{
ACE_TRACE ("ACE_Timer_Queue_T::calculate_timeout");
if (the_timeout == 0)
return 0;
ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, max_wait_time));
if (this->is_empty ())
{
// Nothing on the Timer_Queue, so use whatever the caller gave us.
if (max_wait_time)
*the_timeout = *max_wait_time;
else
return 0;
}
else
{
ACE_Time_Value cur_time = this->gettimeofday_static ();
if (this->earliest_time () > cur_time)
{
// The earliest item on the Timer_Queue is still in the
// future. Therefore, use the smaller of (1) caller's wait
// time or (2) the delta time between now and the earliest
// time on the Timer_Queue.
*the_timeout = this->earliest_time () - cur_time;
if (!(max_wait_time == 0 || *max_wait_time > *the_timeout))
*the_timeout = *max_wait_time;
}
else
{
// The earliest item on the Timer_Queue is now in the past.
// Therefore, we've got to "poll" the Reactor, i.e., it must
// just check the descriptors and then dispatch timers, etc.
*the_timeout = ACE_Time_Value::zero;
}
}
return the_timeout;
}
template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> ACE_Time_Value
ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::current_time()
{
ACE_Time_Value tv = this->gettimeofday_static ();
tv += this->timer_skew();
return tv;
}
template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> void
ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::dump (void) const
{
#if defined (ACE_HAS_DUMP)
ACE_TRACE ("ACE_Timer_Queue_T::dump");
ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
this->timeout_.dump ();
this->timer_skew_.dump ();
ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP));
#endif /* ACE_HAS_DUMP */
}
template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::ACE_Timer_Queue_T (FUNCTOR *upcall_functor,
ACE_Free_List<ACE_Timer_Node_T <TYPE> > *freelist,
TIME_POLICY const & time_policy)
: ACE_Timer_Queue_Upcall_Base<TYPE,FUNCTOR>(upcall_functor),
time_policy_ (time_policy),
delete_free_list_ (freelist == 0),
timer_skew_ (0, ACE_TIMER_SKEW)
{
ACE_TRACE ("ACE_Timer_Queue_T::ACE_Timer_Queue_T");
if (!freelist)
ACE_NEW (free_list_,
(ACE_Locked_Free_List<ACE_Timer_Node_T<TYPE>,ACE_Null_Mutex>));
else
free_list_ = freelist;
}
template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::~ACE_Timer_Queue_T (void)
{
ACE_TRACE ("ACE_Timer_Queue_T::~ACE_Timer_Queue_T");
// Cleanup the free_list on the way out
if (this->delete_free_list_)
delete this->free_list_;
}
template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> ACE_Timer_Node_T<TYPE> *
ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::alloc_node (void)
{
return this->free_list_->remove ();
}
template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> void
ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::free_node (ACE_Timer_Node_T<TYPE> *node)
{
this->free_list_->add (node);
}
template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> ACE_LOCK &
ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::mutex (void)
{
return this->mutex_;
}
template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> long
ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::schedule (const TYPE &type,
const void *act,
const ACE_Time_Value &future_time,
const ACE_Time_Value &interval)
{
ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, -1));
// Schedule the timer.
long const result =
this->schedule_i (type,
act,
future_time,
interval);
// Return on failure.
if (result == -1)
return result;
// Inform upcall functor of successful registration.
this->upcall_functor ().registration (*this,
type,
act);
// Return result;
return result;
}
template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> int
ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::expire (void)
{
// We can't check here is the timer queue is empty, in some
// implementations (like the timer heap) calling is_empty()
// would at that moment access member variables without having
// locked ourself for thread safety
return this->expire (this->gettimeofday_static () + timer_skew_);
}
// Run the <handle_timeout> method for all Timers whose values are <=
// <cur_time>.
template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> int
ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::expire (const ACE_Time_Value &cur_time)
{
ACE_TRACE ("ACE_Timer_Queue_T::expire");
ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, -1));
// Keep looping while there are timers remaining and the earliest
// timer is <= the <cur_time> passed in to the method.
if (this->is_empty ())
return 0;
int number_of_timers_expired = 0;
int result = 0;
ACE_Timer_Node_Dispatch_Info_T<TYPE> info;
while ((result = this->dispatch_info_i (cur_time, info)) != 0)
{
ACE_MT (ACE_Reverse_Lock<ACE_LOCK> rev_lk(this->mutex_));
ACE_MT (ACE_GUARD_RETURN (ACE_Reverse_Lock<ACE_LOCK>, rmon, rev_lk, -1));
const void *upcall_act = 0;
this->preinvoke (info, cur_time, upcall_act);
this->upcall (info, cur_time);
this->postinvoke (info, cur_time, upcall_act);
++number_of_timers_expired;
}
ACE_UNUSED_ARG (result);
return number_of_timers_expired;
}
template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> void
ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::recompute_next_abs_interval_time
(ACE_Timer_Node_T<TYPE> *expired,
const ACE_Time_Value &cur_time)
{
if ( expired->get_timer_value () <= cur_time )
{
/*
* Somehow the current time is past when this time was
* supposed to expire (e.g., timer took too long,
* somebody changed system time, etc.). There used to
* be a simple loop here that skipped ahead one timer
* interval at a time, but that was horribly inefficient
* (an O(n) algorithm) when the timer duration was small
* relative to the amount of time skipped.
*
* So, we replace the loop with a simple computation,
* which also happens to be O(1). All times get
* normalized in the computation to microseconds.
*
* For reference, the loop looked like this:
*
* do
* expired->set_timer_value (expired->get_timer_value () +
* expired->get_interval ());
* while (expired->get_timer_value () <= cur_time);
*
*/
// Compute the duration of the timer's interval
ACE_UINT64 interval_usec;
expired->get_interval ().to_usec (interval_usec);
// Compute the span between the current time and when
// the timer would have expired in the past (and
// normalize to microseconds).
ACE_Time_Value old_diff = cur_time - expired->get_timer_value ();
ACE_UINT64 old_diff_usec;
old_diff.to_usec (old_diff_usec);
// Compute the delta time in the future when the timer
// should fire as if it had advanced incrementally. The
// modulo arithmetic accomodates the likely case that
// the current time doesn't fall precisely on a timer
// firing interval.
ACE_UINT64 new_timer_usec =
interval_usec - (old_diff_usec % interval_usec);
// Compute the absolute time in the future when this
// interval timer should expire.
ACE_Time_Value new_timer_value
(cur_time.sec ()
+ static_cast<time_t>(new_timer_usec / ACE_ONE_SECOND_IN_USECS),
cur_time.usec ()
+ static_cast<suseconds_t>(new_timer_usec % ACE_ONE_SECOND_IN_USECS));
expired->set_timer_value (new_timer_value);
}
}
template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> int
ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::expire_single (
ACE_Command_Base & pre_dispatch_command)
{
ACE_TRACE ("ACE_Timer_Queue_T::expire_single");
ACE_Timer_Node_Dispatch_Info_T<TYPE> info;
ACE_Time_Value cur_time;
{
// Create a scope for the lock ...
ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, -1));
if (this->is_empty ())
return 0;
// Get the current time
cur_time = this->gettimeofday_static () + this->timer_skew ();
// Look for a node in the timer queue whose timer <= the present
// time.
if (!this->dispatch_info_i (cur_time, info))
{
return 0;
}
}
// We do not need the lock anymore, all these operations take place
// with local variables.
const void *upcall_act = 0;
// Preinvoke (handles refcount if needed, etc.)
this->preinvoke (info, cur_time, upcall_act);
// Release the token before expiration upcall.
pre_dispatch_command.execute();
// call the functor
this->upcall (info, cur_time);
// Postinvoke (undo refcount if needed, etc.)
this->postinvoke (info, cur_time, upcall_act);
// We have dispatched a timer
return 1;
}
template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> int
ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::dispatch_info_i (const ACE_Time_Value &cur_time,
ACE_Timer_Node_Dispatch_Info_T<TYPE> &info)
{
ACE_TRACE ("ACE_Timer_Queue_T::dispatch_info_i");
if (this->is_empty ())
return 0;
ACE_Timer_Node_T<TYPE> *expired = 0;
if (this->earliest_time () <= cur_time)
{
expired = this->remove_first ();
// Get the dispatch info
expired->get_dispatch_info (info);
// Check if this is an interval timer.
if (expired->get_interval () > ACE_Time_Value::zero)
{
// Make sure that we skip past values that have already
// "expired".
this->recompute_next_abs_interval_time (expired, cur_time);
// Since this is an interval timer, we need to reschedule
// it.
this->reschedule (expired);
}
else
{
// Call the factory method to free up the node.
this->free_node (expired);
}
return 1;
}
return 0;
}
template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> void
ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::return_node (ACE_Timer_Node_T<TYPE> *node)
{
ACE_MT (ACE_GUARD (ACE_LOCK, ace_mon, this->mutex_));
this->free_node (node);
}
ACE_END_VERSIONED_NAMESPACE_DECL
#endif /* ACE_TIMER_QUEUE_T_CPP */