#ifndef ACE_TIMER_LIST_T_C #define ACE_TIMER_LIST_T_C #include "ace/Timer_List_T.h" #include "ace/Guard_T.h" #include "ace/Log_Category.h" #if !defined (ACE_LACKS_PRAGMA_ONCE) # pragma once #endif /* ACE_LACKS_PRAGMA_ONCE */ // Default Constructor template ACE_Timer_List_Iterator_T::ACE_Timer_List_Iterator_T (List& lst) : list_ (lst) { this->first(); } template ACE_Timer_List_Iterator_T::~ACE_Timer_List_Iterator_T (void) { } // Positions the iterator at the node right after the dummy node template void ACE_Timer_List_Iterator_T::first (void) { this->current_node_ = this->list_.get_first(); } // Positions the iterator at the next node in the Timer Queue template void ACE_Timer_List_Iterator_T::next (void) { // Make sure that if we are at the end, we don't wrap around if (! this->isdone()) this->current_node_ = this->current_node_->get_next (); if (this->current_node_ == this->list_.head_) this->current_node_ = 0; } // Returns true when we are at template bool ACE_Timer_List_Iterator_T::isdone () const { return this->current_node_ == 0; } // Returns the node at or 0 if we are at the end template ACE_Timer_Node_T * ACE_Timer_List_Iterator_T::item (void) { if (! this->isdone()) return this->current_node_; return 0; } /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // Return our instance of the iterator template ACE_Timer_Queue_Iterator_T & ACE_Timer_List_T::iter (void) { this->iterator_->first (); return *this->iterator_; } // Create an empty list. template ACE_Timer_List_T::ACE_Timer_List_T (FUNCTOR* uf, FreeList* fl, TIME_POLICY const & time_policy) : Base_Timer_Queue (uf, fl, time_policy) , head_ (new ACE_Timer_Node_T) , id_counter_ (0) { ACE_TRACE ("ACE_Timer_List_T::ACE_Timer_List_T"); this->head_->set_next (this->head_); this->head_->set_prev (this->head_); ACE_NEW (iterator_, Iterator(*this)); } // Checks if list is empty. template bool ACE_Timer_List_T::is_empty () const { ACE_TRACE ("ACE_Timer_List_T::is_empty"); return this->get_first_i() == 0; } // Returns earliest time in a non-empty list. template const ACE_Time_Value & ACE_Timer_List_T::earliest_time () const { ACE_TRACE ("ACE_Timer_List_T::earliest_time"); ACE_Timer_Node_T* first = this->get_first_i(); if (first != 0) return first->get_timer_value (); return ACE_Time_Value::zero; } // Remove all remaining items in the list. template ACE_Timer_List_T::~ACE_Timer_List_T (void) { ACE_TRACE ("ACE_Timer_List_T::~ACE_Timer_List_T"); ACE_MT (ACE_GUARD (ACE_LOCK, ace_mon, this->mutex_)); delete iterator_; this->close (); // delete the dummy node delete this->head_; } template int ACE_Timer_List_T::close (void) { ACE_TRACE ("ACE_Timer_List_T::close"); ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, -1)); // Remove all remaining items in the list. if (!this->is_empty()) { for (ACE_Timer_Node_T* n = this->get_first(); n != this->head_; ) { this->upcall_functor ().deletion (*this, n->get_type(), n->get_act()); ACE_Timer_Node_T *next = n->get_next (); this->free_node (n); n = next; } } // Leave rest to destructor return 0; } template void ACE_Timer_List_T::dump () const { #if defined (ACE_HAS_DUMP) ACE_TRACE ("ACE_Timer_List_T::dump"); ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); int count = 0; ACE_Timer_Node_T* n = this->get_first_i(); if (n != 0) { for (; n != this->head_; n = n->get_next()) { ++count; } } ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nsize_ = %d"), count)); ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); #endif /* ACE_HAS_DUMP */ } // Reschedule a periodic timer. This function must be called with the // lock held. template void ACE_Timer_List_T::reschedule (ACE_Timer_Node_T* n) { ACE_TRACE ("ACE_Timer_List_T::reschedule"); this->schedule_i(n, n->get_timer_value()); } // Insert a new handler that expires at time future_time; if interval // is > 0, the handler will be reinvoked periodically. template long ACE_Timer_List_T::schedule_i (const TYPE &type, const void *act, const ACE_Time_Value &future_time, const ACE_Time_Value &interval) { ACE_TRACE ("ACE_Timer_List_T::schedule_i"); ACE_Timer_Node_T* n = this->alloc_node(); if (n != 0) { long id = this->id_counter_++; if (id != -1) { n->set (type, act, future_time, interval, 0, 0, id); this->schedule_i (n, future_time); } return id; } // Failure return errno = ENOMEM; return -1; } /// The shared scheduling functionality between schedule() and reschedule() template void ACE_Timer_List_T::schedule_i (ACE_Timer_Node_T* n, const ACE_Time_Value& expire) { if (this->is_empty()) { n->set_prev(this->head_); n->set_next(this->head_); this->head_->set_prev(n); this->head_->set_next(n); return; } // We always want to search backwards from the tail of the list, because // this minimizes the search in the extreme case when lots of timers are // scheduled for exactly the same time, and it also assumes that most of // the timers will be scheduled later than existing timers. ACE_Timer_Node_T* p = this->head_->get_prev(); while (p != this->head_ && p->get_timer_value() > expire) p = p->get_prev(); // insert after n->set_prev(p); n->set_next(p->get_next()); p->get_next()->set_prev(n); p->set_next(n); } template ACE_Timer_Node_T* ACE_Timer_List_T::find_node (long timer_id) const { ACE_Timer_Node_T* n = this->get_first_i(); if (n == 0) return 0; for (; n != this->head_; n = n->get_next()) { if (n->get_timer_id() == timer_id) { return n; } } return 0; } // Locate and update the inteval on the timer_id template int ACE_Timer_List_T::reset_interval (long timer_id, const ACE_Time_Value &interval) { ACE_TRACE ("ACE_Timer_List_T::reset_interval"); ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, -1)); ACE_Timer_Node_T* n = this->find_node(timer_id); if (n != 0) { n->set_interval(interval); // The interval will take effect the next time this node is expired. return 0; } return -1; } // Locate and remove the single with a value of // @a timer_id from the timer queue. template int ACE_Timer_List_T::cancel (long timer_id, const void **act, int skip_close) { ACE_TRACE ("ACE_Timer_List_T::cancel"); ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, -1)); ACE_Timer_Node_T* n = this->find_node(timer_id); if (n != 0) { if (act != 0) *act = n->get_act (); // Call the close hooks. int cookie = 0; // cancel_type() called once per . this->upcall_functor ().cancel_type (*this, n->get_type (), skip_close, cookie); // cancel_timer() called once per . this->upcall_functor ().cancel_timer (*this, n->get_type (), skip_close, cookie); this->cancel_i (n); return 1; } return 0; } // Locate and remove all values of from the timer queue. template int ACE_Timer_List_T::cancel (const TYPE &type, int skip_close) { ACE_TRACE ("ACE_Timer_List_T::cancel"); int num_canceled = 0; // Note : Technically this can overflow. int cookie = 0; ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, -1)); if (!this->is_empty ()) { for (ACE_Timer_Node_T* n = this->get_first(); n != this->head_; ) { if (n->get_type() == type) // Note: Typically Type is an ACE_Event_Handler* { ++num_canceled; ACE_Timer_Node_T* tmp = n; n = n->get_next(); this->cancel_i (tmp); } else { n = n->get_next(); } } } // Call the close hooks. // cancel_type() called once per . this->upcall_functor ().cancel_type (*this, type, skip_close, cookie); for (int i = 0; i < num_canceled; ++i) { // cancel_timer() called once per . this->upcall_functor ().cancel_timer (*this, type, skip_close, cookie); } return num_canceled; } template void ACE_Timer_List_T::unlink (ACE_Timer_Node_T* n) { n->get_prev()->set_next(n->get_next()); n->get_next()->set_prev(n->get_prev()); n->set_prev(0); n->set_next(0); } /// Shared subset of the two cancel() methods. template void ACE_Timer_List_T::cancel_i (ACE_Timer_Node_T* n) { this->unlink (n); this->free_node (n); } // Reads the first node on the list and returns it. template ACE_Timer_Node_T * ACE_Timer_List_T::get_first (void) { ACE_TRACE ("ACE_Timer_List_T::get_first"); return this->get_first_i(); } template ACE_Timer_Node_T * ACE_Timer_List_T::get_first_i () const { ACE_TRACE ("ACE_Timer_List_T::get_first_i"); ACE_Timer_Node_T* first = this->head_->get_next(); if (first != this->head_) // Note : is_empty() uses get_first() return first; return 0; } // Removes the first node on the list and returns it. template ACE_Timer_Node_T * ACE_Timer_List_T::remove_first (void) { ACE_TRACE ("ACE_Timer_List_T::remove_first"); ACE_Timer_Node_T* first = this->get_first(); if (first != 0) { this->unlink(first); return first; } return 0; } #endif /* ACE_TIMER_LIST_T_C */