Timer_Heap_T.cpp

Go to the documentation of this file.
00001 // $Id: Timer_Heap_T.cpp 79134 2007-07-31 18:23:50Z johnnyw $
00002 
00003 #ifndef ACE_TIMER_HEAP_T_CPP
00004 #define ACE_TIMER_HEAP_T_CPP
00005 
00006 #include "ace/Timer_Heap_T.h"
00007 #include "ace/Log_Msg.h"
00008 #include "ace/Guard_T.h"
00009 #include "ace/OS_NS_errno.h"
00010 #include "ace/OS_NS_string.h"
00011 
00012 #if !defined (ACE_LACKS_PRAGMA_ONCE)
00013 # pragma once
00014 #endif /* ACE_LACKS_PRAGMA_ONCE */
00015 
00016 /*
00017 ** The ACE_Timer_Heap::max_size_ and array loops, checks, etc. are all size_t.
00018 ** The timer IDs are long, and since they are indices into the heap, we need
00019 ** to be sure that the timer heap size can fit in a long. Hence, when size
00020 ** is (re)set, limit it to the maximum long value. We use the C++ standard
00021 ** limits if available.
00022 */
00023 #if !defined(ACE_LACKS_NUMERIC_LIMITS)
00024 // some platforms pollute the namespace by defining max() and min() macros
00025 #ifdef max
00026 #undef max
00027 #endif
00028 #ifdef min
00029 #undef min
00030 #endif
00031 #include <limits>
00032 #endif /* ACE_LACKS_NUMERIC_LIMITS */
00033 
00034 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
00035 
00036 // Define some simple macros to clarify the code.
00037 #define ACE_HEAP_PARENT(X) (X == 0 ? 0 : (((X) - 1) / 2))
00038 #define ACE_HEAP_LCHILD(X) (((X)+(X))+1)
00039 
00040 // Constructor that takes in an <ACE_Timer_Heap_T> to iterate over.
00041 
00042 template <class TYPE, class FUNCTOR, class ACE_LOCK>
00043 ACE_Timer_Heap_Iterator_T<TYPE, FUNCTOR, ACE_LOCK>::ACE_Timer_Heap_Iterator_T (ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK> &heap)
00044   : timer_heap_ (heap)
00045 {
00046   ACE_TRACE ("ACE_Timer_Heap_Iterator_T::ACE_Timer_Heap_Iterator");
00047   this->first();
00048 }
00049 
00050 template <class TYPE, class FUNCTOR, class ACE_LOCK>
00051 ACE_Timer_Heap_Iterator_T<TYPE, FUNCTOR, ACE_LOCK>::~ACE_Timer_Heap_Iterator_T (void)
00052 {
00053 }
00054 
00055 // Positions the iterator at the first node in the heap array
00056 
00057 template <class TYPE, class FUNCTOR, class ACE_LOCK> void
00058 ACE_Timer_Heap_Iterator_T<TYPE, FUNCTOR, ACE_LOCK>::first (void)
00059 {
00060   this->position_ = 0;
00061 }
00062 
00063 // Positions the iterator at the next node in the heap array
00064 
00065 template <class TYPE, class FUNCTOR, class ACE_LOCK> void
00066 ACE_Timer_Heap_Iterator_T<TYPE, FUNCTOR, ACE_LOCK>::next (void)
00067 {
00068   if (this->position_ != this->timer_heap_.cur_size_)
00069     this->position_++;
00070 }
00071 
00072 // Returns true the <position_> is at the end of the heap array
00073 
00074 template <class TYPE, class FUNCTOR, class ACE_LOCK> int
00075 ACE_Timer_Heap_Iterator_T<TYPE, FUNCTOR, ACE_LOCK>::isdone (void) const
00076 {
00077   return this->position_ == this->timer_heap_.cur_size_;
00078 }
00079 
00080 // Returns the node at the current position in the heap or 0 if at the end
00081 
00082 template <class TYPE, class FUNCTOR, class ACE_LOCK> ACE_Timer_Node_T<TYPE> *
00083 ACE_Timer_Heap_Iterator_T<TYPE, FUNCTOR, ACE_LOCK>::item (void)
00084 {
00085   if (this->position_ != this->timer_heap_.cur_size_)
00086     return this->timer_heap_.heap_[this->position_];
00087   return 0;
00088 }
00089 
00090 // Constructor
00091 // Note that timer_ids_curr_ and timer_ids_min_free_ both start at 0.
00092 // Since timer IDs are assigned by first incrementing the timer_ids_curr_
00093 // value, the first ID assigned will be 1 (just as in the previous design).
00094 // When it's time to wrap, the next ID given out will be 0.
00095 template <class TYPE, class FUNCTOR, class ACE_LOCK>
00096 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::ACE_Timer_Heap_T (size_t size,
00097                                                              bool preallocated,
00098                                                              FUNCTOR *upcall_functor,
00099                                                              ACE_Free_List<ACE_Timer_Node_T <TYPE> > *freelist)
00100   : ACE_Timer_Queue_T<TYPE,FUNCTOR,ACE_LOCK> (upcall_functor, freelist),
00101     max_size_ (size),
00102     cur_size_ (0),
00103     cur_limbo_ (0),
00104     timer_ids_curr_ (0),
00105     timer_ids_min_free_ (0),
00106     preallocated_nodes_ (0),
00107     preallocated_nodes_freelist_ (0)
00108 {
00109   ACE_TRACE ("ACE_Timer_Heap_T::ACE_Timer_Heap_T");
00110 
00111   // Possibly reduce size to fit in a long.
00112 #if !defined(ACE_LACKS_NUMERIC_LIMITS)
00113   if (size > static_cast<size_t> (std::numeric_limits<long>::max ()))
00114     {
00115       size = static_cast<size_t> (std::numeric_limits<long>::max ());
00116       this->max_size_ = size;
00117     }
00118 #else
00119   if (size > LONG_MAX)
00120     {
00121       size = LONG_MAX;
00122       this->max_size_ = size;
00123     }
00124 #endif /* ACE_LACKS_NUMERIC_LIMITS */
00125 
00126   // Create the heap array.
00127   ACE_NEW (this->heap_,
00128            ACE_Timer_Node_T<TYPE> *[size]);
00129 
00130   // Create the parallel
00131   ACE_NEW (this->timer_ids_,
00132            ssize_t[size]);
00133 
00134   // Initialize the "freelist," which uses negative values to
00135   // distinguish freelist elements from "pointers" into the <heap_>
00136   // array.
00137   for (size_t i = 0; i < size; i++)
00138     this->timer_ids_[i] = -1;
00139 
00140   if (preallocated)
00141     {
00142       ACE_NEW (this->preallocated_nodes_,
00143                ACE_Timer_Node_T<TYPE>[size]);
00144 
00145       // Add allocated array to set of such arrays for deletion on
00146       // cleanup.
00147       this->preallocated_node_set_.insert (this->preallocated_nodes_);
00148 
00149       // Form the freelist by linking the next_ pointers together.
00150       for (size_t j = 1; j < size; j++)
00151         this->preallocated_nodes_[j - 1].set_next (&this->preallocated_nodes_[j]);
00152 
00153       // NULL-terminate the freelist.
00154       this->preallocated_nodes_[size - 1].set_next (0);
00155 
00156       // Assign the freelist pointer to the front of the list.
00157       this->preallocated_nodes_freelist_ =
00158         &this->preallocated_nodes_[0];
00159     }
00160 
00161   ACE_NEW (iterator_,
00162            HEAP_ITERATOR (*this));
00163 }
00164 
00165 // Note that timer_ids_curr_ and timer_ids_min_free_ both start at 0.
00166 // Since timer IDs are assigned by first incrementing the timer_ids_curr_
00167 // value, the first ID assigned will be 1 (just as in the previous design).
00168 // When it's time to wrap, the next ID given out will be 0.
00169 template <class TYPE, class FUNCTOR, class ACE_LOCK>
00170 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::ACE_Timer_Heap_T (FUNCTOR *upcall_functor,
00171                                                              ACE_Free_List<ACE_Timer_Node_T <TYPE> > *freelist)
00172   : ACE_Timer_Queue_T<TYPE,FUNCTOR,ACE_LOCK> (upcall_functor, freelist),
00173     max_size_ (ACE_DEFAULT_TIMERS),
00174     cur_size_ (0),
00175     cur_limbo_ (0),
00176     timer_ids_curr_ (0),
00177     timer_ids_min_free_ (0),
00178     preallocated_nodes_ (0),
00179     preallocated_nodes_freelist_ (0)
00180 {
00181   ACE_TRACE ("ACE_Timer_Heap_T::ACE_Timer_Heap_T");
00182 
00183   // Possibly reduce size to fit in a long.
00184 #if !defined(ACE_LACKS_NUMERIC_LIMITS)
00185   if (this->max_size_ > static_cast<size_t> (std::numeric_limits<long>::max ()))
00186     this->max_size_ = static_cast<size_t> (std::numeric_limits<long>::max ());
00187 #else
00188   if (this->max_size_ > LONG_MAX)
00189     this->max_size_ = LONG_MAX;
00190 #endif /* ACE_LACKS_NUMERIC_LIMITS */
00191 
00192   // Create the heap array.
00193     ACE_NEW (this->heap_,
00194              ACE_Timer_Node_T<TYPE> *[this->max_size_]);
00195 
00196   // Create the parallel array.
00197   ACE_NEW (this->timer_ids_,
00198            ssize_t[this->max_size_]);
00199 
00200   // Initialize the "freelist," which uses negative values to
00201   // distinguish freelist elements from "pointers" into the <heap_>
00202   // array.
00203   for (size_t i = 0; i < this->max_size_; i++)
00204     this->timer_ids_[i] = -1;
00205 
00206   ACE_NEW (iterator_,
00207            HEAP_ITERATOR (*this));
00208 }
00209 
00210 template <class TYPE, class FUNCTOR, class ACE_LOCK>
00211 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::~ACE_Timer_Heap_T (void)
00212 {
00213   ACE_TRACE ("ACE_Timer_Heap_T::~ACE_Timer_Heap_T");
00214 
00215   delete iterator_;
00216 
00217   size_t current_size =
00218     this->cur_size_;
00219 
00220   // Clean up all the nodes still in the queue
00221   for (size_t i = 0; i < current_size; i++)
00222     {
00223       // Grab the event_handler and act, then delete the node before calling
00224       // back to the handler. Prevents a handler from trying to cancel_timer()
00225       // inside handle_close(), ripping the current timer node out from
00226       // under us.
00227       TYPE eh = this->heap_[i]->get_type ();
00228       const void *act = this->heap_[i]->get_act ();
00229       this->free_node (this->heap_[i]);
00230       this->upcall_functor ().deletion (*this, eh, act);
00231     }
00232 
00233   delete [] this->heap_;
00234   delete [] this->timer_ids_;
00235 
00236   // clean up any preallocated timer nodes
00237   if (preallocated_nodes_ != 0)
00238     {
00239       ACE_Unbounded_Set_Iterator<ACE_Timer_Node_T<TYPE> *>
00240         set_iterator (this->preallocated_node_set_);
00241 
00242       for (ACE_Timer_Node_T<TYPE> **entry = 0;
00243            set_iterator.next (entry) !=0;
00244            set_iterator.advance ())
00245         delete [] *entry;
00246     }
00247 }
00248 
00249 template <class TYPE, class FUNCTOR, class ACE_LOCK> long
00250 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::pop_freelist (void)
00251 {
00252   ACE_TRACE ("ACE_Timer_Heap_T::pop_freelist");
00253 
00254   // Scan for a free timer ID. Note that since this function is called
00255   // _after_ the check for a full timer heap, we are guaranteed to find
00256   // a free ID, even if we need to wrap around and start reusing freed IDs.
00257   // On entry, the curr_ index is at the previous ID given out; start
00258   // up where we left off last time.
00259   // NOTE - a timer_ids_ slot with -2 is out of the heap, but not freed.
00260   // It must be either freed (free_node) or rescheduled (reschedule).
00261   ++this->timer_ids_curr_;
00262   while (this->timer_ids_curr_ < this->max_size_ &&
00263          (this->timer_ids_[this->timer_ids_curr_] >= 0 ||
00264           this->timer_ids_[this->timer_ids_curr_] == -2  ))
00265     ++this->timer_ids_curr_;
00266   if (this->timer_ids_curr_ == this->max_size_)
00267     {
00268       ACE_ASSERT (this->timer_ids_min_free_ < this->max_size_);
00269       this->timer_ids_curr_ = this->timer_ids_min_free_;
00270       // We restarted the free search at min. Since min won't be
00271       // free anymore, and curr_ will just keep marching up the list
00272       // on each successive need for an ID, reset min_free_ to the
00273       // size of the list until an ID is freed that curr_ has already
00274       // gone past (see push_freelist).
00275       this->timer_ids_min_free_ = this->max_size_;
00276     }
00277 
00278   return static_cast<long> (this->timer_ids_curr_);
00279 }
00280 
00281 template <class TYPE, class FUNCTOR, class ACE_LOCK> void
00282 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::push_freelist (long old_id)
00283 {
00284   ACE_TRACE ("ACE_Timer_Heap_T::push_freelist");
00285 
00286   // Since this ID has already been checked by one of the public
00287   // functions, it's safe to cast it here.
00288   size_t oldid = size_t (old_id);
00289 
00290   // The freelist values in the <timer_ids_> are negative, so set the
00291   // freed entry back to 'free'. If this is the new lowest value free
00292   // timer ID that curr_ won't see on it's normal march through the list,
00293   // remember it.
00294   ACE_ASSERT (this->timer_ids_[oldid] >= 0 || this->timer_ids_[oldid] == -2);
00295   if (this->timer_ids_[oldid] == -2)
00296     --this->cur_limbo_;
00297   else
00298     --this->cur_size_;
00299   this->timer_ids_[oldid] = -1;
00300   if (oldid < this->timer_ids_min_free_ && oldid <= this->timer_ids_curr_)
00301     this->timer_ids_min_free_ = oldid;
00302   return;
00303 }
00304 
00305 template <class TYPE, class FUNCTOR, class ACE_LOCK> long
00306 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::timer_id (void)
00307 {
00308   ACE_TRACE ("ACE_Timer_Heap_T::timer_id");
00309 
00310   // Return the next item off the freelist and use it as the timer id.
00311   return this->pop_freelist ();
00312 }
00313 
00314 // Checks if queue is empty.
00315 
00316 template <class TYPE, class FUNCTOR, class ACE_LOCK> int
00317 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::is_empty (void) const
00318 {
00319   ACE_TRACE ("ACE_Timer_Heap_T::is_empty");
00320   return this->cur_size_ == 0;
00321 }
00322 
00323 template <class TYPE, class FUNCTOR, class ACE_LOCK> ACE_Timer_Queue_Iterator_T<TYPE, FUNCTOR, ACE_LOCK> &
00324 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::iter (void)
00325 {
00326   this->iterator_->first ();
00327   return *this->iterator_;
00328 }
00329 
00330 // Returns earliest time in a non-empty queue.
00331 
00332 template <class TYPE, class FUNCTOR, class ACE_LOCK> const ACE_Time_Value &
00333 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::earliest_time (void) const
00334 {
00335   ACE_TRACE ("ACE_Timer_Heap_T::earliest_time");
00336   return this->heap_[0]->get_timer_value ();
00337 }
00338 
00339 template <class TYPE, class FUNCTOR, class ACE_LOCK> void
00340 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::dump (void) const
00341 {
00342 #if defined (ACE_HAS_DUMP)
00343   ACE_TRACE ("ACE_Timer_Heap_T::dump");
00344   ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
00345 
00346   ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nmax_size_ = %d"), this->max_size_));
00347   ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\ncur_size_ = %d"), this->cur_size_));
00348   ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\ncur_limbo_= %d"), this->cur_limbo_));
00349   ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nids_curr_ = %d"),
00350               this->timer_ids_curr_));
00351   ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nmin_free_ = %d"),
00352               this->timer_ids_min_free_));
00353 
00354   ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nheap_ = \n")));
00355 
00356   for (size_t i = 0; i < this->cur_size_; i++)
00357     {
00358       ACE_DEBUG ((LM_DEBUG,
00359                   ACE_TEXT ("%d\n"),
00360                   i));
00361       this->heap_[i]->dump ();
00362     }
00363 
00364   ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\ntimer_ids_ = \n")));
00365 
00366   for (size_t j = 0; j < this->max_size_; j++)
00367     ACE_DEBUG ((LM_DEBUG,
00368                 ACE_TEXT ("%d\t%d\n"),
00369                 j,
00370                 this->timer_ids_[j]));
00371 
00372   ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
00373 #endif /* ACE_HAS_DUMP */
00374 }
00375 
00376 template <class TYPE, class FUNCTOR, class ACE_LOCK> void
00377 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::copy (size_t slot,
00378                                                  ACE_Timer_Node_T<TYPE> *moved_node)
00379 {
00380   // Insert <moved_node> into its new location in the heap.
00381   this->heap_[slot] = moved_node;
00382 
00383   ACE_ASSERT (moved_node->get_timer_id () >= 0
00384               && moved_node->get_timer_id () < (int) this->max_size_);
00385 
00386   // Update the corresponding slot in the parallel <timer_ids_> array.
00387   this->timer_ids_[moved_node->get_timer_id ()] = static_cast<ssize_t> (slot);
00388 }
00389 
00390 // Remove the slot'th timer node from the heap, but do not reclaim its
00391 // timer ID or change the size of this timer heap object. The caller of
00392 // this function must call either free_node (to reclaim the timer ID
00393 // and the timer node memory, as well as decrement the size of the queue)
00394 // or reschedule (to reinsert the node in the heap at a new time).
00395 template <class TYPE, class FUNCTOR, class ACE_LOCK> ACE_Timer_Node_T<TYPE> *
00396 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::remove (size_t slot)
00397 {
00398   ACE_Timer_Node_T<TYPE> *removed_node =
00399     this->heap_[slot];
00400 
00401   // NOTE - the cur_size_ is being decremented since the queue has one
00402   // less active timer in it. However, this ACE_Timer_Node is not being
00403   // freed, and there is still a place for it in timer_ids_ (the timer ID
00404   // is not being relinquished). The node can still be rescheduled, or
00405   // it can be freed via free_node.
00406   --this->cur_size_;
00407 
00408   // Only try to reheapify if we're not deleting the last entry.
00409 
00410   if (slot < this->cur_size_)
00411     {
00412       ACE_Timer_Node_T<TYPE> *moved_node =
00413         this->heap_[this->cur_size_];
00414 
00415       // Move the end node to the location being removed and update
00416       // the corresponding slot in the parallel <timer_ids> array.
00417       this->copy (slot, moved_node);
00418 
00419       // If the <moved_node->time_value_> is great than or equal its
00420       // parent it needs be moved down the heap.
00421       size_t parent = ACE_HEAP_PARENT (slot);
00422 
00423       if (moved_node->get_timer_value ()
00424           >= this->heap_[parent]->get_timer_value ())
00425         this->reheap_down (moved_node,
00426                            slot,
00427                            ACE_HEAP_LCHILD (slot));
00428       else
00429         this->reheap_up (moved_node,
00430                          slot,
00431                          parent);
00432     }
00433 
00434   this->timer_ids_[removed_node->get_timer_id ()] = -2;
00435   ++this->cur_limbo_;
00436   return removed_node;
00437 }
00438 
00439 template <class TYPE, class FUNCTOR, class ACE_LOCK> void
00440 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::reheap_down (ACE_Timer_Node_T<TYPE> *moved_node,
00441                                                     size_t slot,
00442                                                     size_t child)
00443 {
00444   // Restore the heap property after a deletion.
00445 
00446   while (child < this->cur_size_)
00447     {
00448       // Choose the smaller of the two children.
00449       if (child + 1 < this->cur_size_
00450           && this->heap_[child + 1]->get_timer_value ()
00451           < this->heap_[child]->get_timer_value ())
00452         child++;
00453 
00454       // Perform a <copy> if the child has a larger timeout value than
00455       // the <moved_node>.
00456       if (this->heap_[child]->get_timer_value ()
00457           < moved_node->get_timer_value ())
00458         {
00459           this->copy (slot,
00460                       this->heap_[child]);
00461           slot = child;
00462           child = ACE_HEAP_LCHILD (child);
00463         }
00464       else
00465         // We've found our location in the heap.
00466         break;
00467     }
00468 
00469   this->copy (slot, moved_node);
00470 }
00471 
00472 template <class TYPE, class FUNCTOR, class ACE_LOCK> void
00473 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::reheap_up (ACE_Timer_Node_T<TYPE> *moved_node,
00474                                                       size_t slot,
00475                                                       size_t parent)
00476 {
00477   // Restore the heap property after an insertion.
00478 
00479   while (slot > 0)
00480     {
00481       // If the parent node is greater than the <moved_node> we need
00482       // to copy it down.
00483       if (moved_node->get_timer_value ()
00484           < this->heap_[parent]->get_timer_value ())
00485         {
00486           this->copy (slot, this->heap_[parent]);
00487           slot = parent;
00488           parent = ACE_HEAP_PARENT (slot);
00489         }
00490       else
00491         break;
00492     }
00493 
00494   // Insert the new node into its proper resting place in the heap and
00495   // update the corresponding slot in the parallel <timer_ids> array.
00496   this->copy (slot,
00497               moved_node);
00498 }
00499 
00500 template <class TYPE, class FUNCTOR, class ACE_LOCK> void
00501 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::insert (ACE_Timer_Node_T<TYPE> *new_node)
00502 {
00503   if (this->cur_size_ + this->cur_limbo_ + 2 >= this->max_size_)
00504     this->grow_heap ();
00505 
00506   this->reheap_up (new_node,
00507                    this->cur_size_,
00508                    ACE_HEAP_PARENT (this->cur_size_));
00509   this->cur_size_++;
00510 }
00511 
00512 template <class TYPE, class FUNCTOR, class ACE_LOCK> void
00513 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::grow_heap (void)
00514 {
00515   // All the containers will double in size from max_size_.
00516   size_t new_size = this->max_size_ * 2;
00517 
00518 #if 0
00519   // Yikes - there's no way to flag a failure of going out of range of
00520   // a 'long' - this is a problem that should be addressed at some point.
00521 #if !defined(ACE_LACKS_NUMERIC_LIMITS)
00522   if (new_size > std::numeric_limits<long>::max ())
00523     new_size = std::numeric_limits<long>::max ();
00524 #else
00525   if (new_size > LONG_MAX)
00526     new_size = LONG_MAX;
00527 #endif /* ACE_LACKS_NUMERIC_LIMITS */
00528 
00529   if (new_size <= this->max_size_)   // We are already at the limit
00530     {
00531       errno = ENOMEM;
00532       return -1;
00533     }
00534 #endif /* 0 */
00535 
00536    // First grow the heap itself.
00537 
00538   ACE_Timer_Node_T<TYPE> **new_heap = 0;
00539 
00540   ACE_NEW (new_heap,
00541            ACE_Timer_Node_T<TYPE> *[new_size]);
00542 
00543   ACE_OS::memcpy (new_heap,
00544                   this->heap_,
00545                   this->max_size_ * sizeof *new_heap);
00546   delete [] this->heap_;
00547   this->heap_ = new_heap;
00548 
00549   // Grow the array of timer ids.
00550 
00551   ssize_t *new_timer_ids = 0;
00552 
00553   ACE_NEW (new_timer_ids,
00554            ssize_t[new_size]);
00555 
00556   ACE_OS::memcpy (new_timer_ids,
00557                   this->timer_ids_,
00558                   this->max_size_ * sizeof (ssize_t));
00559 
00560   delete [] timer_ids_;
00561   this->timer_ids_ = new_timer_ids;
00562 
00563   // And add the new elements to the end of the "freelist".
00564   for (size_t i = this->max_size_; i < new_size; i++)
00565     this->timer_ids_[i] = -(static_cast<ssize_t> (i) + 1);
00566 
00567    // Grow the preallocation array (if using preallocation)
00568   if (this->preallocated_nodes_ != 0)
00569     {
00570       // Create a new array with max_size elements to link in to
00571       // existing list.
00572       ACE_NEW (this->preallocated_nodes_,
00573                ACE_Timer_Node_T<TYPE>[this->max_size_]);
00574 
00575       // Add it to the set for later deletion
00576       this->preallocated_node_set_.insert (this->preallocated_nodes_);
00577 
00578       // Link new nodes together (as for original list).
00579       for (size_t k = 1; k < this->max_size_; k++)
00580         this->preallocated_nodes_[k - 1].set_next (&this->preallocated_nodes_[k]);
00581 
00582       // NULL-terminate the new list.
00583       this->preallocated_nodes_[this->max_size_ - 1].set_next (0);
00584 
00585       // Link new array to the end of the existling list.
00586       if (this->preallocated_nodes_freelist_ == 0)
00587         this->preallocated_nodes_freelist_ =
00588           &preallocated_nodes_[0];
00589       else
00590         {
00591           ACE_Timer_Node_T<TYPE> *previous =
00592             this->preallocated_nodes_freelist_;
00593 
00594           for (ACE_Timer_Node_T<TYPE> *current = this->preallocated_nodes_freelist_->get_next ();
00595                current != 0;
00596                current = current->get_next ())
00597             previous = current;
00598 
00599           previous->set_next (&this->preallocated_nodes_[0]);
00600         }
00601     }
00602 
00603   this->max_size_ = new_size;
00604   // Force rescan of list from beginning for a free slot (I think...)
00605   // This fixed Bugzilla #2447.
00606   this->timer_ids_min_free_ = this->max_size_;
00607 }
00608 
00609 // Reschedule a periodic timer.  This function must be called with the
00610 // mutex lock held.
00611 
00612 template <class TYPE, class FUNCTOR, class ACE_LOCK> void
00613 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::reschedule (ACE_Timer_Node_T<TYPE> *expired)
00614 {
00615   ACE_TRACE ("ACE_Timer_Heap_T::reschedule");
00616 
00617   // If we are rescheduling, then the most recent call was to
00618   // remove_first (). That called remove () to remove the node from the
00619   // heap, but did not free the timer ID. The ACE_Timer_Node still has
00620   // its assigned ID - just needs to be inserted at the new proper
00621   // place, and the heap restored properly.
00622   if (this->timer_ids_[expired->get_timer_id ()] == -2)
00623     --this->cur_limbo_;
00624   this->insert (expired);
00625 }
00626 
00627 template <class TYPE, class FUNCTOR, class ACE_LOCK> ACE_Timer_Node_T<TYPE> *
00628 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::alloc_node (void)
00629 {
00630   ACE_Timer_Node_T<TYPE> *temp = 0;
00631 
00632   // Only allocate a node if we are *not* using the preallocated heap.
00633   if (this->preallocated_nodes_ == 0)
00634     ACE_NEW_RETURN (temp,
00635                     ACE_Timer_Node_T<TYPE>,
00636                     0);
00637   else
00638     {
00639       // check to see if the heap needs to grow
00640       if (this->preallocated_nodes_freelist_ == 0)
00641         this->grow_heap ();
00642 
00643       temp = this->preallocated_nodes_freelist_;
00644 
00645       // Remove the first element from the freelist.
00646       this->preallocated_nodes_freelist_ =
00647         this->preallocated_nodes_freelist_->get_next ();
00648     }
00649   return temp;
00650 }
00651 
00652 template <class TYPE, class FUNCTOR, class ACE_LOCK> void
00653 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::free_node (ACE_Timer_Node_T<TYPE> *node)
00654 {
00655   // Return this timer id to the freelist.
00656   this->push_freelist (node->get_timer_id ());
00657 
00658   // Only free up a node if we are *not* using the preallocated heap.
00659   if (this->preallocated_nodes_ == 0)
00660     delete node;
00661   else
00662     {
00663       node->set_next (this->preallocated_nodes_freelist_);
00664       this->preallocated_nodes_freelist_ = node;
00665     }
00666 }
00667 
00668 // Insert a new timer that expires at time future_time; if interval is
00669 // > 0, the handler will be reinvoked periodically.
00670 
00671 template <class TYPE, class FUNCTOR, class ACE_LOCK> long
00672 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::schedule_i (const TYPE &type,
00673                                                        const void *act,
00674                                                        const ACE_Time_Value &future_time,
00675                                                        const ACE_Time_Value &interval)
00676 {
00677   ACE_TRACE ("ACE_Timer_Heap_T::schedule_i");
00678 
00679   if ((this->cur_size_ + this->cur_limbo_) < this->max_size_)
00680     {
00681       // Obtain the next unique sequence number.
00682       long timer_id = this->timer_id ();
00683 
00684       // Obtain the memory to the new node.
00685       ACE_Timer_Node_T<TYPE> *temp = 0;
00686 
00687       ACE_ALLOCATOR_RETURN (temp,
00688                             this->alloc_node (),
00689                             -1);
00690       temp->set (type,
00691                  act,
00692                  future_time,
00693                  interval,
00694                  0,
00695                  timer_id);
00696 
00697       this->insert (temp);
00698       return timer_id;
00699     }
00700   else
00701     return -1;
00702 }
00703 
00704 // Locate and remove the single timer with a value of <timer_id> from
00705 // the timer queue.
00706 
00707 template <class TYPE, class FUNCTOR, class ACE_LOCK> int
00708 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::cancel (long timer_id,
00709                                                    const void **act,
00710                                                    int dont_call)
00711 {
00712   ACE_TRACE ("ACE_Timer_Heap_T::cancel");
00713   ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, -1));
00714 
00715   // Locate the ACE_Timer_Node that corresponds to the timer_id.
00716 
00717   // Check to see if the timer_id is out of range
00718   if (timer_id < 0
00719       || (size_t) timer_id > this->max_size_)
00720     return 0;
00721 
00722   ssize_t timer_node_slot = this->timer_ids_[timer_id];
00723 
00724   // Check to see if timer_id is still valid.
00725   if (timer_node_slot < 0)
00726     return 0;
00727 
00728   if (timer_id != this->heap_[timer_node_slot]->get_timer_id ())
00729     {
00730       ACE_ASSERT (timer_id == this->heap_[timer_node_slot]->get_timer_id ());
00731       return 0;
00732     }
00733   else
00734     {
00735       ACE_Timer_Node_T<TYPE> *temp =
00736         this->remove (timer_node_slot);
00737 
00738       // Call the close hooks.
00739       int cookie = 0;
00740 
00741       // cancel_type() called once per <type>.
00742       this->upcall_functor ().cancel_type (*this,
00743                                            temp->get_type (),
00744                                            dont_call,
00745                                            cookie);
00746 
00747       // cancel_timer() called once per <timer>.
00748       this->upcall_functor ().cancel_timer (*this,
00749                                             temp->get_type (),
00750                                             dont_call,
00751                                             cookie);
00752 
00753       if (act != 0)
00754         *act = temp->get_act ();
00755 
00756       this->free_node (temp);
00757       return 1;
00758     }
00759 }
00760 
00761 // Locate and update the inteval on the timer_id
00762 
00763 template <class TYPE, class FUNCTOR, class ACE_LOCK> int
00764 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::reset_interval (long timer_id,
00765                                                            const ACE_Time_Value &interval)
00766 {
00767   ACE_TRACE ("ACE_Timer_Heap_T::reset_interval");
00768   ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, -1));
00769 
00770   // Locate the ACE_Timer_Node that corresponds to the timer_id.
00771 
00772   // Check to see if the timer_id is out of range
00773   if (timer_id < 0
00774       || (size_t) timer_id > this->max_size_)
00775     return -1;
00776 
00777   ssize_t timer_node_slot = this->timer_ids_[timer_id];
00778 
00779   // Check to see if timer_id is still valid.
00780   if (timer_node_slot < 0)
00781     return -1;
00782 
00783   if (timer_id != this->heap_[timer_node_slot]->get_timer_id ())
00784     {
00785       ACE_ASSERT (timer_id == this->heap_[timer_node_slot]->get_timer_id ());
00786       return -1;
00787     }
00788   else
00789     {
00790       // Reset the timer interval
00791       this->heap_[timer_node_slot]->set_interval (interval);
00792       return 0;
00793     }
00794 }
00795 
00796 // Locate and remove all values of <type> from the timer queue.
00797 
00798 template <class TYPE, class FUNCTOR, class ACE_LOCK> int
00799 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::cancel (const TYPE &type,
00800                                                    int dont_call)
00801 {
00802   ACE_TRACE ("ACE_Timer_Heap_T::cancel");
00803   ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, -1));
00804 
00805   int number_of_cancellations = 0;
00806 
00807   // Try to locate the ACE_Timer_Node that matches the timer_id.
00808 
00809   for (size_t i = 0; i < this->cur_size_; )
00810     {
00811       if (this->heap_[i]->get_type () == type)
00812         {
00813           ACE_Timer_Node_T<TYPE> *temp = this->remove (i);
00814 
00815           number_of_cancellations++;
00816 
00817           this->free_node (temp);
00818 
00819           // We reset to zero so that we don't miss checking any nodes
00820           // if a reheapify occurs when a node is removed.  There
00821           // may be a better fix than this, however.
00822           i = 0;
00823         }
00824       else
00825         i++;
00826     }
00827 
00828   // Call the close hooks.
00829   int cookie = 0;
00830 
00831   // cancel_type() called once per <type>.
00832   this->upcall_functor ().cancel_type (*this,
00833                                        type,
00834                                        dont_call,
00835                                        cookie);
00836 
00837   for (int j = 0;
00838        j < number_of_cancellations;
00839        ++j)
00840     {
00841       // cancel_timer() called once per <timer>.
00842       this->upcall_functor ().cancel_timer (*this,
00843                                             type,
00844                                             dont_call,
00845                                             cookie);
00846     }
00847 
00848   return number_of_cancellations;
00849 }
00850 
00851 // Returns the earliest node or returns 0 if the heap is empty.
00852 
00853 template <class TYPE, class FUNCTOR, class ACE_LOCK> ACE_Timer_Node_T <TYPE> *
00854 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::remove_first (void)
00855 {
00856   ACE_TRACE ("ACE_Timer_Heap_T::remove_first");
00857 
00858   if (this->cur_size_ == 0)
00859     return 0;
00860 
00861   return this->remove (0);
00862 }
00863 
00864 template <class TYPE, class FUNCTOR, class ACE_LOCK> ACE_Timer_Node_T <TYPE> *
00865 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::get_first (void)
00866 {
00867   ACE_TRACE ("ACE_Timer_Heap_T::get_first");
00868 
00869   return this->cur_size_ == 0 ? 0 : this->heap_[0];
00870 }
00871 
00872 ACE_END_VERSIONED_NAMESPACE_DECL
00873 
00874 #endif /* ACE_TIMER_HEAP_T_CPP */

Generated on Sun Jan 27 12:05:41 2008 for ACE by doxygen 1.3.6