Changes to attempt to silence bcc64x
[ACE_TAO.git] / ACE / ace / Timer_Heap_T.cpp
blob3fa0897a4d8cd8453d57dfad07e43abaf0b4f806
1 #ifndef ACE_TIMER_HEAP_T_CPP
2 #define ACE_TIMER_HEAP_T_CPP
4 #include "ace/Timer_Heap_T.h"
5 #include "ace/Log_Category.h"
6 #include "ace/Guard_T.h"
7 #include "ace/OS_NS_errno.h"
8 #include "ace/OS_NS_string.h"
9 #include "ace/Numeric_Limits.h"
11 #if !defined (ACE_LACKS_PRAGMA_ONCE)
12 # pragma once
13 #endif /* ACE_LACKS_PRAGMA_ONCE */
16 ** The ACE_Timer_Heap::max_size_ and array loops, checks, etc. are all size_t.
17 ** The timer IDs are long, and since they are indices into the heap, we need
18 ** to be sure that the timer heap size can fit in a long. Hence, when size
19 ** is (re)set, limit it to the maximum long value. We use the C++ standard
20 ** limits if available.
23 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
25 ACE_ALLOC_HOOK_DEFINE_Tccct(ACE_Timer_Heap_Iterator_T)
26 ACE_ALLOC_HOOK_DEFINE_Tccct(ACE_Timer_Heap_T)
28 // Define some simple inlined functions to clarify the code.
29 inline size_t
30 ACE_HEAP_PARENT (size_t X)
32 return (X == 0 ? 0 : ((X - 1) / 2));
35 inline size_t
36 ACE_HEAP_LCHILD (size_t X)
38 return X + X + 1;
41 // Constructor that takes in an <ACE_Timer_Heap_T> to iterate over.
42 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
43 ACE_Timer_Heap_Iterator_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::ACE_Timer_Heap_Iterator_T (
44 Heap & heap)
45 : timer_heap_ (heap)
47 ACE_TRACE ("ACE_Timer_Heap_Iterator_T::ACE_Timer_Heap_Iterator");
48 this->first ();
51 // Positions the iterator at the first node in the heap array
52 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
53 void
54 ACE_Timer_Heap_Iterator_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::first ()
56 this->position_ = 0;
59 // Positions the iterator at the next node in the heap array
60 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
61 void
62 ACE_Timer_Heap_Iterator_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::next ()
64 if (this->position_ != this->timer_heap_.cur_size_)
65 ++this->position_;
68 // Returns true the <position_> is at the end of the heap array
69 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> bool
70 ACE_Timer_Heap_Iterator_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::isdone () const
72 return this->position_ == this->timer_heap_.cur_size_;
75 // Returns the node at the current position in the heap or 0 if at the end
76 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> ACE_Timer_Node_T<TYPE> *
77 ACE_Timer_Heap_Iterator_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::item ()
79 if (this->position_ != this->timer_heap_.cur_size_)
80 return this->timer_heap_.heap_[this->position_];
81 return 0;
84 // Constructor
85 // Note that timer_ids_curr_ and timer_ids_min_free_ both start at 0.
86 // Since timer IDs are assigned by first incrementing the timer_ids_curr_
87 // value, the first ID assigned will be 1 (just as in the previous design).
88 // When it's time to wrap, the next ID given out will be 0.
89 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
90 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::ACE_Timer_Heap_T (
91 size_t size,
92 bool preallocated,
93 FUNCTOR *upcall_functor,
94 ACE_Free_List<ACE_Timer_Node_T <TYPE> > *freelist,
95 TIME_POLICY const & time_policy)
96 : Base_Time_Policy (upcall_functor,
97 freelist,
98 time_policy),
99 max_size_ (size),
100 cur_size_ (0),
101 cur_limbo_ (0),
102 iterator_ (nullptr),
103 timer_ids_curr_ (0),
104 timer_ids_min_free_ (0),
105 preallocated_nodes_ (0),
106 preallocated_nodes_freelist_ (0)
108 ACE_TRACE ("ACE_Timer_Heap_T::ACE_Timer_Heap_T");
110 // Possibly reduce size to fit in a long.
111 if (size > static_cast<size_t> (ACE_Numeric_Limits<long>::max ()))
113 size = static_cast<size_t> (ACE_Numeric_Limits<long>::max ());
114 this->max_size_ = size;
117 // Create the heap array.
118 #if defined (ACE_HAS_ALLOC_HOOKS)
119 this->heap_ = reinterpret_cast<ACE_Timer_Node_T<TYPE> **>
120 (ACE_Allocator::instance ()->malloc (sizeof (ACE_Timer_Node_T<TYPE> *) * size));
121 #else
122 ACE_NEW (this->heap_,
123 ACE_Timer_Node_T<TYPE> *[size]);
124 #endif /* ACE_HAS_ALLOC_HOOKS */
126 // Create the parallel
127 ACE_NEW (this->timer_ids_,
128 ssize_t[size]);
130 // Initialize the "freelist," which uses negative values to
131 // distinguish freelist elements from "pointers" into the <heap_>
132 // array.
133 for (size_t i = 0; i < size; ++i)
134 this->timer_ids_[i] = -1;
136 if (preallocated)
138 ACE_NEW (this->preallocated_nodes_,
139 ACE_Timer_Node_T<TYPE>[size]);
141 // Add allocated array to set of such arrays for deletion on
142 // cleanup.
143 this->preallocated_node_set_.insert (this->preallocated_nodes_);
145 // Form the freelist by linking the next_ pointers together.
146 for (size_t j = 1; j < size; ++j)
147 this->preallocated_nodes_[j - 1].set_next (&this->preallocated_nodes_[j]);
149 // NULL-terminate the freelist.
150 this->preallocated_nodes_[size - 1].set_next (0);
152 // Assign the freelist pointer to the front of the list.
153 this->preallocated_nodes_freelist_ =
154 &this->preallocated_nodes_[0];
157 ACE_NEW (iterator_,
158 HEAP_ITERATOR (*this));
161 // Note that timer_ids_curr_ and timer_ids_min_free_ both start at 0.
162 // Since timer IDs are assigned by first incrementing the timer_ids_curr_
163 // value, the first ID assigned will be 1 (just as in the previous design).
164 // When it's time to wrap, the next ID given out will be 0.
165 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
166 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::ACE_Timer_Heap_T (
167 FUNCTOR *upcall_functor,
168 ACE_Free_List<ACE_Timer_Node_T <TYPE> > *freelist,
169 TIME_POLICY const & time_policy)
170 : Base_Time_Policy (upcall_functor,
171 freelist,
172 time_policy),
173 max_size_ (ACE_DEFAULT_TIMERS),
174 cur_size_ (0),
175 cur_limbo_ (0),
176 timer_ids_curr_ (0),
177 timer_ids_min_free_ (0),
178 preallocated_nodes_ (0),
179 preallocated_nodes_freelist_ (0)
181 ACE_TRACE ("ACE_Timer_Heap_T::ACE_Timer_Heap_T");
183 // Possibly reduce size to fit in a long.
184 if (this->max_size_ > static_cast<size_t> (ACE_Numeric_Limits<long>::max ()))
185 this->max_size_ = static_cast<size_t> (ACE_Numeric_Limits<long>::max ());
187 // Create the heap array.
188 #if defined (ACE_HAS_ALLOC_HOOKS)
189 this->heap_ = reinterpret_cast<ACE_Timer_Node_T<TYPE> **>
190 (ACE_Allocator::instance ()->malloc (sizeof (ACE_Timer_Node_T<TYPE> *) * this->max_size_));
191 #else
192 ACE_NEW (this->heap_,
193 ACE_Timer_Node_T<TYPE> *[this->max_size_]);
194 #endif /* ACE_HAS_ALLOC_HOOKS */
196 // Create the parallel array.
197 #if defined (ACE_HAS_ALLOC_HOOKS)
198 this->timer_ids_ = reinterpret_cast<ssize_t *>
199 (ACE_Allocator::instance ()->malloc (sizeof (ssize_t) * this->max_size_));
200 #else
201 ACE_NEW (this->timer_ids_,
202 ssize_t[this->max_size_]);
203 #endif /* ACE_HAS_ALLOC_HOOKS */
205 // Initialize the "freelist," which uses negative values to
206 // distinguish freelist elements from "pointers" into the <heap_>
207 // array.
208 for (size_t i = 0; i < this->max_size_; ++i)
209 this->timer_ids_[i] = -1;
211 ACE_NEW (iterator_,
212 HEAP_ITERATOR (*this));
215 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
216 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::~ACE_Timer_Heap_T ()
218 ACE_TRACE ("ACE_Timer_Heap_T::~ACE_Timer_Heap_T");
220 delete iterator_;
222 this->close ();
224 #if defined (ACE_HAS_ALLOC_HOOKS)
225 if (this->heap_)
226 (ACE_Allocator::instance ()->free (this->heap_));
227 #else
228 delete [] this->heap_;
229 #endif /* ACE_HAS_ALLOC_HOOKS */
231 #if defined (ACE_HAS_ALLOC_HOOKS)
232 if (this->timer_ids_)
233 (ACE_Allocator::instance ()->free (this->timer_ids_));
234 #else
235 delete [] this->timer_ids_;
236 #endif /* ACE_HAS_ALLOC_HOOKS */
238 // clean up any preallocated timer nodes
239 if (preallocated_nodes_ != 0)
241 ACE_Unbounded_Set_Iterator<ACE_Timer_Node_T<TYPE> *>
242 set_iterator (this->preallocated_node_set_);
244 for (ACE_Timer_Node_T<TYPE> **entry = 0;
245 set_iterator.next (entry) !=0;
246 set_iterator.advance ())
247 delete [] *entry;
251 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> int
252 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::close ()
254 ACE_TRACE ("ACE_Timer_Heap_T::close");
256 size_t current_size =
257 this->cur_size_;
259 // Clean up all the nodes still in the queue
260 for (size_t i = 0; i < current_size; ++i)
262 // Grab the event_handler and act, then delete the node before calling
263 // back to the handler. Prevents a handler from trying to cancel_timer()
264 // inside handle_close(), ripping the current timer node out from
265 // under us.
266 TYPE eh = this->heap_[i]->get_type ();
267 const void *act = this->heap_[i]->get_act ();
268 this->free_node (this->heap_[i]);
269 this->upcall_functor ().deletion (*this, eh, act);
272 // leave the rest to the destructor
273 return 0;
276 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
277 long
278 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::pop_freelist ()
280 ACE_TRACE ("ACE_Timer_Heap_T::pop_freelist");
282 // Scan for a free timer ID. Note that since this function is called
283 // _after_ the check for a full timer heap, we are guaranteed to find
284 // a free ID, even if we need to wrap around and start reusing freed IDs.
285 // On entry, the curr_ index is at the previous ID given out; start
286 // up where we left off last time.
287 // NOTE - a timer_ids_ slot with -2 is out of the heap, but not freed.
288 // It must be either freed (free_node) or rescheduled (reschedule).
289 ++this->timer_ids_curr_;
290 while (this->timer_ids_curr_ < this->max_size_ &&
291 (this->timer_ids_[this->timer_ids_curr_] >= 0 ||
292 this->timer_ids_[this->timer_ids_curr_] == -2 ))
293 ++this->timer_ids_curr_;
294 if (this->timer_ids_curr_ == this->max_size_)
296 ACE_ASSERT (this->timer_ids_min_free_ < this->max_size_);
297 this->timer_ids_curr_ = this->timer_ids_min_free_;
298 // We restarted the free search at min. Since min won't be
299 // free anymore, and curr_ will just keep marching up the list
300 // on each successive need for an ID, reset min_free_ to the
301 // size of the list until an ID is freed that curr_ has already
302 // gone past (see push_freelist).
303 this->timer_ids_min_free_ = this->max_size_;
306 return static_cast<long> (this->timer_ids_curr_);
309 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
310 void
311 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::push_freelist (long old_id)
313 ACE_TRACE ("ACE_Timer_Heap_T::push_freelist");
315 // Since this ID has already been checked by one of the public
316 // functions, it's safe to cast it here.
317 size_t oldid = static_cast<size_t> (old_id);
319 // The freelist values in the <timer_ids_> are negative, so set the
320 // freed entry back to 'free'. If this is the new lowest value free
321 // timer ID that curr_ won't see on it's normal march through the list,
322 // remember it.
323 ACE_ASSERT (this->timer_ids_[oldid] >= 0 || this->timer_ids_[oldid] == -2);
324 if (this->timer_ids_[oldid] == -2)
325 --this->cur_limbo_;
326 else
327 --this->cur_size_;
328 this->timer_ids_[oldid] = -1;
329 if (oldid < this->timer_ids_min_free_ && oldid <= this->timer_ids_curr_)
330 this->timer_ids_min_free_ = oldid;
331 return;
334 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
335 long
336 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::timer_id ()
338 ACE_TRACE ("ACE_Timer_Heap_T::timer_id");
340 // Return the next item off the freelist and use it as the timer id.
341 return this->pop_freelist ();
344 // Checks if queue is empty.
346 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
347 bool
348 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::is_empty () const
350 ACE_TRACE ("ACE_Timer_Heap_T::is_empty");
352 return this->cur_size_ == 0;
355 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
356 ACE_Timer_Queue_Iterator_T<TYPE> &
357 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::iter ()
359 this->iterator_->first ();
360 return *this->iterator_;
363 // Returns earliest time in a non-empty queue.
365 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> const ACE_Time_Value &
366 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::earliest_time () const
368 ACE_TRACE ("ACE_Timer_Heap_T::earliest_time");
369 return this->heap_[0]->get_timer_value ();
372 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
373 void
374 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::dump () const
376 #if defined (ACE_HAS_DUMP)
377 ACE_TRACE ("ACE_Timer_Heap_T::dump");
378 ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
380 ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nmax_size_ = %d"), this->max_size_));
381 ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\ncur_size_ = %d"), this->cur_size_));
382 ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\ncur_limbo_= %d"), this->cur_limbo_));
383 ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nids_curr_ = %d"),
384 this->timer_ids_curr_));
385 ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nmin_free_ = %d"),
386 this->timer_ids_min_free_));
388 ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nheap_ =\n")));
390 for (size_t i = 0; i < this->cur_size_; ++i)
392 ACELIB_DEBUG ((LM_DEBUG,
393 ACE_TEXT ("%d\n"),
394 i));
395 this->heap_[i]->dump ();
398 ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\ntimer_ids_ =\n")));
400 for (size_t j = 0; j < this->max_size_; ++j)
401 ACELIB_DEBUG ((LM_DEBUG,
402 ACE_TEXT ("%d\t%d\n"),
404 this->timer_ids_[j]));
406 ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP));
407 #endif /* ACE_HAS_DUMP */
410 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
411 void
412 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::copy (
413 size_t slot,
414 ACE_Timer_Node_T<TYPE> *moved_node)
416 // Insert <moved_node> into its new location in the heap.
417 this->heap_[slot] = moved_node;
419 ACE_ASSERT (moved_node->get_timer_id () >= 0
420 && moved_node->get_timer_id () < (int) this->max_size_);
422 // Update the corresponding slot in the parallel <timer_ids_> array.
423 this->timer_ids_[moved_node->get_timer_id ()] = static_cast<ssize_t> (slot);
426 // Remove the slot'th timer node from the heap, but do not reclaim its
427 // timer ID or change the size of this timer heap object. The caller of
428 // this function must call either free_node (to reclaim the timer ID
429 // and the timer node memory, as well as decrement the size of the queue)
430 // or reschedule (to reinsert the node in the heap at a new time).
431 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
432 ACE_Timer_Node_T<TYPE> *
433 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::remove (size_t slot)
435 ACE_Timer_Node_T<TYPE> *removed_node =
436 this->heap_[slot];
438 // NOTE - the cur_size_ is being decremented since the queue has one
439 // less active timer in it. However, this ACE_Timer_Node is not being
440 // freed, and there is still a place for it in timer_ids_ (the timer ID
441 // is not being relinquished). The node can still be rescheduled, or
442 // it can be freed via free_node.
443 --this->cur_size_;
445 // Only try to reheapify if we're not deleting the last entry.
447 if (slot < this->cur_size_)
449 ACE_Timer_Node_T<TYPE> *moved_node =
450 this->heap_[this->cur_size_];
452 // Move the end node to the location being removed and update
453 // the corresponding slot in the parallel <timer_ids> array.
454 this->copy (slot, moved_node);
456 // If the <moved_node->time_value_> is great than or equal its
457 // parent it needs be moved down the heap.
458 size_t parent = ACE_HEAP_PARENT (slot);
460 if (moved_node->get_timer_value ()
461 >= this->heap_[parent]->get_timer_value ())
462 this->reheap_down (moved_node,
463 slot,
464 ACE_HEAP_LCHILD (slot));
465 else
466 this->reheap_up (moved_node,
467 slot,
468 parent);
471 this->timer_ids_[removed_node->get_timer_id ()] = -2;
472 ++this->cur_limbo_;
473 return removed_node;
476 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> void
477 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::reheap_down (
478 ACE_Timer_Node_T<TYPE> *moved_node,
479 size_t slot,
480 size_t child)
482 // Restore the heap property after a deletion.
484 while (child < this->cur_size_)
486 // Choose the smaller of the two children.
487 if (child + 1 < this->cur_size_
488 && this->heap_[child + 1]->get_timer_value ()
489 < this->heap_[child]->get_timer_value ())
490 child++;
492 // Perform a <copy> if the child has a larger timeout value than
493 // the <moved_node>.
494 if (this->heap_[child]->get_timer_value ()
495 < moved_node->get_timer_value ())
497 this->copy (slot,
498 this->heap_[child]);
499 slot = child;
500 child = ACE_HEAP_LCHILD (child);
502 else
503 // We've found our location in the heap.
504 break;
507 this->copy (slot, moved_node);
510 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
511 void
512 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::reheap_up (
513 ACE_Timer_Node_T<TYPE> *moved_node,
514 size_t slot,
515 size_t parent)
517 // Restore the heap property after an insertion.
519 while (slot > 0)
521 // If the parent node is greater than the <moved_node> we need
522 // to copy it down.
523 if (moved_node->get_timer_value ()
524 < this->heap_[parent]->get_timer_value ())
526 this->copy (slot, this->heap_[parent]);
527 slot = parent;
528 parent = ACE_HEAP_PARENT (slot);
530 else
531 break;
534 // Insert the new node into its proper resting place in the heap and
535 // update the corresponding slot in the parallel <timer_ids> array.
536 this->copy (slot,
537 moved_node);
540 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
541 void
542 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::insert (
543 ACE_Timer_Node_T<TYPE> *new_node)
545 if (this->cur_size_ + this->cur_limbo_ + 2 >= this->max_size_)
546 this->grow_heap ();
548 this->reheap_up (new_node,
549 this->cur_size_,
550 ACE_HEAP_PARENT (this->cur_size_));
551 this->cur_size_++;
554 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
555 void
556 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::grow_heap ()
558 // All the containers will double in size from max_size_.
559 size_t new_size = this->max_size_ * 2;
561 // First grow the heap itself.
562 ACE_Timer_Node_T<TYPE> **new_heap = 0;
564 #if defined (ACE_HAS_ALLOC_HOOKS)
565 new_heap = reinterpret_cast<ACE_Timer_Node_T<TYPE> **>
566 (ACE_Allocator::instance ()->malloc (sizeof (ACE_Timer_Node_T<TYPE> *) * new_size));
567 #else
568 ACE_NEW (new_heap,
569 ACE_Timer_Node_T<TYPE> *[new_size]);
570 #endif /* ACE_HAS_ALLOC_HOOKS */
572 ACE_OS::memcpy (new_heap,
573 this->heap_,
574 this->max_size_ * sizeof *new_heap);
576 #if defined (ACE_HAS_ALLOC_HOOKS)
577 ACE_Allocator::instance ()->free (this->heap_);
578 #else
579 delete [] this->heap_;
580 #endif /* ACE_HAS_ALLOC_HOOKS */
582 this->heap_ = new_heap;
584 // Grow the array of timer ids.
586 ssize_t *new_timer_ids = 0;
588 #if defined (ACE_HAS_ALLOC_HOOKS)
589 new_timer_ids = reinterpret_cast<ssize_t *>
590 (ACE_Allocator::instance ()->malloc (sizeof (ssize_t) * new_size));
591 #else
592 ACE_NEW (new_timer_ids,
593 ssize_t[new_size]);
594 #endif /* ACE_HAS_ALLOC_HOOKS */
596 ACE_OS::memcpy (new_timer_ids,
597 this->timer_ids_,
598 this->max_size_ * sizeof (ssize_t));
600 #if defined (ACE_HAS_ALLOC_HOOKS)
601 if (this->timer_ids_)
602 (ACE_Allocator::instance ()->free (this->timer_ids_));
603 #else
604 delete [] this->timer_ids_;
605 #endif /* ACE_HAS_ALLOC_HOOKS */
606 this->timer_ids_ = new_timer_ids;
608 // And add the new elements to the end of the "freelist".
609 for (size_t i = this->max_size_; i < new_size; ++i)
610 this->timer_ids_[i] = -(static_cast<ssize_t> (i) + 1);
612 // Grow the preallocation array (if using preallocation)
613 if (this->preallocated_nodes_ != 0)
615 // Create a new array with max_size elements to link in to
616 // existing list.
617 ACE_NEW (this->preallocated_nodes_,
618 ACE_Timer_Node_T<TYPE>[this->max_size_]);
620 // Add it to the set for later deletion
621 this->preallocated_node_set_.insert (this->preallocated_nodes_);
623 // Link new nodes together (as for original list).
624 for (size_t k = 1; k < this->max_size_; ++k)
625 this->preallocated_nodes_[k - 1].set_next (&this->preallocated_nodes_[k]);
627 // NULL-terminate the new list.
628 this->preallocated_nodes_[this->max_size_ - 1].set_next (0);
630 // Link new array to the end of the existling list.
631 if (this->preallocated_nodes_freelist_ == 0)
632 this->preallocated_nodes_freelist_ =
633 &preallocated_nodes_[0];
634 else
636 ACE_Timer_Node_T<TYPE> *previous =
637 this->preallocated_nodes_freelist_;
639 for (ACE_Timer_Node_T<TYPE> *current = this->preallocated_nodes_freelist_->get_next ();
640 current != 0;
641 current = current->get_next ())
642 previous = current;
644 previous->set_next (&this->preallocated_nodes_[0]);
648 this->max_size_ = new_size;
649 // Force rescan of list from beginning for a free slot (I think...)
650 // This fixed Bugzilla #2447.
651 this->timer_ids_min_free_ = this->max_size_;
654 // Reschedule a periodic timer. This function must be called with the
655 // mutex lock held.
657 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
658 void
659 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::reschedule (
660 ACE_Timer_Node_T<TYPE> *expired)
662 ACE_TRACE ("ACE_Timer_Heap_T::reschedule");
664 // If we are rescheduling, then the most recent call was to
665 // remove_first (). That called remove () to remove the node from the
666 // heap, but did not free the timer ID. The ACE_Timer_Node still has
667 // its assigned ID - just needs to be inserted at the new proper
668 // place, and the heap restored properly.
669 if (this->timer_ids_[expired->get_timer_id ()] == -2)
670 --this->cur_limbo_;
671 this->insert (expired);
674 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
675 ACE_Timer_Node_T<TYPE> *
676 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::alloc_node ()
678 ACE_Timer_Node_T<TYPE> *temp = 0;
680 // Only allocate a node if we are *not* using the preallocated heap.
681 if (this->preallocated_nodes_ == 0)
682 ACE_NEW_RETURN (temp,
683 ACE_Timer_Node_T<TYPE>,
685 else
687 // check to see if the heap needs to grow
688 if (this->preallocated_nodes_freelist_ == 0)
689 this->grow_heap ();
691 temp = this->preallocated_nodes_freelist_;
693 if (this->preallocated_nodes_freelist_)
695 // Remove the first element from the freelist.
696 this->preallocated_nodes_freelist_ =
697 this->preallocated_nodes_freelist_->get_next ();
700 return temp;
703 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
704 void
705 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::free_node (
706 ACE_Timer_Node_T<TYPE> *node)
708 // Return this timer id to the freelist.
709 this->push_freelist (node->get_timer_id ());
711 // Only free up a node if we are *not* using the preallocated heap.
712 if (this->preallocated_nodes_ == 0)
713 delete node;
714 else
716 node->set_next (this->preallocated_nodes_freelist_);
717 this->preallocated_nodes_freelist_ = node;
721 // Insert a new timer that expires at time future_time; if interval is
722 // > 0, the handler will be reinvoked periodically.
724 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
725 long
726 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::schedule_i (
727 const TYPE &type,
728 const void *act,
729 const ACE_Time_Value &future_time,
730 const ACE_Time_Value &interval)
732 ACE_TRACE ("ACE_Timer_Heap_T::schedule_i");
734 if ((this->cur_size_ + this->cur_limbo_) < this->max_size_)
736 // Obtain the next unique sequence number.
737 long const timer_id = this->timer_id ();
739 // Obtain the memory to the new node.
740 ACE_Timer_Node_T<TYPE> *temp = 0;
742 ACE_ALLOCATOR_RETURN (temp,
743 this->alloc_node (),
744 -1);
745 temp->set (type,
746 act,
747 future_time,
748 interval,
750 timer_id);
752 this->insert (temp);
753 return timer_id;
755 else
756 return -1;
759 // Locate and remove the single timer with a value of @a timer_id from
760 // the timer queue.
762 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
764 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::cancel (long timer_id,
765 const void **act,
766 int dont_call)
768 ACE_TRACE ("ACE_Timer_Heap_T::cancel");
769 ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, -1));
771 // Locate the ACE_Timer_Node that corresponds to the timer_id.
773 // Check to see if the timer_id is out of range
774 if (timer_id < 0
775 || (size_t) timer_id > this->max_size_)
776 return 0;
778 ssize_t timer_node_slot = this->timer_ids_[timer_id];
780 // Check to see if timer_id is still valid.
781 if (timer_node_slot < 0)
782 return 0;
784 if (timer_id != this->heap_[timer_node_slot]->get_timer_id ())
786 ACE_ASSERT (timer_id == this->heap_[timer_node_slot]->get_timer_id ());
787 return 0;
789 else
791 ACE_Timer_Node_T<TYPE> *temp =
792 this->remove (timer_node_slot);
794 // Call the close hooks.
795 int cookie = 0;
797 // cancel_type() called once per <type>.
798 this->upcall_functor ().cancel_type (*this,
799 temp->get_type (),
800 dont_call,
801 cookie);
803 // cancel_timer() called once per <timer>.
804 this->upcall_functor ().cancel_timer (*this,
805 temp->get_type (),
806 dont_call,
807 cookie);
809 if (act != 0)
810 *act = temp->get_act ();
812 this->free_node (temp);
813 return 1;
817 // Locate and update the inteval on the timer_id
819 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
821 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::reset_interval (long timer_id,
822 const ACE_Time_Value &interval)
824 ACE_TRACE ("ACE_Timer_Heap_T::reset_interval");
825 ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, -1));
827 // Locate the ACE_Timer_Node that corresponds to the timer_id.
829 // Check to see if the timer_id is out of range
830 if (timer_id < 0
831 || (size_t) timer_id > this->max_size_)
832 return -1;
834 ssize_t timer_node_slot = this->timer_ids_[timer_id];
836 // Check to see if timer_id is still valid.
837 if (timer_node_slot < 0)
838 return -1;
840 if (timer_id != this->heap_[timer_node_slot]->get_timer_id ())
842 ACE_ASSERT (timer_id == this->heap_[timer_node_slot]->get_timer_id ());
843 return -1;
845 else
847 // Reset the timer interval
848 this->heap_[timer_node_slot]->set_interval (interval);
849 return 0;
853 // Locate and remove all values of @a type from the timer queue.
855 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
857 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::cancel (const TYPE &type,
858 int dont_call)
860 ACE_TRACE ("ACE_Timer_Heap_T::cancel");
862 ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, -1));
864 int number_of_cancellations = 0;
866 // Try to locate the ACE_Timer_Node that matches the timer_id.
868 for (size_t i = 0; i < this->cur_size_; )
870 if (this->heap_[i]->get_type () == type)
872 ACE_Timer_Node_T<TYPE> *temp = this->remove (i);
874 ++number_of_cancellations;
876 this->free_node (temp);
878 // We reset to zero so that we don't miss checking any nodes
879 // if a reheapify occurs when a node is removed. There
880 // may be a better fix than this, however.
881 i = 0;
883 else
884 ++i;
887 // Call the close hooks.
888 int cookie = 0;
890 // cancel_type() called once per <type>.
891 this->upcall_functor ().cancel_type (*this,
892 type,
893 dont_call,
894 cookie);
896 for (int j = 0;
897 j < number_of_cancellations;
898 ++j)
900 // cancel_timer() called once per <timer>.
901 this->upcall_functor ().cancel_timer (*this,
902 type,
903 dont_call,
904 cookie);
907 return number_of_cancellations;
910 // Returns the earliest node or returns 0 if the heap is empty.
912 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
913 ACE_Timer_Node_T <TYPE> *
914 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::remove_first ()
916 ACE_TRACE ("ACE_Timer_Heap_T::remove_first");
918 if (this->cur_size_ == 0)
919 return 0;
921 return this->remove (0);
924 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
925 ACE_Timer_Node_T <TYPE> *
926 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::get_first ()
928 ACE_TRACE ("ACE_Timer_Heap_T::get_first");
930 return this->cur_size_ == 0 ? 0 : this->heap_[0];
933 ACE_END_VERSIONED_NAMESPACE_DECL
935 #endif /* ACE_TIMER_HEAP_T_CPP */