#ifndef ACE_TIMER_HEAP_T_CPP #define ACE_TIMER_HEAP_T_CPP #include "ace/Timer_Heap_T.h" #include "ace/Log_Category.h" #include "ace/Guard_T.h" #include "ace/OS_NS_errno.h" #include "ace/OS_NS_string.h" #include "ace/Numeric_Limits.h" #if !defined (ACE_LACKS_PRAGMA_ONCE) # pragma once #endif /* ACE_LACKS_PRAGMA_ONCE */ /* ** The ACE_Timer_Heap::max_size_ and array loops, checks, etc. are all size_t. ** The timer IDs are long, and since they are indices into the heap, we need ** to be sure that the timer heap size can fit in a long. Hence, when size ** is (re)set, limit it to the maximum long value. We use the C++ standard ** limits if available. */ ACE_BEGIN_VERSIONED_NAMESPACE_DECL ACE_ALLOC_HOOK_DEFINE_Tccct(ACE_Timer_Heap_Iterator_T) ACE_ALLOC_HOOK_DEFINE_Tccct(ACE_Timer_Heap_T) // Define some simple inlined functions to clarify the code. inline size_t ACE_HEAP_PARENT (size_t X) { return (X == 0 ? 0 : ((X - 1) / 2)); } inline size_t ACE_HEAP_LCHILD (size_t X) { return X + X + 1; } // Constructor that takes in an to iterate over. template ACE_Timer_Heap_Iterator_T::ACE_Timer_Heap_Iterator_T ( Heap & heap) : timer_heap_ (heap) { ACE_TRACE ("ACE_Timer_Heap_Iterator_T::ACE_Timer_Heap_Iterator"); this->first (); } // Positions the iterator at the first node in the heap array template void ACE_Timer_Heap_Iterator_T::first () { this->position_ = 0; } // Positions the iterator at the next node in the heap array template void ACE_Timer_Heap_Iterator_T::next () { if (this->position_ != this->timer_heap_.cur_size_) ++this->position_; } // Returns true the is at the end of the heap array template bool ACE_Timer_Heap_Iterator_T::isdone () const { return this->position_ == this->timer_heap_.cur_size_; } // Returns the node at the current position in the heap or 0 if at the end template ACE_Timer_Node_T * ACE_Timer_Heap_Iterator_T::item () { if (this->position_ != this->timer_heap_.cur_size_) return this->timer_heap_.heap_[this->position_]; return 0; } // Constructor // Note that timer_ids_curr_ and timer_ids_min_free_ both start at 0. // Since timer IDs are assigned by first incrementing the timer_ids_curr_ // value, the first ID assigned will be 1 (just as in the previous design). // When it's time to wrap, the next ID given out will be 0. template ACE_Timer_Heap_T::ACE_Timer_Heap_T ( size_t size, bool preallocated, FUNCTOR *upcall_functor, ACE_Free_List > *freelist, TIME_POLICY const & time_policy) : Base_Time_Policy (upcall_functor, freelist, time_policy), max_size_ (size), cur_size_ (0), cur_limbo_ (0), iterator_ (nullptr), timer_ids_curr_ (0), timer_ids_min_free_ (0), preallocated_nodes_ (0), preallocated_nodes_freelist_ (0) { ACE_TRACE ("ACE_Timer_Heap_T::ACE_Timer_Heap_T"); // Possibly reduce size to fit in a long. if (size > static_cast (ACE_Numeric_Limits::max ())) { size = static_cast (ACE_Numeric_Limits::max ()); this->max_size_ = size; } // Create the heap array. #if defined (ACE_HAS_ALLOC_HOOKS) this->heap_ = reinterpret_cast **> (ACE_Allocator::instance ()->malloc (sizeof (ACE_Timer_Node_T *) * size)); #else ACE_NEW (this->heap_, ACE_Timer_Node_T *[size]); #endif /* ACE_HAS_ALLOC_HOOKS */ // Create the parallel ACE_NEW (this->timer_ids_, ssize_t[size]); // Initialize the "freelist," which uses negative values to // distinguish freelist elements from "pointers" into the // array. for (size_t i = 0; i < size; ++i) this->timer_ids_[i] = -1; if (preallocated) { ACE_NEW (this->preallocated_nodes_, ACE_Timer_Node_T[size]); // Add allocated array to set of such arrays for deletion on // cleanup. this->preallocated_node_set_.insert (this->preallocated_nodes_); // Form the freelist by linking the next_ pointers together. for (size_t j = 1; j < size; ++j) this->preallocated_nodes_[j - 1].set_next (&this->preallocated_nodes_[j]); // NULL-terminate the freelist. this->preallocated_nodes_[size - 1].set_next (0); // Assign the freelist pointer to the front of the list. this->preallocated_nodes_freelist_ = &this->preallocated_nodes_[0]; } ACE_NEW (iterator_, HEAP_ITERATOR (*this)); } // Note that timer_ids_curr_ and timer_ids_min_free_ both start at 0. // Since timer IDs are assigned by first incrementing the timer_ids_curr_ // value, the first ID assigned will be 1 (just as in the previous design). // When it's time to wrap, the next ID given out will be 0. template ACE_Timer_Heap_T::ACE_Timer_Heap_T ( FUNCTOR *upcall_functor, ACE_Free_List > *freelist, TIME_POLICY const & time_policy) : Base_Time_Policy (upcall_functor, freelist, time_policy), max_size_ (ACE_DEFAULT_TIMERS), cur_size_ (0), cur_limbo_ (0), timer_ids_curr_ (0), timer_ids_min_free_ (0), preallocated_nodes_ (0), preallocated_nodes_freelist_ (0) { ACE_TRACE ("ACE_Timer_Heap_T::ACE_Timer_Heap_T"); // Possibly reduce size to fit in a long. if (this->max_size_ > static_cast (ACE_Numeric_Limits::max ())) this->max_size_ = static_cast (ACE_Numeric_Limits::max ()); // Create the heap array. #if defined (ACE_HAS_ALLOC_HOOKS) this->heap_ = reinterpret_cast **> (ACE_Allocator::instance ()->malloc (sizeof (ACE_Timer_Node_T *) * this->max_size_)); #else ACE_NEW (this->heap_, ACE_Timer_Node_T *[this->max_size_]); #endif /* ACE_HAS_ALLOC_HOOKS */ // Create the parallel array. #if defined (ACE_HAS_ALLOC_HOOKS) this->timer_ids_ = reinterpret_cast (ACE_Allocator::instance ()->malloc (sizeof (ssize_t) * this->max_size_)); #else ACE_NEW (this->timer_ids_, ssize_t[this->max_size_]); #endif /* ACE_HAS_ALLOC_HOOKS */ // Initialize the "freelist," which uses negative values to // distinguish freelist elements from "pointers" into the // array. for (size_t i = 0; i < this->max_size_; ++i) this->timer_ids_[i] = -1; ACE_NEW (iterator_, HEAP_ITERATOR (*this)); } template ACE_Timer_Heap_T::~ACE_Timer_Heap_T () { ACE_TRACE ("ACE_Timer_Heap_T::~ACE_Timer_Heap_T"); delete iterator_; this->close (); #if defined (ACE_HAS_ALLOC_HOOKS) if (this->heap_) (ACE_Allocator::instance ()->free (this->heap_)); #else delete [] this->heap_; #endif /* ACE_HAS_ALLOC_HOOKS */ #if defined (ACE_HAS_ALLOC_HOOKS) if (this->timer_ids_) (ACE_Allocator::instance ()->free (this->timer_ids_)); #else delete [] this->timer_ids_; #endif /* ACE_HAS_ALLOC_HOOKS */ // clean up any preallocated timer nodes if (preallocated_nodes_ != 0) { ACE_Unbounded_Set_Iterator *> set_iterator (this->preallocated_node_set_); for (ACE_Timer_Node_T **entry = 0; set_iterator.next (entry) !=0; set_iterator.advance ()) delete [] *entry; } } template int ACE_Timer_Heap_T::close () { ACE_TRACE ("ACE_Timer_Heap_T::close"); size_t current_size = this->cur_size_; // Clean up all the nodes still in the queue for (size_t i = 0; i < current_size; ++i) { // Grab the event_handler and act, then delete the node before calling // back to the handler. Prevents a handler from trying to cancel_timer() // inside handle_close(), ripping the current timer node out from // under us. TYPE eh = this->heap_[i]->get_type (); const void *act = this->heap_[i]->get_act (); this->free_node (this->heap_[i]); this->upcall_functor ().deletion (*this, eh, act); } // leave the rest to the destructor return 0; } template long ACE_Timer_Heap_T::pop_freelist () { ACE_TRACE ("ACE_Timer_Heap_T::pop_freelist"); // Scan for a free timer ID. Note that since this function is called // _after_ the check for a full timer heap, we are guaranteed to find // a free ID, even if we need to wrap around and start reusing freed IDs. // On entry, the curr_ index is at the previous ID given out; start // up where we left off last time. // NOTE - a timer_ids_ slot with -2 is out of the heap, but not freed. // It must be either freed (free_node) or rescheduled (reschedule). ++this->timer_ids_curr_; while (this->timer_ids_curr_ < this->max_size_ && (this->timer_ids_[this->timer_ids_curr_] >= 0 || this->timer_ids_[this->timer_ids_curr_] == -2 )) ++this->timer_ids_curr_; if (this->timer_ids_curr_ == this->max_size_) { ACE_ASSERT (this->timer_ids_min_free_ < this->max_size_); this->timer_ids_curr_ = this->timer_ids_min_free_; // We restarted the free search at min. Since min won't be // free anymore, and curr_ will just keep marching up the list // on each successive need for an ID, reset min_free_ to the // size of the list until an ID is freed that curr_ has already // gone past (see push_freelist). this->timer_ids_min_free_ = this->max_size_; } return static_cast (this->timer_ids_curr_); } template void ACE_Timer_Heap_T::push_freelist (long old_id) { ACE_TRACE ("ACE_Timer_Heap_T::push_freelist"); // Since this ID has already been checked by one of the public // functions, it's safe to cast it here. size_t oldid = static_cast (old_id); // The freelist values in the are negative, so set the // freed entry back to 'free'. If this is the new lowest value free // timer ID that curr_ won't see on it's normal march through the list, // remember it. ACE_ASSERT (this->timer_ids_[oldid] >= 0 || this->timer_ids_[oldid] == -2); if (this->timer_ids_[oldid] == -2) --this->cur_limbo_; else --this->cur_size_; this->timer_ids_[oldid] = -1; if (oldid < this->timer_ids_min_free_ && oldid <= this->timer_ids_curr_) this->timer_ids_min_free_ = oldid; return; } template long ACE_Timer_Heap_T::timer_id () { ACE_TRACE ("ACE_Timer_Heap_T::timer_id"); // Return the next item off the freelist and use it as the timer id. return this->pop_freelist (); } // Checks if queue is empty. template bool ACE_Timer_Heap_T::is_empty () const { ACE_TRACE ("ACE_Timer_Heap_T::is_empty"); return this->cur_size_ == 0; } template ACE_Timer_Queue_Iterator_T & ACE_Timer_Heap_T::iter () { this->iterator_->first (); return *this->iterator_; } // Returns earliest time in a non-empty queue. template const ACE_Time_Value & ACE_Timer_Heap_T::earliest_time () const { ACE_TRACE ("ACE_Timer_Heap_T::earliest_time"); return this->heap_[0]->get_timer_value (); } template void ACE_Timer_Heap_T::dump () const { #if defined (ACE_HAS_DUMP) ACE_TRACE ("ACE_Timer_Heap_T::dump"); ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nmax_size_ = %d"), this->max_size_)); ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\ncur_size_ = %d"), this->cur_size_)); ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\ncur_limbo_= %d"), this->cur_limbo_)); ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nids_curr_ = %d"), this->timer_ids_curr_)); ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nmin_free_ = %d"), this->timer_ids_min_free_)); ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nheap_ =\n"))); for (size_t i = 0; i < this->cur_size_; ++i) { ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("%d\n"), i)); this->heap_[i]->dump (); } ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\ntimer_ids_ =\n"))); for (size_t j = 0; j < this->max_size_; ++j) ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("%d\t%d\n"), j, this->timer_ids_[j])); ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); #endif /* ACE_HAS_DUMP */ } template void ACE_Timer_Heap_T::copy ( size_t slot, ACE_Timer_Node_T *moved_node) { // Insert into its new location in the heap. this->heap_[slot] = moved_node; ACE_ASSERT (moved_node->get_timer_id () >= 0 && moved_node->get_timer_id () < (int) this->max_size_); // Update the corresponding slot in the parallel array. this->timer_ids_[moved_node->get_timer_id ()] = static_cast (slot); } // Remove the slot'th timer node from the heap, but do not reclaim its // timer ID or change the size of this timer heap object. The caller of // this function must call either free_node (to reclaim the timer ID // and the timer node memory, as well as decrement the size of the queue) // or reschedule (to reinsert the node in the heap at a new time). template ACE_Timer_Node_T * ACE_Timer_Heap_T::remove (size_t slot) { ACE_Timer_Node_T *removed_node = this->heap_[slot]; // NOTE - the cur_size_ is being decremented since the queue has one // less active timer in it. However, this ACE_Timer_Node is not being // freed, and there is still a place for it in timer_ids_ (the timer ID // is not being relinquished). The node can still be rescheduled, or // it can be freed via free_node. --this->cur_size_; // Only try to reheapify if we're not deleting the last entry. if (slot < this->cur_size_) { ACE_Timer_Node_T *moved_node = this->heap_[this->cur_size_]; // Move the end node to the location being removed and update // the corresponding slot in the parallel array. this->copy (slot, moved_node); // If the time_value_> is great than or equal its // parent it needs be moved down the heap. size_t parent = ACE_HEAP_PARENT (slot); if (moved_node->get_timer_value () >= this->heap_[parent]->get_timer_value ()) this->reheap_down (moved_node, slot, ACE_HEAP_LCHILD (slot)); else this->reheap_up (moved_node, slot, parent); } this->timer_ids_[removed_node->get_timer_id ()] = -2; ++this->cur_limbo_; return removed_node; } template void ACE_Timer_Heap_T::reheap_down ( ACE_Timer_Node_T *moved_node, size_t slot, size_t child) { // Restore the heap property after a deletion. while (child < this->cur_size_) { // Choose the smaller of the two children. if (child + 1 < this->cur_size_ && this->heap_[child + 1]->get_timer_value () < this->heap_[child]->get_timer_value ()) child++; // Perform a if the child has a larger timeout value than // the . if (this->heap_[child]->get_timer_value () < moved_node->get_timer_value ()) { this->copy (slot, this->heap_[child]); slot = child; child = ACE_HEAP_LCHILD (child); } else // We've found our location in the heap. break; } this->copy (slot, moved_node); } template void ACE_Timer_Heap_T::reheap_up ( ACE_Timer_Node_T *moved_node, size_t slot, size_t parent) { // Restore the heap property after an insertion. while (slot > 0) { // If the parent node is greater than the we need // to copy it down. if (moved_node->get_timer_value () < this->heap_[parent]->get_timer_value ()) { this->copy (slot, this->heap_[parent]); slot = parent; parent = ACE_HEAP_PARENT (slot); } else break; } // Insert the new node into its proper resting place in the heap and // update the corresponding slot in the parallel array. this->copy (slot, moved_node); } template void ACE_Timer_Heap_T::insert ( ACE_Timer_Node_T *new_node) { if (this->cur_size_ + this->cur_limbo_ + 2 >= this->max_size_) this->grow_heap (); this->reheap_up (new_node, this->cur_size_, ACE_HEAP_PARENT (this->cur_size_)); this->cur_size_++; } template void ACE_Timer_Heap_T::grow_heap () { // All the containers will double in size from max_size_. size_t new_size = this->max_size_ * 2; // First grow the heap itself. ACE_Timer_Node_T **new_heap = 0; #if defined (ACE_HAS_ALLOC_HOOKS) new_heap = reinterpret_cast **> (ACE_Allocator::instance ()->malloc (sizeof (ACE_Timer_Node_T *) * new_size)); #else ACE_NEW (new_heap, ACE_Timer_Node_T *[new_size]); #endif /* ACE_HAS_ALLOC_HOOKS */ ACE_OS::memcpy (new_heap, this->heap_, this->max_size_ * sizeof *new_heap); #if defined (ACE_HAS_ALLOC_HOOKS) ACE_Allocator::instance ()->free (this->heap_); #else delete [] this->heap_; #endif /* ACE_HAS_ALLOC_HOOKS */ this->heap_ = new_heap; // Grow the array of timer ids. ssize_t *new_timer_ids = 0; #if defined (ACE_HAS_ALLOC_HOOKS) new_timer_ids = reinterpret_cast (ACE_Allocator::instance ()->malloc (sizeof (ssize_t) * new_size)); #else ACE_NEW (new_timer_ids, ssize_t[new_size]); #endif /* ACE_HAS_ALLOC_HOOKS */ ACE_OS::memcpy (new_timer_ids, this->timer_ids_, this->max_size_ * sizeof (ssize_t)); #if defined (ACE_HAS_ALLOC_HOOKS) if (this->timer_ids_) (ACE_Allocator::instance ()->free (this->timer_ids_)); #else delete [] this->timer_ids_; #endif /* ACE_HAS_ALLOC_HOOKS */ this->timer_ids_ = new_timer_ids; // And add the new elements to the end of the "freelist". for (size_t i = this->max_size_; i < new_size; ++i) this->timer_ids_[i] = -(static_cast (i) + 1); // Grow the preallocation array (if using preallocation) if (this->preallocated_nodes_ != 0) { // Create a new array with max_size elements to link in to // existing list. ACE_NEW (this->preallocated_nodes_, ACE_Timer_Node_T[this->max_size_]); // Add it to the set for later deletion this->preallocated_node_set_.insert (this->preallocated_nodes_); // Link new nodes together (as for original list). for (size_t k = 1; k < this->max_size_; ++k) this->preallocated_nodes_[k - 1].set_next (&this->preallocated_nodes_[k]); // NULL-terminate the new list. this->preallocated_nodes_[this->max_size_ - 1].set_next (0); // Link new array to the end of the existling list. if (this->preallocated_nodes_freelist_ == 0) this->preallocated_nodes_freelist_ = &preallocated_nodes_[0]; else { ACE_Timer_Node_T *previous = this->preallocated_nodes_freelist_; for (ACE_Timer_Node_T *current = this->preallocated_nodes_freelist_->get_next (); current != 0; current = current->get_next ()) previous = current; previous->set_next (&this->preallocated_nodes_[0]); } } this->max_size_ = new_size; // Force rescan of list from beginning for a free slot (I think...) // This fixed Bugzilla #2447. this->timer_ids_min_free_ = this->max_size_; } // Reschedule a periodic timer. This function must be called with the // mutex lock held. template void ACE_Timer_Heap_T::reschedule ( ACE_Timer_Node_T *expired) { ACE_TRACE ("ACE_Timer_Heap_T::reschedule"); // If we are rescheduling, then the most recent call was to // remove_first (). That called remove () to remove the node from the // heap, but did not free the timer ID. The ACE_Timer_Node still has // its assigned ID - just needs to be inserted at the new proper // place, and the heap restored properly. if (this->timer_ids_[expired->get_timer_id ()] == -2) --this->cur_limbo_; this->insert (expired); } template ACE_Timer_Node_T * ACE_Timer_Heap_T::alloc_node () { ACE_Timer_Node_T *temp = 0; // Only allocate a node if we are *not* using the preallocated heap. if (this->preallocated_nodes_ == 0) ACE_NEW_RETURN (temp, ACE_Timer_Node_T, 0); else { // check to see if the heap needs to grow if (this->preallocated_nodes_freelist_ == 0) this->grow_heap (); temp = this->preallocated_nodes_freelist_; if (this->preallocated_nodes_freelist_) { // Remove the first element from the freelist. this->preallocated_nodes_freelist_ = this->preallocated_nodes_freelist_->get_next (); } } return temp; } template void ACE_Timer_Heap_T::free_node ( ACE_Timer_Node_T *node) { // Return this timer id to the freelist. this->push_freelist (node->get_timer_id ()); // Only free up a node if we are *not* using the preallocated heap. if (this->preallocated_nodes_ == 0) delete node; else { node->set_next (this->preallocated_nodes_freelist_); this->preallocated_nodes_freelist_ = node; } } // Insert a new timer that expires at time future_time; if interval is // > 0, the handler will be reinvoked periodically. template long ACE_Timer_Heap_T::schedule_i ( const TYPE &type, const void *act, const ACE_Time_Value &future_time, const ACE_Time_Value &interval) { ACE_TRACE ("ACE_Timer_Heap_T::schedule_i"); if ((this->cur_size_ + this->cur_limbo_) < this->max_size_) { // Obtain the next unique sequence number. long const timer_id = this->timer_id (); // Obtain the memory to the new node. ACE_Timer_Node_T *temp = 0; ACE_ALLOCATOR_RETURN (temp, this->alloc_node (), -1); temp->set (type, act, future_time, interval, 0, timer_id); this->insert (temp); return timer_id; } else return -1; } // Locate and remove the single timer with a value of @a timer_id from // the timer queue. template int ACE_Timer_Heap_T::cancel (long timer_id, const void **act, int dont_call) { ACE_TRACE ("ACE_Timer_Heap_T::cancel"); ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, -1)); // Locate the ACE_Timer_Node that corresponds to the timer_id. // Check to see if the timer_id is out of range if (timer_id < 0 || (size_t) timer_id > this->max_size_) return 0; ssize_t timer_node_slot = this->timer_ids_[timer_id]; // Check to see if timer_id is still valid. if (timer_node_slot < 0) return 0; if (timer_id != this->heap_[timer_node_slot]->get_timer_id ()) { ACE_ASSERT (timer_id == this->heap_[timer_node_slot]->get_timer_id ()); return 0; } else { ACE_Timer_Node_T *temp = this->remove (timer_node_slot); // Call the close hooks. int cookie = 0; // cancel_type() called once per . this->upcall_functor ().cancel_type (*this, temp->get_type (), dont_call, cookie); // cancel_timer() called once per . this->upcall_functor ().cancel_timer (*this, temp->get_type (), dont_call, cookie); if (act != 0) *act = temp->get_act (); this->free_node (temp); return 1; } } // Locate and update the inteval on the timer_id template int ACE_Timer_Heap_T::reset_interval (long timer_id, const ACE_Time_Value &interval) { ACE_TRACE ("ACE_Timer_Heap_T::reset_interval"); ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, -1)); // Locate the ACE_Timer_Node that corresponds to the timer_id. // Check to see if the timer_id is out of range if (timer_id < 0 || (size_t) timer_id > this->max_size_) return -1; ssize_t timer_node_slot = this->timer_ids_[timer_id]; // Check to see if timer_id is still valid. if (timer_node_slot < 0) return -1; if (timer_id != this->heap_[timer_node_slot]->get_timer_id ()) { ACE_ASSERT (timer_id == this->heap_[timer_node_slot]->get_timer_id ()); return -1; } else { // Reset the timer interval this->heap_[timer_node_slot]->set_interval (interval); return 0; } } // Locate and remove all values of @a type from the timer queue. template int ACE_Timer_Heap_T::cancel (const TYPE &type, int dont_call) { ACE_TRACE ("ACE_Timer_Heap_T::cancel"); ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, -1)); int number_of_cancellations = 0; // Try to locate the ACE_Timer_Node that matches the timer_id. for (size_t i = 0; i < this->cur_size_; ) { if (this->heap_[i]->get_type () == type) { ACE_Timer_Node_T *temp = this->remove (i); ++number_of_cancellations; this->free_node (temp); // We reset to zero so that we don't miss checking any nodes // if a reheapify occurs when a node is removed. There // may be a better fix than this, however. i = 0; } else ++i; } // Call the close hooks. int cookie = 0; // cancel_type() called once per . this->upcall_functor ().cancel_type (*this, type, dont_call, cookie); for (int j = 0; j < number_of_cancellations; ++j) { // cancel_timer() called once per . this->upcall_functor ().cancel_timer (*this, type, dont_call, cookie); } return number_of_cancellations; } // Returns the earliest node or returns 0 if the heap is empty. template ACE_Timer_Node_T * ACE_Timer_Heap_T::remove_first () { ACE_TRACE ("ACE_Timer_Heap_T::remove_first"); if (this->cur_size_ == 0) return 0; return this->remove (0); } template ACE_Timer_Node_T * ACE_Timer_Heap_T::get_first () { ACE_TRACE ("ACE_Timer_Heap_T::get_first"); return this->cur_size_ == 0 ? 0 : this->heap_[0]; } ACE_END_VERSIONED_NAMESPACE_DECL #endif /* ACE_TIMER_HEAP_T_CPP */