1 // -*- c++ -*-
2 //------------------------------------------------------------------------------
3 //                            TimerQueue.cpp
4 //------------------------------------------------------------------------------
5 //  Copyright (c) 2000,2005 by Vladislav Grinchenko
6 //
7 //  This library is free software; you can redistribute it and/or
8 //  modify it under the terms of the GNU Library General Public
9 //  License as published by the Free Software Foundation; either
10 //  version 2 of the License, or (at your option) any later version.
11 //
12 //------------------------------------------------------------------------------
13 //  Created: 07/28/99
14 //------------------------------------------------------------------------------
15 
16 #include "assa/TimerQueue.h"
17 using namespace ASSA;
18 
19 TimerQueue::
~TimerQueue()20 ~TimerQueue ()
21 {
22     trace_with_mask("TimerQueue::~TimerQueue",REACTTRACE);
23 
24     while (m_queue.size ()) {
25 		delete m_queue.pop ();
26     }
27 }
28 
29 int
30 TimerQueue::
remove(EventHandler * eh_)31 remove (EventHandler* eh_)
32 {
33     // Like STL iterators, after deletion of an element,
34     // queue structure and indexing might drastically change
35     // and there is no guarantee that elements we haven't seen
36     // yet will not be moved past the iterator. Therefore,
37     // we must start scanning from the beginning after each deletion :-(
38 
39     trace_with_mask("TimerQueue::remove(eh_)",REACTTRACE);
40 
41     register size_t i;
42     int cnt = 0;
43     bool f = true;		// changed flag
44     register Timer* tmr;
45 
46     DL((REACT,"Searching for Timer: 0x%x\n", dynamic_cast<void*> (eh_)));
47 
48     while (f) {
49 		f = false;
50 		DL((REACT,"Queue size: %d\n", m_queue.size()));
51 		for (i = 0; i < m_queue.size (); i++) {
52 			if (m_queue[i]->getHandler() == eh_) {
53 				DL((REACT,"Found Timer: 0x%x in slot: %d\n",
54 					dynamic_cast<void*>(eh_), i));
55 				tmr = m_queue[i];
56 				m_queue.remove (tmr);
57 				delete tmr;
58 				cnt++;
59 				f = true;
60 			}
61 		}
62     }
63     return cnt;
64 }
65 
66 bool
67 TimerQueue::
remove(TimerId tid_)68 remove (TimerId tid_)
69 {
70     trace_with_mask("TimerQueue::remove(tid)",REACTTRACE);
71     register size_t i;
72 
73     DL((REACTTRACE,"Queue size before remove: %d\n", m_queue.size()));
74 
75     for (i = 0; i < m_queue.size (); i++) {
76 		if (m_queue[i] == (Timer*) tid_) {
77 			Timer* tmr = m_queue[i];
78 			int ret = m_queue.remove (tmr);
79 			delete tmr;
80 			DL((REACTTRACE,"Queue size after remove: %d\n", m_queue.size()));
81 			return ret;
82 		}
83     }
84     return false;
85 }
86 
87 int
88 TimerQueue::
expire(const TimeVal & tv_)89 expire (const TimeVal& tv_)
90 {
91     trace_with_mask("TimerQueue::expire",REACTTRACE);
92 
93     register Timer* tp = (Timer*) NULL;
94     register int cnt = 0;
95 
96     while (m_queue.size () && (tp = m_queue.top ()) != (Timer*) NULL) {
97 		if (tp->getExpirationTime () > tv_) {
98 			DL((REACT,"Top timer:\n"));
99 			tp->dump ();
100 			break;
101 		}
102 		/* First, pop item from the queue. Then call an appropriate
103 		   EventHandler. If done in reverse, EventHandler might
104 		   remove item first and then pop () will fail
105 		   (This needs more investigation!).
106 		*/
107 		m_queue.pop ();
108 
109 		DL((REACT,"Expired %s [t=%s] timer!\n",
110 			tp->get_id ().c_str (),
111 			tp->getExpirationTime ().fmtString ().c_str ()));
112 
113 		int ret = tp->getHandler ()->handle_timeout ((TimerId) tp);
114 
115 		/** Reschedule without deleting the Timer object so that
116 			application-level code can still hold to the valid TimerId.
117 		*/
118 		if (ret == 1) {
119 			tp->rescheduleExpirationTime ();
120 			m_queue.insert (tp);
121 		}
122 		else {
123 			delete tp;
124 			tp = (Timer*)NULL;
125 		}
126 		cnt++;
127     }
128 
129     if (cnt) {
130 		DL((TRACE,"Expired total of %d timer(s).\n",cnt));
131     }
132 
133     return cnt;
134 }
135 
136 TimerId
137 TimerQueue::
insert(EventHandler * eh_,const TimeVal & tv_,const TimeVal & delta_,const std::string & name_)138 insert (EventHandler*      eh_,
139 		const TimeVal&     tv_,
140 		const TimeVal&     delta_,
141 		const std::string& name_)
142 {
143 	trace("TimerQueue::insert");
144 
145 	Timer* t = new Timer (eh_, tv_, delta_, name_);
146 	m_queue.insert (t);
147 	return (TimerId) t;
148 }
149 
150 void
151 TimerQueue::
dump(void)152 dump (void)
153 {
154 	trace("TimerQueue::dump");
155 
156 	if (m_queue.size() == 0) {
157 		DL((REACT,"Queue is empty\n"));
158 	}
159 	else {
160 		for (size_t i = 0; i < m_queue.size (); ) {
161 			m_queue[i++]->dump();
162 		}
163 	}
164 }
165