gtimerlist.cpp
Go to the documentation of this file.
1 //
2 // Copyright (C) 2001-2013 Graeme Walker <graeme_walker@users.sourceforge.net>
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
16 // ===
17 //
18 // gtimerlist.cpp
19 //
20 
21 #include "gdef.h"
22 #include "gtimerlist.h"
23 #include "gtimer.h"
24 #include "geventloop.h"
25 #include "glog.h"
26 
27 GNet::TimerList * GNet::TimerList::m_this = NULL ;
28 
30  m_run_on_destruction(true) ,
31  m_list_changed(false) ,
32  m_empty_set_timeout_hint(false) ,
33  m_soonest_changed(true) ,
34  m_soonest(99U)
35 {
36  if( m_this == NULL )
37  m_this = this ;
38 }
39 
41 {
42  if( m_run_on_destruction )
43  {
44  try
45  {
46  doTimeouts() ;
47  }
48  catch(...)
49  {
50  }
51  }
52 
53  if( m_this == this )
54  m_this = NULL ;
55 }
56 
58 {
59  m_list_changed = true ;
60  m_list.push_back( &t ) ;
61 }
62 
64 {
65  for( List::iterator p = m_list.begin() ; p != m_list.end() ; ++p )
66  {
67  if( *p == &t )
68  {
69  *p = NULL ;
70  break ;
71  }
72  }
73 }
74 
76 {
77  // after any change in the soonest() time notify the event loop
78 
79  G::DateTime::EpochTime t_new = soonest() ;
80  if( t_old != t_new )
81  {
82  m_soonest_changed = true ;
83  if( EventLoop::exists() )
84  {
85  G_DEBUG( "GNet::TimerList::update: " << t_old << " -> " << t_new ) ;
86  EventLoop::instance().setTimeout( t_new , m_empty_set_timeout_hint ) ;
87  }
88  }
89 }
90 
91 void GNet::TimerList::update()
92 {
93  // this overload just assumes that the soonest() time has probably changed
94 
95  m_soonest_changed = true ;
96  if( EventLoop::exists() )
97  {
98  G::DateTime::EpochTime t_new = soonest() ;
99  G_DEBUG( "GNet::TimerList::update: ? -> " << t_new ) ;
100  EventLoop::instance().setTimeout( t_new , m_empty_set_timeout_hint ) ;
101  }
102 }
103 
105 {
106  G::DateTime::EpochTime result = 0U ;
107  const List::const_iterator end = m_list.end() ;
108  for( List::const_iterator p = m_list.begin() ; p != end ; ++p )
109  {
110  if( *p != NULL && (*p)->t() != 0UL && ( result == 0U || (*p)->t() < result ) )
111  result = (*p)->t() ;
112  }
113  return result ;
114 }
115 
117 {
118  // this optimised overload is for interval() which
119  // gets called on _every_ fd event
120 
121  if( m_soonest_changed )
122  {
123  TimerList * This = const_cast<TimerList*>(this) ;
124  This->m_soonest = soonest() ;
125  This->m_soonest_changed = false ;
126  }
127  //G_ASSERT( valid() ) ; // optimisation lost if this is active
128  return m_soonest ;
129 }
130 
131 bool GNet::TimerList::valid() const
132 {
133  if( soonest() != m_soonest )
134  {
135  G_ERROR( "GNet::TimerList::valid: soonest()=" << soonest() << ", m_soonest=" << m_soonest ) ;
136  return false ;
137  }
138  return true ;
139 }
140 
141 unsigned int GNet::TimerList::interval( bool & infinite ) const
142 {
143  G::DateTime::EpochTime then = soonest(0) ; // fast
144  infinite = then == 0U ;
145  if( infinite )
146  {
147  return 0U ;
148  }
149  else
150  {
152  return now >= then ? 0U : static_cast<unsigned int>(then-now) ;
153  }
154 }
155 
157 {
158  return m_this ;
159 }
160 
162 {
163  if( m_this == NULL )
164  throw NoInstance() ;
165 
166  return * m_this ;
167 }
168 
170 {
171  G_DEBUG( "GNet::TimerList::doTimeouts" ) ;
173 
174  for( List::iterator p = m_list.begin() ; p != m_list.end() ; ++p )
175  {
176  if( *p != NULL )
177  {
178  G::DateTime::EpochTime t = (*p)->t() ;
179  if( t != 0U && now >= t )
180  {
181  (*p)->doTimeout() ;
182  }
183  }
184  }
185 
186  // deal with any change in the soonest() time
187  update() ;
188 }
189 
190 void GNet::TimerList::collectGarbage()
191 {
192  for( List::iterator p = m_list.begin() ; p != m_list.end() ; )
193  {
194  if( *p == NULL )
195  p = m_list.erase( p ) ;
196  else
197  ++p ;
198  }
199 }
200 
static EpochTime now()
Returns the current epoch time.
Definition: gdatetime.cpp:34
void remove(AbstractTimer &)
Removes a timer from the list.
Definition: gtimerlist.cpp:63
void add(AbstractTimer &)
Adds a timer. Used by Timer::Timer().
Definition: gtimerlist.cpp:57
std::time_t EpochTime
Definition: gdatetime.h:41
void update(G::DateTime::EpochTime previous_soonest)
Called when one of the list's timers has changed.
Definition: gtimerlist.cpp:75
G::DateTime::EpochTime soonest() const
Returns the time of the first timer to expire, or zero if none.
Definition: gtimerlist.cpp:104
TimerList()
Default constructor.
Definition: gtimerlist.cpp:29
Overload discriminator class for TimerList.
Definition: gtimerlist.h:47
A singleton which maintains a list of all Timer objects, and interfaces to the event loop on their be...
Definition: gtimerlist.h:42
unsigned int interval(bool &infinite) const
Returns the interval to the next timer expiry.
Definition: gtimerlist.cpp:141
static TimerList & instance()
Singleton access. Throws an exception if none.
Definition: gtimerlist.cpp:161
#define G_ERROR(expr)
Definition: glog.h:108
virtual void setTimeout(G::DateTime::EpochTime t, bool &empty_implementation_hint)=0
Used by GNet::TimerList.
void doTimeouts()
Triggers the timeout callbacks of any expired timers.
Definition: gtimerlist.cpp:169
#define G_DEBUG(expr)
Definition: glog.h:95
~TimerList()
Destructor.
Definition: gtimerlist.cpp:40
static bool exists()
Returns true if an instance exists.
Definition: geventloop.cpp:51
static EventLoop & instance()
Returns a reference to an instance of the class, if any.
Definition: geventloop.cpp:43
A timer base class that calls a pure virtual method on expiry.
Definition: gtimer.h:41