Removed ACE_HAS_BSTRING, not used
[ACE_TAO.git] / ACE / ace / Timer_Heap_T.cpp
blobfa2704ed82c8e4c727d02ead34d2adf10e89c0fc
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.
43 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
44 ACE_Timer_Heap_Iterator_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::ACE_Timer_Heap_Iterator_T (
45 Heap & heap)
46 : timer_heap_ (heap)
48 ACE_TRACE ("ACE_Timer_Heap_Iterator_T::ACE_Timer_Heap_Iterator");
49 this->first ();
52 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
53 ACE_Timer_Heap_Iterator_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::~ACE_Timer_Heap_Iterator_T (void)
57 // Positions the iterator at the first node in the heap array
59 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
60 void
61 ACE_Timer_Heap_Iterator_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::first (void)
63 this->position_ = 0;
66 // Positions the iterator at the next node in the heap array
68 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
69 void
70 ACE_Timer_Heap_Iterator_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::next (void)
72 if (this->position_ != this->timer_heap_.cur_size_)
73 ++this->position_;
76 // Returns true the <position_> is at the end of the heap array
78 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> bool
79 ACE_Timer_Heap_Iterator_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::isdone (void) const
81 return this->position_ == this->timer_heap_.cur_size_;
84 // Returns the node at the current position in the heap or 0 if at the end
86 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> ACE_Timer_Node_T<TYPE> *
87 ACE_Timer_Heap_Iterator_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::item (void)
89 if (this->position_ != this->timer_heap_.cur_size_)
90 return this->timer_heap_.heap_[this->position_];
91 return 0;
94 // Constructor
95 // Note that timer_ids_curr_ and timer_ids_min_free_ both start at 0.
96 // Since timer IDs are assigned by first incrementing the timer_ids_curr_
97 // value, the first ID assigned will be 1 (just as in the previous design).
98 // When it's time to wrap, the next ID given out will be 0.
99 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
100 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::ACE_Timer_Heap_T (
101 size_t size,
102 bool preallocated,
103 FUNCTOR *upcall_functor,
104 ACE_Free_List<ACE_Timer_Node_T <TYPE> > *freelist,
105 TIME_POLICY const & time_policy)
106 : Base_Time_Policy (upcall_functor,
107 freelist,
108 time_policy),
109 max_size_ (size),
110 cur_size_ (0),
111 cur_limbo_ (0),
112 timer_ids_curr_ (0),
113 timer_ids_min_free_ (0),
114 preallocated_nodes_ (0),
115 preallocated_nodes_freelist_ (0)
117 ACE_TRACE ("ACE_Timer_Heap_T::ACE_Timer_Heap_T");
119 // Possibly reduce size to fit in a long.
120 if (size > static_cast<size_t> (ACE_Numeric_Limits<long>::max ()))
122 size = static_cast<size_t> (ACE_Numeric_Limits<long>::max ());
123 this->max_size_ = size;
126 // Create the heap array.
127 #if defined (ACE_HAS_ALLOC_HOOKS)
128 this->heap_ = reinterpret_cast<ACE_Timer_Node_T<TYPE> **>
129 (ACE_Allocator::instance ()->malloc (sizeof (ACE_Timer_Node_T<TYPE> *) * size));
130 #else
131 ACE_NEW (this->heap_,
132 ACE_Timer_Node_T<TYPE> *[size]);
133 #endif /* ACE_HAS_ALLOC_HOOKS */
135 // Create the parallel
136 ACE_NEW (this->timer_ids_,
137 ssize_t[size]);
139 // Initialize the "freelist," which uses negative values to
140 // distinguish freelist elements from "pointers" into the <heap_>
141 // array.
142 for (size_t i = 0; i < size; ++i)
143 this->timer_ids_[i] = -1;
145 if (preallocated)
147 ACE_NEW (this->preallocated_nodes_,
148 ACE_Timer_Node_T<TYPE>[size]);
150 // Add allocated array to set of such arrays for deletion on
151 // cleanup.
152 this->preallocated_node_set_.insert (this->preallocated_nodes_);
154 // Form the freelist by linking the next_ pointers together.
155 for (size_t j = 1; j < size; ++j)
156 this->preallocated_nodes_[j - 1].set_next (&this->preallocated_nodes_[j]);
158 // NULL-terminate the freelist.
159 this->preallocated_nodes_[size - 1].set_next (0);
161 // Assign the freelist pointer to the front of the list.
162 this->preallocated_nodes_freelist_ =
163 &this->preallocated_nodes_[0];
166 ACE_NEW (iterator_,
167 HEAP_ITERATOR (*this));
170 // Note that timer_ids_curr_ and timer_ids_min_free_ both start at 0.
171 // Since timer IDs are assigned by first incrementing the timer_ids_curr_
172 // value, the first ID assigned will be 1 (just as in the previous design).
173 // When it's time to wrap, the next ID given out will be 0.
174 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
175 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::ACE_Timer_Heap_T (
176 FUNCTOR *upcall_functor,
177 ACE_Free_List<ACE_Timer_Node_T <TYPE> > *freelist,
178 TIME_POLICY const & time_policy)
179 : Base_Time_Policy (upcall_functor,
180 freelist,
181 time_policy),
182 max_size_ (ACE_DEFAULT_TIMERS),
183 cur_size_ (0),
184 cur_limbo_ (0),
185 timer_ids_curr_ (0),
186 timer_ids_min_free_ (0),
187 preallocated_nodes_ (0),
188 preallocated_nodes_freelist_ (0)
190 ACE_TRACE ("ACE_Timer_Heap_T::ACE_Timer_Heap_T");
192 // Possibly reduce size to fit in a long.
193 if (this->max_size_ > static_cast<size_t> (ACE_Numeric_Limits<long>::max ()))
194 this->max_size_ = static_cast<size_t> (ACE_Numeric_Limits<long>::max ());
196 // Create the heap array.
197 #if defined (ACE_HAS_ALLOC_HOOKS)
198 this->heap_ = reinterpret_cast<ACE_Timer_Node_T<TYPE> **>
199 (ACE_Allocator::instance ()->malloc (sizeof (ACE_Timer_Node_T<TYPE> *) * this->max_size_));
200 #else
201 ACE_NEW (this->heap_,
202 ACE_Timer_Node_T<TYPE> *[this->max_size_]);
203 #endif /* ACE_HAS_ALLOC_HOOKS */
205 // Create the parallel array.
206 #if defined (ACE_HAS_ALLOC_HOOKS)
207 this->timer_ids_ = reinterpret_cast<ssize_t *>
208 (ACE_Allocator::instance ()->malloc (sizeof (ssize_t) * this->max_size_));
209 #else
210 ACE_NEW (this->timer_ids_,
211 ssize_t[this->max_size_]);
212 #endif /* ACE_HAS_ALLOC_HOOKS */
214 // Initialize the "freelist," which uses negative values to
215 // distinguish freelist elements from "pointers" into the <heap_>
216 // array.
217 for (size_t i = 0; i < this->max_size_; ++i)
218 this->timer_ids_[i] = -1;
220 ACE_NEW (iterator_,
221 HEAP_ITERATOR (*this));
224 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
225 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::~ACE_Timer_Heap_T (void)
227 ACE_TRACE ("ACE_Timer_Heap_T::~ACE_Timer_Heap_T");
229 delete iterator_;
231 this->close ();
233 #if defined (ACE_HAS_ALLOC_HOOKS)
234 if (this->heap_)
235 (ACE_Allocator::instance ()->free (this->heap_));
236 #else
237 delete [] this->heap_;
238 #endif /* ACE_HAS_ALLOC_HOOKS */
240 #if defined (ACE_HAS_ALLOC_HOOKS)
241 if (this->timer_ids_)
242 (ACE_Allocator::instance ()->free (this->timer_ids_));
243 #else
244 delete [] this->timer_ids_;
245 #endif /* ACE_HAS_ALLOC_HOOKS */
247 // clean up any preallocated timer nodes
248 if (preallocated_nodes_ != 0)
250 ACE_Unbounded_Set_Iterator<ACE_Timer_Node_T<TYPE> *>
251 set_iterator (this->preallocated_node_set_);
253 for (ACE_Timer_Node_T<TYPE> **entry = 0;
254 set_iterator.next (entry) !=0;
255 set_iterator.advance ())
256 delete [] *entry;
260 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> int
261 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::close (void)
263 ACE_TRACE ("ACE_Timer_Heap_T::close");
265 size_t current_size =
266 this->cur_size_;
268 // Clean up all the nodes still in the queue
269 for (size_t i = 0; i < current_size; ++i)
271 // Grab the event_handler and act, then delete the node before calling
272 // back to the handler. Prevents a handler from trying to cancel_timer()
273 // inside handle_close(), ripping the current timer node out from
274 // under us.
275 TYPE eh = this->heap_[i]->get_type ();
276 const void *act = this->heap_[i]->get_act ();
277 this->free_node (this->heap_[i]);
278 this->upcall_functor ().deletion (*this, eh, act);
281 // leave the rest to the destructor
282 return 0;
285 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
286 long
287 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::pop_freelist (void)
289 ACE_TRACE ("ACE_Timer_Heap_T::pop_freelist");
291 // Scan for a free timer ID. Note that since this function is called
292 // _after_ the check for a full timer heap, we are guaranteed to find
293 // a free ID, even if we need to wrap around and start reusing freed IDs.
294 // On entry, the curr_ index is at the previous ID given out; start
295 // up where we left off last time.
296 // NOTE - a timer_ids_ slot with -2 is out of the heap, but not freed.
297 // It must be either freed (free_node) or rescheduled (reschedule).
298 ++this->timer_ids_curr_;
299 while (this->timer_ids_curr_ < this->max_size_ &&
300 (this->timer_ids_[this->timer_ids_curr_] >= 0 ||
301 this->timer_ids_[this->timer_ids_curr_] == -2 ))
302 ++this->timer_ids_curr_;
303 if (this->timer_ids_curr_ == this->max_size_)
305 ACE_ASSERT (this->timer_ids_min_free_ < this->max_size_);
306 this->timer_ids_curr_ = this->timer_ids_min_free_;
307 // We restarted the free search at min. Since min won't be
308 // free anymore, and curr_ will just keep marching up the list
309 // on each successive need for an ID, reset min_free_ to the
310 // size of the list until an ID is freed that curr_ has already
311 // gone past (see push_freelist).
312 this->timer_ids_min_free_ = this->max_size_;
315 return static_cast<long> (this->timer_ids_curr_);
318 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
319 void
320 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::push_freelist (long old_id)
322 ACE_TRACE ("ACE_Timer_Heap_T::push_freelist");
324 // Since this ID has already been checked by one of the public
325 // functions, it's safe to cast it here.
326 size_t oldid = static_cast<size_t> (old_id);
328 // The freelist values in the <timer_ids_> are negative, so set the
329 // freed entry back to 'free'. If this is the new lowest value free
330 // timer ID that curr_ won't see on it's normal march through the list,
331 // remember it.
332 ACE_ASSERT (this->timer_ids_[oldid] >= 0 || this->timer_ids_[oldid] == -2);
333 if (this->timer_ids_[oldid] == -2)
334 --this->cur_limbo_;
335 else
336 --this->cur_size_;
337 this->timer_ids_[oldid] = -1;
338 if (oldid < this->timer_ids_min_free_ && oldid <= this->timer_ids_curr_)
339 this->timer_ids_min_free_ = oldid;
340 return;
343 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
344 long
345 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::timer_id (void)
347 ACE_TRACE ("ACE_Timer_Heap_T::timer_id");
349 // Return the next item off the freelist and use it as the timer id.
350 return this->pop_freelist ();
353 // Checks if queue is empty.
355 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
356 bool
357 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::is_empty (void) const
359 ACE_TRACE ("ACE_Timer_Heap_T::is_empty");
361 return this->cur_size_ == 0;
364 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
365 ACE_Timer_Queue_Iterator_T<TYPE> &
366 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::iter (void)
368 this->iterator_->first ();
369 return *this->iterator_;
372 // Returns earliest time in a non-empty queue.
374 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> const ACE_Time_Value &
375 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::earliest_time (void) const
377 ACE_TRACE ("ACE_Timer_Heap_T::earliest_time");
378 return this->heap_[0]->get_timer_value ();
381 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
382 void
383 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::dump (void) const
385 #if defined (ACE_HAS_DUMP)
386 ACE_TRACE ("ACE_Timer_Heap_T::dump");
387 ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
389 ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nmax_size_ = %d"), this->max_size_));
390 ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\ncur_size_ = %d"), this->cur_size_));
391 ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\ncur_limbo_= %d"), this->cur_limbo_));
392 ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nids_curr_ = %d"),
393 this->timer_ids_curr_));
394 ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nmin_free_ = %d"),
395 this->timer_ids_min_free_));
397 ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nheap_ =\n")));
399 for (size_t i = 0; i < this->cur_size_; ++i)
401 ACELIB_DEBUG ((LM_DEBUG,
402 ACE_TEXT ("%d\n"),
403 i));
404 this->heap_[i]->dump ();
407 ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\ntimer_ids_ =\n")));
409 for (size_t j = 0; j < this->max_size_; ++j)
410 ACELIB_DEBUG ((LM_DEBUG,
411 ACE_TEXT ("%d\t%d\n"),
413 this->timer_ids_[j]));
415 ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP));
416 #endif /* ACE_HAS_DUMP */
419 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
420 void
421 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::copy (
422 size_t slot,
423 ACE_Timer_Node_T<TYPE> *moved_node)
425 // Insert <moved_node> into its new location in the heap.
426 this->heap_[slot] = moved_node;
428 ACE_ASSERT (moved_node->get_timer_id () >= 0
429 && moved_node->get_timer_id () < (int) this->max_size_);
431 // Update the corresponding slot in the parallel <timer_ids_> array.
432 this->timer_ids_[moved_node->get_timer_id ()] = static_cast<ssize_t> (slot);
435 // Remove the slot'th timer node from the heap, but do not reclaim its
436 // timer ID or change the size of this timer heap object. The caller of
437 // this function must call either free_node (to reclaim the timer ID
438 // and the timer node memory, as well as decrement the size of the queue)
439 // or reschedule (to reinsert the node in the heap at a new time).
440 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
441 ACE_Timer_Node_T<TYPE> *
442 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::remove (size_t slot)
444 ACE_Timer_Node_T<TYPE> *removed_node =
445 this->heap_[slot];
447 // NOTE - the cur_size_ is being decremented since the queue has one
448 // less active timer in it. However, this ACE_Timer_Node is not being
449 // freed, and there is still a place for it in timer_ids_ (the timer ID
450 // is not being relinquished). The node can still be rescheduled, or
451 // it can be freed via free_node.
452 --this->cur_size_;
454 // Only try to reheapify if we're not deleting the last entry.
456 if (slot < this->cur_size_)
458 ACE_Timer_Node_T<TYPE> *moved_node =
459 this->heap_[this->cur_size_];
461 // Move the end node to the location being removed and update
462 // the corresponding slot in the parallel <timer_ids> array.
463 this->copy (slot, moved_node);
465 // If the <moved_node->time_value_> is great than or equal its
466 // parent it needs be moved down the heap.
467 size_t parent = ACE_HEAP_PARENT (slot);
469 if (moved_node->get_timer_value ()
470 >= this->heap_[parent]->get_timer_value ())
471 this->reheap_down (moved_node,
472 slot,
473 ACE_HEAP_LCHILD (slot));
474 else
475 this->reheap_up (moved_node,
476 slot,
477 parent);
480 this->timer_ids_[removed_node->get_timer_id ()] = -2;
481 ++this->cur_limbo_;
482 return removed_node;
485 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY> void
486 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::reheap_down (
487 ACE_Timer_Node_T<TYPE> *moved_node,
488 size_t slot,
489 size_t child)
491 // Restore the heap property after a deletion.
493 while (child < this->cur_size_)
495 // Choose the smaller of the two children.
496 if (child + 1 < this->cur_size_
497 && this->heap_[child + 1]->get_timer_value ()
498 < this->heap_[child]->get_timer_value ())
499 child++;
501 // Perform a <copy> if the child has a larger timeout value than
502 // the <moved_node>.
503 if (this->heap_[child]->get_timer_value ()
504 < moved_node->get_timer_value ())
506 this->copy (slot,
507 this->heap_[child]);
508 slot = child;
509 child = ACE_HEAP_LCHILD (child);
511 else
512 // We've found our location in the heap.
513 break;
516 this->copy (slot, moved_node);
519 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
520 void
521 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::reheap_up (
522 ACE_Timer_Node_T<TYPE> *moved_node,
523 size_t slot,
524 size_t parent)
526 // Restore the heap property after an insertion.
528 while (slot > 0)
530 // If the parent node is greater than the <moved_node> we need
531 // to copy it down.
532 if (moved_node->get_timer_value ()
533 < this->heap_[parent]->get_timer_value ())
535 this->copy (slot, this->heap_[parent]);
536 slot = parent;
537 parent = ACE_HEAP_PARENT (slot);
539 else
540 break;
543 // Insert the new node into its proper resting place in the heap and
544 // update the corresponding slot in the parallel <timer_ids> array.
545 this->copy (slot,
546 moved_node);
549 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
550 void
551 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::insert (
552 ACE_Timer_Node_T<TYPE> *new_node)
554 if (this->cur_size_ + this->cur_limbo_ + 2 >= this->max_size_)
555 this->grow_heap ();
557 this->reheap_up (new_node,
558 this->cur_size_,
559 ACE_HEAP_PARENT (this->cur_size_));
560 this->cur_size_++;
563 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
564 void
565 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::grow_heap (void)
567 // All the containers will double in size from max_size_.
568 size_t new_size = this->max_size_ * 2;
570 // First grow the heap itself.
571 ACE_Timer_Node_T<TYPE> **new_heap = 0;
573 #if defined (ACE_HAS_ALLOC_HOOKS)
574 new_heap = reinterpret_cast<ACE_Timer_Node_T<TYPE> **>
575 (ACE_Allocator::instance ()->malloc (sizeof (ACE_Timer_Node_T<TYPE> *) * new_size));
576 #else
577 ACE_NEW (new_heap,
578 ACE_Timer_Node_T<TYPE> *[new_size]);
579 #endif /* ACE_HAS_ALLOC_HOOKS */
581 ACE_OS::memcpy (new_heap,
582 this->heap_,
583 this->max_size_ * sizeof *new_heap);
585 #if defined (ACE_HAS_ALLOC_HOOKS)
586 ACE_Allocator::instance ()->free (this->heap_);
587 #else
588 delete [] this->heap_;
589 #endif /* ACE_HAS_ALLOC_HOOKS */
591 this->heap_ = new_heap;
593 // Grow the array of timer ids.
595 ssize_t *new_timer_ids = 0;
597 #if defined (ACE_HAS_ALLOC_HOOKS)
598 new_timer_ids = reinterpret_cast<ssize_t *>
599 (ACE_Allocator::instance ()->malloc (sizeof (ssize_t) * new_size));
600 #else
601 ACE_NEW (new_timer_ids,
602 ssize_t[new_size]);
603 #endif /* ACE_HAS_ALLOC_HOOKS */
605 ACE_OS::memcpy (new_timer_ids,
606 this->timer_ids_,
607 this->max_size_ * sizeof (ssize_t));
609 #if defined (ACE_HAS_ALLOC_HOOKS)
610 if (this->timer_ids_)
611 (ACE_Allocator::instance ()->free (this->timer_ids_));
612 #else
613 delete [] this->timer_ids_;
614 #endif /* ACE_HAS_ALLOC_HOOKS */
615 this->timer_ids_ = new_timer_ids;
617 // And add the new elements to the end of the "freelist".
618 for (size_t i = this->max_size_; i < new_size; ++i)
619 this->timer_ids_[i] = -(static_cast<ssize_t> (i) + 1);
621 // Grow the preallocation array (if using preallocation)
622 if (this->preallocated_nodes_ != 0)
624 // Create a new array with max_size elements to link in to
625 // existing list.
626 ACE_NEW (this->preallocated_nodes_,
627 ACE_Timer_Node_T<TYPE>[this->max_size_]);
629 // Add it to the set for later deletion
630 this->preallocated_node_set_.insert (this->preallocated_nodes_);
632 // Link new nodes together (as for original list).
633 for (size_t k = 1; k < this->max_size_; ++k)
634 this->preallocated_nodes_[k - 1].set_next (&this->preallocated_nodes_[k]);
636 // NULL-terminate the new list.
637 this->preallocated_nodes_[this->max_size_ - 1].set_next (0);
639 // Link new array to the end of the existling list.
640 if (this->preallocated_nodes_freelist_ == 0)
641 this->preallocated_nodes_freelist_ =
642 &preallocated_nodes_[0];
643 else
645 ACE_Timer_Node_T<TYPE> *previous =
646 this->preallocated_nodes_freelist_;
648 for (ACE_Timer_Node_T<TYPE> *current = this->preallocated_nodes_freelist_->get_next ();
649 current != 0;
650 current = current->get_next ())
651 previous = current;
653 previous->set_next (&this->preallocated_nodes_[0]);
657 this->max_size_ = new_size;
658 // Force rescan of list from beginning for a free slot (I think...)
659 // This fixed Bugzilla #2447.
660 this->timer_ids_min_free_ = this->max_size_;
663 // Reschedule a periodic timer. This function must be called with the
664 // mutex lock held.
666 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
667 void
668 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::reschedule (
669 ACE_Timer_Node_T<TYPE> *expired)
671 ACE_TRACE ("ACE_Timer_Heap_T::reschedule");
673 // If we are rescheduling, then the most recent call was to
674 // remove_first (). That called remove () to remove the node from the
675 // heap, but did not free the timer ID. The ACE_Timer_Node still has
676 // its assigned ID - just needs to be inserted at the new proper
677 // place, and the heap restored properly.
678 if (this->timer_ids_[expired->get_timer_id ()] == -2)
679 --this->cur_limbo_;
680 this->insert (expired);
683 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
684 ACE_Timer_Node_T<TYPE> *
685 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::alloc_node (void)
687 ACE_Timer_Node_T<TYPE> *temp = 0;
689 // Only allocate a node if we are *not* using the preallocated heap.
690 if (this->preallocated_nodes_ == 0)
691 ACE_NEW_RETURN (temp,
692 ACE_Timer_Node_T<TYPE>,
694 else
696 // check to see if the heap needs to grow
697 if (this->preallocated_nodes_freelist_ == 0)
698 this->grow_heap ();
700 temp = this->preallocated_nodes_freelist_;
702 if (this->preallocated_nodes_freelist_)
704 // Remove the first element from the freelist.
705 this->preallocated_nodes_freelist_ =
706 this->preallocated_nodes_freelist_->get_next ();
709 return temp;
712 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
713 void
714 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::free_node (
715 ACE_Timer_Node_T<TYPE> *node)
717 // Return this timer id to the freelist.
718 this->push_freelist (node->get_timer_id ());
720 // Only free up a node if we are *not* using the preallocated heap.
721 if (this->preallocated_nodes_ == 0)
722 delete node;
723 else
725 node->set_next (this->preallocated_nodes_freelist_);
726 this->preallocated_nodes_freelist_ = node;
730 // Insert a new timer that expires at time future_time; if interval is
731 // > 0, the handler will be reinvoked periodically.
733 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
734 long
735 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::schedule_i (
736 const TYPE &type,
737 const void *act,
738 const ACE_Time_Value &future_time,
739 const ACE_Time_Value &interval)
741 ACE_TRACE ("ACE_Timer_Heap_T::schedule_i");
743 if ((this->cur_size_ + this->cur_limbo_) < this->max_size_)
745 // Obtain the next unique sequence number.
746 long const timer_id = this->timer_id ();
748 // Obtain the memory to the new node.
749 ACE_Timer_Node_T<TYPE> *temp = 0;
751 ACE_ALLOCATOR_RETURN (temp,
752 this->alloc_node (),
753 -1);
754 temp->set (type,
755 act,
756 future_time,
757 interval,
759 timer_id);
761 this->insert (temp);
762 return timer_id;
764 else
765 return -1;
768 // Locate and remove the single timer with a value of @a timer_id from
769 // the timer queue.
771 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
773 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::cancel (long timer_id,
774 const void **act,
775 int dont_call)
777 ACE_TRACE ("ACE_Timer_Heap_T::cancel");
778 ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, -1));
780 // Locate the ACE_Timer_Node that corresponds to the timer_id.
782 // Check to see if the timer_id is out of range
783 if (timer_id < 0
784 || (size_t) timer_id > this->max_size_)
785 return 0;
787 ssize_t timer_node_slot = this->timer_ids_[timer_id];
789 // Check to see if timer_id is still valid.
790 if (timer_node_slot < 0)
791 return 0;
793 if (timer_id != this->heap_[timer_node_slot]->get_timer_id ())
795 ACE_ASSERT (timer_id == this->heap_[timer_node_slot]->get_timer_id ());
796 return 0;
798 else
800 ACE_Timer_Node_T<TYPE> *temp =
801 this->remove (timer_node_slot);
803 // Call the close hooks.
804 int cookie = 0;
806 // cancel_type() called once per <type>.
807 this->upcall_functor ().cancel_type (*this,
808 temp->get_type (),
809 dont_call,
810 cookie);
812 // cancel_timer() called once per <timer>.
813 this->upcall_functor ().cancel_timer (*this,
814 temp->get_type (),
815 dont_call,
816 cookie);
818 if (act != 0)
819 *act = temp->get_act ();
821 this->free_node (temp);
822 return 1;
826 // Locate and update the inteval on the timer_id
828 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
830 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::reset_interval (long timer_id,
831 const ACE_Time_Value &interval)
833 ACE_TRACE ("ACE_Timer_Heap_T::reset_interval");
834 ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, -1));
836 // Locate the ACE_Timer_Node that corresponds to the timer_id.
838 // Check to see if the timer_id is out of range
839 if (timer_id < 0
840 || (size_t) timer_id > this->max_size_)
841 return -1;
843 ssize_t timer_node_slot = this->timer_ids_[timer_id];
845 // Check to see if timer_id is still valid.
846 if (timer_node_slot < 0)
847 return -1;
849 if (timer_id != this->heap_[timer_node_slot]->get_timer_id ())
851 ACE_ASSERT (timer_id == this->heap_[timer_node_slot]->get_timer_id ());
852 return -1;
854 else
856 // Reset the timer interval
857 this->heap_[timer_node_slot]->set_interval (interval);
858 return 0;
862 // Locate and remove all values of @a type from the timer queue.
864 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
866 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::cancel (const TYPE &type,
867 int dont_call)
869 ACE_TRACE ("ACE_Timer_Heap_T::cancel");
871 ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, -1));
873 int number_of_cancellations = 0;
875 // Try to locate the ACE_Timer_Node that matches the timer_id.
877 for (size_t i = 0; i < this->cur_size_; )
879 if (this->heap_[i]->get_type () == type)
881 ACE_Timer_Node_T<TYPE> *temp = this->remove (i);
883 ++number_of_cancellations;
885 this->free_node (temp);
887 // We reset to zero so that we don't miss checking any nodes
888 // if a reheapify occurs when a node is removed. There
889 // may be a better fix than this, however.
890 i = 0;
892 else
893 ++i;
896 // Call the close hooks.
897 int cookie = 0;
899 // cancel_type() called once per <type>.
900 this->upcall_functor ().cancel_type (*this,
901 type,
902 dont_call,
903 cookie);
905 for (int j = 0;
906 j < number_of_cancellations;
907 ++j)
909 // cancel_timer() called once per <timer>.
910 this->upcall_functor ().cancel_timer (*this,
911 type,
912 dont_call,
913 cookie);
916 return number_of_cancellations;
919 // Returns the earliest node or returns 0 if the heap is empty.
921 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
922 ACE_Timer_Node_T <TYPE> *
923 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::remove_first (void)
925 ACE_TRACE ("ACE_Timer_Heap_T::remove_first");
927 if (this->cur_size_ == 0)
928 return 0;
930 return this->remove (0);
933 template <class TYPE, class FUNCTOR, class ACE_LOCK, typename TIME_POLICY>
934 ACE_Timer_Node_T <TYPE> *
935 ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK, TIME_POLICY>::get_first (void)
937 ACE_TRACE ("ACE_Timer_Heap_T::get_first");
939 return this->cur_size_ == 0 ? 0 : this->heap_[0];
942 ACE_END_VERSIONED_NAMESPACE_DECL
944 #endif /* ACE_TIMER_HEAP_T_CPP */