// -*- c++ -*- //------------------------------------------------------------------------------ // TimerQueue.cpp //------------------------------------------------------------------------------ // Copyright (c) 2000,2005 by Vladislav Grinchenko // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Library General Public // License as published by the Free Software Foundation; either // version 2 of the License, or (at your option) any later version. // //------------------------------------------------------------------------------ // Created: 07/28/99 //------------------------------------------------------------------------------ #include "assa/TimerQueue.h" using namespace ASSA; TimerQueue:: ~TimerQueue () { trace_with_mask("TimerQueue::~TimerQueue",REACTTRACE); while (m_queue.size ()) { delete m_queue.pop (); } } int TimerQueue:: remove (EventHandler* eh_) { // Like STL iterators, after deletion of an element, // queue structure and indexing might drastically change // and there is no guarantee that elements we haven't seen // yet will not be moved past the iterator. Therefore, // we must start scanning from the beginning after each deletion :-( trace_with_mask("TimerQueue::remove(eh_)",REACTTRACE); register size_t i; int cnt = 0; bool f = true; // changed flag register Timer* tmr; DL((REACT,"Searching for Timer: 0x%x\n", dynamic_cast (eh_))); while (f) { f = false; DL((REACT,"Queue size: %d\n", m_queue.size())); for (i = 0; i < m_queue.size (); i++) { if (m_queue[i]->getHandler() == eh_) { DL((REACT,"Found Timer: 0x%x in slot: %d\n", dynamic_cast(eh_), i)); tmr = m_queue[i]; m_queue.remove (tmr); delete tmr; cnt++; f = true; } } } return cnt; } bool TimerQueue:: remove (TimerId tid_) { trace_with_mask("TimerQueue::remove(tid)",REACTTRACE); register size_t i; DL((REACTTRACE,"Queue size before remove: %d\n", m_queue.size())); for (i = 0; i < m_queue.size (); i++) { if (m_queue[i] == (Timer*) tid_) { Timer* tmr = m_queue[i]; int ret = m_queue.remove (tmr); delete tmr; DL((REACTTRACE,"Queue size after remove: %d\n", m_queue.size())); return ret; } } return false; } int TimerQueue:: expire (const TimeVal& tv_) { trace_with_mask("TimerQueue::expire",REACTTRACE); register Timer* tp = (Timer*) NULL; register int cnt = 0; while (m_queue.size () && (tp = m_queue.top ()) != (Timer*) NULL) { if (tp->getExpirationTime () > tv_) { DL((REACT,"Top timer:\n")); tp->dump (); break; } /* First, pop item from the queue. Then call an appropriate EventHandler. If done in reverse, EventHandler might remove item first and then pop () will fail (This needs more investigation!). */ m_queue.pop (); DL((REACT,"Expired %s [t=%s] timer!\n", tp->get_id ().c_str (), tp->getExpirationTime ().fmtString ().c_str ())); int ret = tp->getHandler ()->handle_timeout ((TimerId) tp); /** Reschedule without deleting the Timer object so that application-level code can still hold to the valid TimerId. */ if (ret == 1) { tp->rescheduleExpirationTime (); m_queue.insert (tp); } else { delete tp; tp = (Timer*)NULL; } cnt++; } if (cnt) { DL((TRACE,"Expired total of %d timer(s).\n",cnt)); } return cnt; } TimerId TimerQueue:: insert (EventHandler* eh_, const TimeVal& tv_, const TimeVal& delta_, const std::string& name_) { trace("TimerQueue::insert"); Timer* t = new Timer (eh_, tv_, delta_, name_); m_queue.insert (t); return (TimerId) t; } void TimerQueue:: dump (void) { trace("TimerQueue::dump"); if (m_queue.size() == 0) { DL((REACT,"Queue is empty\n")); } else { for (size_t i = 0; i < m_queue.size (); ) { m_queue[i++]->dump(); } } }