Timer_Heap_T.cpp

Go to the documentation of this file.
00001 // Timer_Heap_T.cpp,v 4.79 2006/03/16 22:32:09 shuston Exp
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                                                              int preallocate,
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 (preallocate)
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 #if defined (__IBMCPP__) && (__IBMCPP__ >= 400) && defined (_WINDOWS)
00194     ACE_NEW (this->heap_,
00195              ACE_Timer_Node_T<TYPE> *[ACE_DEFAULT_TIMERS]);
00196 #else
00197     ACE_NEW (this->heap_,
00198              ACE_Timer_Node_T<TYPE> *[this->max_size_]);
00199 #endif /* defined (__IBMCPP__) && (__IBMCPP__ >= 400) && defined (_WINDOWS) */
00200 
00201   // Create the parallel array.
00202   ACE_NEW (this->timer_ids_,
00203            ssize_t[this->max_size_]);
00204 
00205   // Initialize the "freelist," which uses negative values to
00206   // distinguish freelist elements from "pointers" into the <heap_>
00207   // array.
00208   for (size_t i = 0; i < this->max_size_; i++)
00209     this->timer_ids_[i] = -1;
00210 
00211   ACE_NEW (iterator_,
00212            HEAP_ITERATOR (*this));
00213 }
00214 
00215 template <class TYPE, class FUNCTOR, class ACE_LOCK>
00216 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::~ACE_Timer_Heap_T (void)
00217 {
00218   ACE_TRACE ("ACE_Timer_Heap_T::~ACE_Timer_Heap_T");
00219 
00220   delete iterator_;
00221 
00222   size_t current_size =
00223     this->cur_size_;
00224 
00225   // Clean up all the nodes still in the queue
00226   for (size_t i = 0; i < current_size; i++)
00227     {
00228       // Grab the event_handler and act, then delete the node before calling
00229       // back to the handler. Prevents a handler from trying to cancel_timer()
00230       // inside handle_close(), ripping the current timer node out from
00231       // under us.
00232       TYPE eh = this->heap_[i]->get_type ();
00233       const void *act = this->heap_[i]->get_act ();
00234       this->free_node (this->heap_[i]);
00235       this->upcall_functor ().deletion (*this, eh, act);
00236     }
00237 
00238   delete [] this->heap_;
00239   delete [] this->timer_ids_;
00240 
00241   // clean up any preallocated timer nodes
00242   if (preallocated_nodes_ != 0)
00243     {
00244       ACE_Unbounded_Set_Iterator<ACE_Timer_Node_T<TYPE> *>
00245         set_iterator (this->preallocated_node_set_);
00246 
00247       for (ACE_Timer_Node_T<TYPE> **entry = 0;
00248            set_iterator.next (entry) !=0;
00249            set_iterator.advance ())
00250         delete [] *entry;
00251     }
00252 }
00253 
00254 template <class TYPE, class FUNCTOR, class ACE_LOCK> long
00255 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::pop_freelist (void)
00256 {
00257   ACE_TRACE ("ACE_Timer_Heap_T::pop_freelist");
00258 
00259   // Scan for a free timer ID. Note that since this function is called
00260   // _after_ the check for a full timer heap, we are guaranteed to find
00261   // a free ID, even if we need to wrap around and start reusing freed IDs.
00262   // On entry, the curr_ index is at the previous ID given out; start
00263   // up where we left off last time.
00264   // NOTE - a timer_ids_ slot with -2 is out of the heap, but not freed.
00265   // It must be either freed (free_node) or rescheduled (reschedule).
00266   ++this->timer_ids_curr_;
00267   while (this->timer_ids_curr_ < this->max_size_ &&
00268          (this->timer_ids_[this->timer_ids_curr_] >= 0 ||
00269           this->timer_ids_[this->timer_ids_curr_] == -2  ))
00270     ++this->timer_ids_curr_;
00271   if (this->timer_ids_curr_ == this->max_size_)
00272     {
00273       ACE_ASSERT (this->timer_ids_min_free_ < this->max_size_);
00274       this->timer_ids_curr_ = this->timer_ids_min_free_;
00275       // We restarted the free search at min. Since min won't be
00276       // free anymore, and curr_ will just keep marching up the list
00277       // on each successive need for an ID, reset min_free_ to the
00278       // size of the list until an ID is freed that curr_ has already
00279       // gone past (see push_freelist).
00280       this->timer_ids_min_free_ = this->max_size_;
00281     }
00282 
00283   return static_cast<long> (this->timer_ids_curr_);
00284 }
00285 
00286 template <class TYPE, class FUNCTOR, class ACE_LOCK> void
00287 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::push_freelist (long old_id)
00288 {
00289   ACE_TRACE ("ACE_Timer_Heap_T::push_freelist");
00290 
00291   // Since this ID has already been checked by one of the public
00292   // functions, it's safe to cast it here.
00293   size_t oldid = size_t (old_id);
00294 
00295   // The freelist values in the <timer_ids_> are negative, so set the
00296   // freed entry back to 'free'. If this is the new lowest value free
00297   // timer ID that curr_ won't see on it's normal march through the list,
00298   // remember it.
00299   ACE_ASSERT (this->timer_ids_[oldid] >= 0 || this->timer_ids_[oldid] == -2);
00300   if (this->timer_ids_[oldid] == -2)
00301     --this->cur_limbo_;
00302   else
00303     --this->cur_size_;
00304   this->timer_ids_[oldid] = -1;
00305   if (oldid < this->timer_ids_min_free_ && oldid <= this->timer_ids_curr_)
00306     this->timer_ids_min_free_ = oldid;
00307   return;
00308 }
00309 
00310 template <class TYPE, class FUNCTOR, class ACE_LOCK> long
00311 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::timer_id (void)
00312 {
00313   ACE_TRACE ("ACE_Timer_Heap_T::timer_id");
00314 
00315   // Return the next item off the freelist and use it as the timer id.
00316   return this->pop_freelist ();
00317 }
00318 
00319 // Checks if queue is empty.
00320 
00321 template <class TYPE, class FUNCTOR, class ACE_LOCK> int
00322 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::is_empty (void) const
00323 {
00324   ACE_TRACE ("ACE_Timer_Heap_T::is_empty");
00325   return this->cur_size_ == 0;
00326 }
00327 
00328 template <class TYPE, class FUNCTOR, class ACE_LOCK> ACE_Timer_Queue_Iterator_T<TYPE, FUNCTOR, ACE_LOCK> &
00329 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::iter (void)
00330 {
00331   this->iterator_->first ();
00332   return *this->iterator_;
00333 }
00334 
00335 // Returns earliest time in a non-empty queue.
00336 
00337 template <class TYPE, class FUNCTOR, class ACE_LOCK> const ACE_Time_Value &
00338 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::earliest_time (void) const
00339 {
00340   ACE_TRACE ("ACE_Timer_Heap_T::earliest_time");
00341   return this->heap_[0]->get_timer_value ();
00342 }
00343 
00344 template <class TYPE, class FUNCTOR, class ACE_LOCK> void
00345 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::dump (void) const
00346 {
00347 #if defined (ACE_HAS_DUMP)
00348   ACE_TRACE ("ACE_Timer_Heap_T::dump");
00349   ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
00350 
00351   ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nmax_size_ = %d"), this->max_size_));
00352   ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\ncur_size_ = %d"), this->cur_size_));
00353   ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\ncur_limbo_= %d"), this->cur_limbo_));
00354   ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nids_curr_ = %d"),
00355               this->timer_ids_curr_));
00356   ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nmin_free_ = %d"),
00357               this->timer_ids_min_free_));
00358 
00359   ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nheap_ = \n")));
00360 
00361   for (size_t i = 0; i < this->cur_size_; i++)
00362     {
00363       ACE_DEBUG ((LM_DEBUG,
00364                   ACE_LIB_TEXT ("%d\n"),
00365                   i));
00366       this->heap_[i]->dump ();
00367     }
00368 
00369   ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\ntimer_ids_ = \n")));
00370 
00371   for (size_t j = 0; j < this->max_size_; j++)
00372     ACE_DEBUG ((LM_DEBUG,
00373                 ACE_LIB_TEXT ("%d\t%d\n"),
00374                 j,
00375                 this->timer_ids_[j]));
00376 
00377   ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
00378 #endif /* ACE_HAS_DUMP */
00379 }
00380 
00381 template <class TYPE, class FUNCTOR, class ACE_LOCK> void
00382 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::copy (size_t slot,
00383                                                  ACE_Timer_Node_T<TYPE> *moved_node)
00384 {
00385   // Insert <moved_node> into its new location in the heap.
00386   this->heap_[slot] = moved_node;
00387 
00388   ACE_ASSERT (moved_node->get_timer_id () >= 0
00389               && moved_node->get_timer_id () < (int) this->max_size_);
00390 
00391   // Update the corresponding slot in the parallel <timer_ids_> array.
00392   this->timer_ids_[moved_node->get_timer_id ()] = slot;
00393 }
00394 
00395 // Remove the slot'th timer node from the heap, but do not reclaim its
00396 // timer ID or change the size of this timer heap object. The caller of
00397 // this function must call either free_node (to reclaim the timer ID
00398 // and the timer node memory, as well as decrement the size of the queue)
00399 // or reschedule (to reinsert the node in the heap at a new time).
00400 template <class TYPE, class FUNCTOR, class ACE_LOCK> ACE_Timer_Node_T<TYPE> *
00401 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::remove (size_t slot)
00402 {
00403   ACE_Timer_Node_T<TYPE> *removed_node =
00404     this->heap_[slot];
00405 
00406   // NOTE - the cur_size_ is being decremented since the queue has one
00407   // less active timer in it. However, this ACE_Timer_Node is not being
00408   // freed, and there is still a place for it in timer_ids_ (the timer ID
00409   // is not being relinquished). The node can still be rescheduled, or
00410   // it can be freed via free_node.
00411   --this->cur_size_;
00412 
00413   // Only try to reheapify if we're not deleting the last entry.
00414 
00415   if (slot < this->cur_size_)
00416     {
00417       ACE_Timer_Node_T<TYPE> *moved_node =
00418         this->heap_[this->cur_size_];
00419 
00420       // Move the end node to the location being removed and update
00421       // the corresponding slot in the parallel <timer_ids> array.
00422       this->copy (slot, moved_node);
00423 
00424       // If the <moved_node->time_value_> is great than or equal its
00425       // parent it needs be moved down the heap.
00426       size_t parent = ACE_HEAP_PARENT (slot);
00427 
00428       if (moved_node->get_timer_value ()
00429           >= this->heap_[parent]->get_timer_value ())
00430         this->reheap_down (moved_node,
00431                            slot,
00432                            ACE_HEAP_LCHILD (slot));
00433       else
00434         this->reheap_up (moved_node,
00435                          slot,
00436                          parent);
00437     }
00438 
00439   this->timer_ids_[removed_node->get_timer_id ()] = -2;
00440   ++this->cur_limbo_;
00441   return removed_node;
00442 }
00443 
00444 template <class TYPE, class FUNCTOR, class ACE_LOCK> void
00445 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::reheap_down (ACE_Timer_Node_T<TYPE> *moved_node,
00446                                                     size_t slot,
00447                                                     size_t child)
00448 {
00449   // Restore the heap property after a deletion.
00450 
00451   while (child < this->cur_size_)
00452     {
00453       // Choose the smaller of the two children.
00454       if (child + 1 < this->cur_size_
00455           && this->heap_[child + 1]->get_timer_value ()
00456           < this->heap_[child]->get_timer_value ())
00457         child++;
00458 
00459       // Perform a <copy> if the child has a larger timeout value than
00460       // the <moved_node>.
00461       if (this->heap_[child]->get_timer_value ()
00462           < moved_node->get_timer_value ())
00463         {
00464           this->copy (slot,
00465                       this->heap_[child]);
00466           slot = child;
00467           child = ACE_HEAP_LCHILD (child);
00468         }
00469       else
00470         // We've found our location in the heap.
00471         break;
00472     }
00473 
00474   this->copy (slot, moved_node);
00475 }
00476 
00477 template <class TYPE, class FUNCTOR, class ACE_LOCK> void
00478 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::reheap_up (ACE_Timer_Node_T<TYPE> *moved_node,
00479                                                       size_t slot,
00480                                                       size_t parent)
00481 {
00482   // Restore the heap property after an insertion.
00483 
00484   while (slot > 0)
00485     {
00486       // If the parent node is greater than the <moved_node> we need
00487       // to copy it down.
00488       if (moved_node->get_timer_value ()
00489           < this->heap_[parent]->get_timer_value ())
00490         {
00491           this->copy (slot, this->heap_[parent]);
00492           slot = parent;
00493           parent = ACE_HEAP_PARENT (slot);
00494         }
00495       else
00496         break;
00497     }
00498 
00499   // Insert the new node into its proper resting place in the heap and
00500   // update the corresponding slot in the parallel <timer_ids> array.
00501   this->copy (slot,
00502               moved_node);
00503 }
00504 
00505 template <class TYPE, class FUNCTOR, class ACE_LOCK> void
00506 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::insert (ACE_Timer_Node_T<TYPE> *new_node)
00507 {
00508   if (this->cur_size_ + this->cur_limbo_ + 2 >= this->max_size_)
00509     this->grow_heap ();
00510 
00511   this->reheap_up (new_node,
00512                    this->cur_size_,
00513                    ACE_HEAP_PARENT (this->cur_size_));
00514   this->cur_size_++;
00515 }
00516 
00517 template <class TYPE, class FUNCTOR, class ACE_LOCK> void
00518 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::grow_heap (void)
00519 {
00520   // All the containers will double in size from max_size_.
00521   size_t new_size = this->max_size_ * 2;
00522 
00523 #if 0
00524   // Yikes - there's no way to flag a failure of going out of range of
00525   // a 'long' - this is a problem that should be addressed at some point.
00526 #if !defined(ACE_LACKS_NUMERIC_LIMITS)
00527   if (new_size > std::numeric_limits<long>::max ())
00528     new_size = std::numeric_limits<long>::max ();
00529 #else
00530   if (new_size > LONG_MAX)
00531     new_size = LONG_MAX;
00532 #endif /* ACE_LACKS_NUMERIC_LIMITS */
00533 
00534   if (new_size <= this->max_size_)   // We are already at the limit
00535     {
00536       errno = ENOMEM;
00537       return -1;
00538     }
00539 #endif /* 0 */
00540 
00541    // First grow the heap itself.
00542 
00543   ACE_Timer_Node_T<TYPE> **new_heap = 0;
00544 
00545 #if defined (__IBMCPP__) && (__IBMCPP__ >= 400) && defined (_WINDOWS)
00546   ACE_NEW (new_heap,
00547            ACE_Timer_Node_T<TYPE> *[1024]);
00548 #else
00549   ACE_NEW (new_heap,
00550            ACE_Timer_Node_T<TYPE> *[new_size]);
00551 #endif /* defined (__IBMCPP__) && (__IBMCPP__ >= 400) && defined (_WINDOWS) */
00552   ACE_OS::memcpy (new_heap,
00553                   this->heap_,
00554                   this->max_size_ * sizeof *new_heap);
00555   delete [] this->heap_;
00556   this->heap_ = new_heap;
00557 
00558   // Grow the array of timer ids.
00559 
00560   ssize_t *new_timer_ids = 0;
00561 
00562   ACE_NEW (new_timer_ids,
00563            ssize_t[new_size]);
00564 
00565   ACE_OS::memcpy (new_timer_ids,
00566                   this->timer_ids_,
00567                   this->max_size_ * sizeof (ssize_t));
00568 
00569   delete [] timer_ids_;
00570   this->timer_ids_ = new_timer_ids;
00571 
00572   // And add the new elements to the end of the "freelist".
00573   for (size_t i = this->max_size_; i < new_size; i++)
00574     this->timer_ids_[i] = -(static_cast<ssize_t> (i) + 1);
00575 
00576    // Grow the preallocation array (if using preallocation)
00577   if (this->preallocated_nodes_ != 0)
00578     {
00579       // Create a new array with max_size elements to link in to
00580       // existing list.
00581 #if defined (__IBMCPP__) && (__IBMCPP__ >= 400) && defined (_WINDOWS)
00582       ACE_NEW (this->preallocated_nodes_,
00583                ACE_Timer_Node_T<TYPE>[88]);
00584 #else
00585       ACE_NEW (this->preallocated_nodes_,
00586                ACE_Timer_Node_T<TYPE>[this->max_size_]);
00587 #endif /* defined (__IBMCPP__) && (__IBMCPP__ >= 400) && defined (_WINDOWS) */
00588 
00589       // Add it to the set for later deletion
00590       this->preallocated_node_set_.insert (this->preallocated_nodes_);
00591 
00592       // Link new nodes together (as for original list).
00593       for (size_t k = 1; k < this->max_size_; k++)
00594         this->preallocated_nodes_[k - 1].set_next (&this->preallocated_nodes_[k]);
00595 
00596       // NULL-terminate the new list.
00597       this->preallocated_nodes_[this->max_size_ - 1].set_next (0);
00598 
00599       // Link new array to the end of the existling list.
00600       if (this->preallocated_nodes_freelist_ == 0)
00601         this->preallocated_nodes_freelist_ =
00602           &preallocated_nodes_[0];
00603       else
00604         {
00605           ACE_Timer_Node_T<TYPE> *previous =
00606             this->preallocated_nodes_freelist_;
00607 
00608           for (ACE_Timer_Node_T<TYPE> *current = this->preallocated_nodes_freelist_->get_next ();
00609                current != 0;
00610                current = current->get_next ())
00611             previous = current;
00612 
00613           previous->set_next (&this->preallocated_nodes_[0]);
00614         }
00615     }
00616 
00617   this->max_size_ = new_size;
00618   // Force rescan of list from beginning for a free slot (I think...)
00619   // This fixed Bugzilla #2447.
00620   this->timer_ids_min_free_ = this->max_size_;
00621 }
00622 
00623 // Reschedule a periodic timer.  This function must be called with the
00624 // mutex lock held.
00625 
00626 template <class TYPE, class FUNCTOR, class ACE_LOCK> void
00627 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::reschedule (ACE_Timer_Node_T<TYPE> *expired)
00628 {
00629   ACE_TRACE ("ACE_Timer_Heap_T::reschedule");
00630 
00631   // If we are rescheduling, then the most recent call was to
00632   // remove_first (). That called remove () to remove the node from the
00633   // heap, but did not free the timer ID. The ACE_Timer_Node still has
00634   // its assigned ID - just needs to be inserted at the new proper
00635   // place, and the heap restored properly.
00636   if (this->timer_ids_[expired->get_timer_id ()] == -2)
00637     --this->cur_limbo_;
00638   this->insert (expired);
00639 }
00640 
00641 template <class TYPE, class FUNCTOR, class ACE_LOCK> ACE_Timer_Node_T<TYPE> *
00642 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::alloc_node (void)
00643 {
00644   ACE_Timer_Node_T<TYPE> *temp = 0;
00645 
00646   // Only allocate a node if we are *not* using the preallocated heap.
00647   if (this->preallocated_nodes_ == 0)
00648     ACE_NEW_RETURN (temp,
00649                     ACE_Timer_Node_T<TYPE>,
00650                     0);
00651   else
00652     {
00653       // check to see if the heap needs to grow
00654       if (this->preallocated_nodes_freelist_ == 0)
00655         this->grow_heap ();
00656 
00657       temp = this->preallocated_nodes_freelist_;
00658 
00659       // Remove the first element from the freelist.
00660       this->preallocated_nodes_freelist_ =
00661         this->preallocated_nodes_freelist_->get_next ();
00662     }
00663   return temp;
00664 }
00665 
00666 template <class TYPE, class FUNCTOR, class ACE_LOCK> void
00667 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::free_node (ACE_Timer_Node_T<TYPE> *node)
00668 {
00669   // Return this timer id to the freelist.
00670   this->push_freelist (node->get_timer_id ());
00671 
00672   // Only free up a node if we are *not* using the preallocated heap.
00673   if (this->preallocated_nodes_ == 0)
00674     delete node;
00675   else
00676     {
00677       node->set_next (this->preallocated_nodes_freelist_);
00678       this->preallocated_nodes_freelist_ = node;
00679     }
00680 }
00681 
00682 // Insert a new timer that expires at time future_time; if interval is
00683 // > 0, the handler will be reinvoked periodically.
00684 
00685 template <class TYPE, class FUNCTOR, class ACE_LOCK> long
00686 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::schedule_i (const TYPE &type,
00687                                                        const void *act,
00688                                                        const ACE_Time_Value &future_time,
00689                                                        const ACE_Time_Value &interval)
00690 {
00691   ACE_TRACE ("ACE_Timer_Heap_T::schedule_i");
00692 
00693   if ((this->cur_size_ + this->cur_limbo_) < this->max_size_)
00694     {
00695       // Obtain the next unique sequence number.
00696       long timer_id = this->timer_id ();
00697 
00698       // Obtain the memory to the new node.
00699       ACE_Timer_Node_T<TYPE> *temp = 0;
00700 
00701       ACE_ALLOCATOR_RETURN (temp,
00702                             this->alloc_node (),
00703                             -1);
00704       temp->set (type,
00705                  act,
00706                  future_time,
00707                  interval,
00708                  0,
00709                  timer_id);
00710 
00711       this->insert (temp);
00712       return timer_id;
00713     }
00714   else
00715     return -1;
00716 }
00717 
00718 // Locate and remove the single timer with a value of <timer_id> from
00719 // the timer queue.
00720 
00721 template <class TYPE, class FUNCTOR, class ACE_LOCK> int
00722 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::cancel (long timer_id,
00723                                                    const void **act,
00724                                                    int dont_call)
00725 {
00726   ACE_TRACE ("ACE_Timer_Heap_T::cancel");
00727   ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, -1));
00728 
00729   // Locate the ACE_Timer_Node that corresponds to the timer_id.
00730 
00731   // Check to see if the timer_id is out of range
00732   if (timer_id < 0
00733       || (size_t) timer_id > this->max_size_)
00734     return 0;
00735 
00736   ssize_t timer_node_slot = this->timer_ids_[timer_id];
00737 
00738   // Check to see if timer_id is still valid.
00739   if (timer_node_slot < 0)
00740     return 0;
00741 
00742   if (timer_id != this->heap_[timer_node_slot]->get_timer_id ())
00743     {
00744       ACE_ASSERT (timer_id == this->heap_[timer_node_slot]->get_timer_id ());
00745       return 0;
00746     }
00747   else
00748     {
00749       ACE_Timer_Node_T<TYPE> *temp =
00750         this->remove (timer_node_slot);
00751 
00752       // Call the close hooks.
00753       int cookie = 0;
00754 
00755       // cancel_type() called once per <type>.
00756       this->upcall_functor ().cancel_type (*this,
00757                                            temp->get_type (),
00758                                            dont_call,
00759                                            cookie);
00760 
00761       // cancel_timer() called once per <timer>.
00762       this->upcall_functor ().cancel_timer (*this,
00763                                             temp->get_type (),
00764                                             dont_call,
00765                                             cookie);
00766 
00767       if (act != 0)
00768         *act = temp->get_act ();
00769 
00770       this->free_node (temp);
00771       return 1;
00772     }
00773 }
00774 
00775 // Locate and update the inteval on the timer_id
00776 
00777 template <class TYPE, class FUNCTOR, class ACE_LOCK> int
00778 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::reset_interval (long timer_id,
00779                                                            const ACE_Time_Value &interval)
00780 {
00781   ACE_TRACE ("ACE_Timer_Heap_T::reset_interval");
00782   ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, -1));
00783 
00784   // Locate the ACE_Timer_Node that corresponds to the timer_id.
00785 
00786   // Check to see if the timer_id is out of range
00787   if (timer_id < 0
00788       || (size_t) timer_id > this->max_size_)
00789     return -1;
00790 
00791   ssize_t timer_node_slot = this->timer_ids_[timer_id];
00792 
00793   // Check to see if timer_id is still valid.
00794   if (timer_node_slot < 0)
00795     return -1;
00796 
00797   if (timer_id != this->heap_[timer_node_slot]->get_timer_id ())
00798     {
00799       ACE_ASSERT (timer_id == this->heap_[timer_node_slot]->get_timer_id ());
00800       return -1;
00801     }
00802   else
00803     {
00804       // Reset the timer interval
00805       this->heap_[timer_node_slot]->set_interval (interval);
00806       return 0;
00807     }
00808 }
00809 
00810 // Locate and remove all values of <type> from the timer queue.
00811 
00812 template <class TYPE, class FUNCTOR, class ACE_LOCK> int
00813 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::cancel (const TYPE &type,
00814                                                    int dont_call)
00815 {
00816   ACE_TRACE ("ACE_Timer_Heap_T::cancel");
00817   ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, -1));
00818 
00819   int number_of_cancellations = 0;
00820 
00821   // Try to locate the ACE_Timer_Node that matches the timer_id.
00822 
00823   for (size_t i = 0; i < this->cur_size_; )
00824     {
00825       if (this->heap_[i]->get_type () == type)
00826         {
00827           ACE_Timer_Node_T<TYPE> *temp = this->remove (i);
00828 
00829           number_of_cancellations++;
00830 
00831           this->free_node (temp);
00832 
00833           // We reset to zero so that we don't miss checking any nodes
00834           // if a reheapify occurs when a node is removed.  There
00835           // may be a better fix than this, however.
00836           i = 0;
00837         }
00838       else
00839         i++;
00840     }
00841 
00842   // Call the close hooks.
00843   int cookie = 0;
00844 
00845   // cancel_type() called once per <type>.
00846   this->upcall_functor ().cancel_type (*this,
00847                                        type,
00848                                        dont_call,
00849                                        cookie);
00850 
00851   for (int j = 0;
00852        j < number_of_cancellations;
00853        ++j)
00854     {
00855       // cancel_timer() called once per <timer>.
00856       this->upcall_functor ().cancel_timer (*this,
00857                                             type,
00858                                             dont_call,
00859                                             cookie);
00860     }
00861 
00862   return number_of_cancellations;
00863 }
00864 
00865 // Returns the earliest node or returns 0 if the heap is empty.
00866 
00867 template <class TYPE, class FUNCTOR, class ACE_LOCK> ACE_Timer_Node_T <TYPE> *
00868 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::remove_first (void)
00869 {
00870   ACE_TRACE ("ACE_Timer_Heap_T::remove_first");
00871 
00872   if (this->cur_size_ == 0)
00873     return 0;
00874 
00875   return this->remove (0);
00876 }
00877 
00878 template <class TYPE, class FUNCTOR, class ACE_LOCK> ACE_Timer_Node_T <TYPE> *
00879 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::get_first (void)
00880 {
00881   ACE_TRACE ("ACE_Timer_Heap_T::get_first");
00882 
00883   return this->cur_size_ == 0 ? 0 : this->heap_[0];
00884 }
00885 
00886 ACE_END_VERSIONED_NAMESPACE_DECL
00887 
00888 #endif /* ACE_TIMER_HEAP_T_CPP */

Generated on Thu Nov 9 09:42:07 2006 for ACE by doxygen 1.3.6