E-MailRelay

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

gtimerlist.cpp
Go to the documentation of this file.
1 //
2 // Copyright (C) 2001-2018 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 #include "gassert.h"
27 #include <algorithm>
28 #include <sstream>
29
30 GNet::TimerList * GNet::TimerList::m_this = nullptr ;
31
32 GNet::TimerList::TimerList() :
33 m_soonest(nullptr)
34 {
35 if( m_this == nullptr )
36 m_this = this ;
37 }
38
39 GNet::TimerList::~TimerList()
40 {
41 if( m_this == this )
42 m_this = nullptr ;
43 }
44
45 void GNet::TimerList::add( TimerBase & t , ExceptionHandler & eh )
46 {
47 G_ASSERT( !t.active() ) ; // (called by ctor)
48 m_list.push_back( Value(&t,&eh) ) ;
49 }
50
51 void GNet::TimerList::remove( TimerBase & timer )
52 {
53 const List::iterator end = m_list.end() ;
54 for( List::iterator p = m_list.begin() ; p != end ; ++p )
55 {
56 if( (*p).first == &timer )
57 (*p).first = nullptr ;
58 }
59
60 if( m_soonest == &timer )
61 {
62 m_soonest = findSoonest() ;
63 setTimeout() ;
64 }
65 }
66
67 void GNet::TimerList::disarm( ExceptionHandler * eh )
68 {
69 const List::iterator end = m_list.end() ;
70 for( List::iterator p = m_list.begin() ; p != end ; ++p )
71 {
72 if( (*p).second == eh )
73 (*p).second = nullptr ;
74 }
75 }
76
77 void GNet::TimerList::update( TimerBase & timer )
78 {
79 if( !timer.active() && m_soonest != &timer )
80 {
81 ; // no-op -- cancelled a non-soonest timer
82 }
83 else if( timer.active() && m_soonest != nullptr && timer.t() > m_soonest->t() )
84 {
85 ; // no-op -- started a non-soonest timer
86 }
87 else
88 {
89 G::EpochTime old_soonest = soonestTime() ;
90 m_soonest = (timer.active() && timer.immediate()) ? &timer : findSoonest() ;
91 if( soonestTime() != old_soonest )
92 setTimeout() ;
93 }
94 }
95
96 G::EpochTime GNet::TimerList::soonestTime() const
97 {
98 return m_soonest == nullptr ? G::EpochTime(0) : m_soonest->t() ;
99 }
100
101 GNet::TimerBase * GNet::TimerList::findSoonest()
102 {
103 // (we could keep the list sorted to make this O(1), but keep it simple for now)
104 TimerBase * result = nullptr ;
105 const List::const_iterator end = m_list.end() ;
106 for( List::const_iterator p = m_list.begin() ; p != end ; ++p )
107 {
108 if( (*p).first != nullptr && (*p).first->active() && ( result == nullptr || (*p).first->t() < result->t() ) )
109 result = (*p).first ;
110 }
111 return result ;
112 }
113
114 G::EpochTime GNet::TimerList::interval( bool & infinite ) const
115 {
116 if( m_soonest == nullptr )
117 {
118 infinite = true ;
119 return G::EpochTime(0) ;
120 }
121 else if( m_soonest->immediate() )
122 {
123 infinite = false ;
124 return G::EpochTime(0) ;
125 }
126 else
127 {
128 infinite = false ;
129 G::EpochTime now = G::DateTime::now() ;
130 G::EpochTime then = m_soonest->t() ;
131 return now >= then ? G::EpochTime(0) : (then-now) ;
132 }
133 }
134
135 GNet::TimerList * GNet::TimerList::instance( const NoThrow & )
136 {
137 return m_this ;
138 }
139
140 bool GNet::TimerList::exists()
141 {
142 return m_this != nullptr ;
143 }
144
145 GNet::TimerList & GNet::TimerList::instance()
146 {
147 if( m_this == nullptr )
148 throw NoInstance() ;
149 return * m_this ;
150 }
151
152 void GNet::TimerList::doTimeouts()
153 {
154 G::EpochTime now( 0 ) ; // lazy initialisation to G::DateTime::now() in G::Timer::expired()
155 for( List::iterator p = m_list.begin() ; p != m_list.end() ; ++p )
156 {
157 if( (*p).first != nullptr && (*p).first->active() && (*p).first->expired(now) )
158 {
159 try
160 {
161 (*p).first->doTimeout() ;
162 }
163 catch( std::exception & e )
164 {
165 if( (*p).second )
166 (*p).second->onException( e ) ;
167 }
168 }
169 }
170
171 collectGarbage() ;
172
173 m_soonest = findSoonest() ;
174 setTimeout() ;
175 }
176
177 void GNet::TimerList::setTimeout()
178 {
179 if( EventLoop::exists() )
180 EventLoop::instance().setTimeout( soonestTime() ) ;
181 }
182
183 void GNet::TimerList::collectGarbage()
184 {
185 for( List::iterator p = m_list.begin() ; p != m_list.end() ; )
186 {
187 if( (*p).first == nullptr )
188 p = m_list.erase( p ) ;
189 else
190 ++p ;
191 }
192 }
193
194 std::string GNet::TimerList::report() const
195 {
196 std::ostringstream ss ;
197 ss << m_list.size() ;
198 return ss.str() ;
199 }
200
201 /// \file gtimerlist.cpp
G::EpochTime
A subsecond-resolution timestamp based on a time_t.
Definition: gdatetime.h:39
GNet::EventLoop::setTimeout
virtual void setTimeout(G::EpochTime t)=0
Used by GNet::TimerList.
glog.h
gtimerlist.h
GNet::TimerBase::t
G::EpochTime t() const
Used by TimerList to get the expiry epoch time.
Definition: gtimer.cpp:97
GNet::TimerBase::active
bool active() const
Returns true if the timer is started and not cancelled.
Definition: gtimer.h:90
GNet::TimerList::TimerList
TimerList()
Default constructor.
Definition: gtimerlist.cpp:32
GNet::TimerList::NoThrow
Overload discriminator class for TimerList.
Definition: gtimerlist.h:65
GNet::TimerList
A singleton which maintains a list of all Timer objects, and interfaces to the event loop on their be...
Definition: gtimerlist.h:61
geventloop.h
GNet::TimerList::add
void add(TimerBase &, ExceptionHandler &)
Adds a timer.
Definition: gtimerlist.cpp:45
G::DateTime::now
static EpochTime now()
Returns the current epoch time.
Definition: gdatetime_unix.cpp:26
GNet::ExceptionHandler
An abstract interface for handling exceptions thrown out of event-loop callbacks (socket events...
Definition: gexceptionhandler.h:44
GNet::TimerList::instance
static TimerList & instance()
Singleton access. Throws an exception if none.
Definition: gtimerlist.cpp:145
GNet::TimerList::interval
G::EpochTime interval(bool &infinite) const
Returns the interval to the first timer expiry.
Definition: gtimerlist.cpp:114
gassert.h
gtimer.h
GNet::TimerList::doTimeouts
void doTimeouts()
Triggers the timeout callbacks of any expired timers.
Definition: gtimerlist.cpp:152
GNet::TimerList::exists
static bool exists()
Returns true if instance() exists.
Definition: gtimerlist.cpp:140
GNet::TimerList::~TimerList
~TimerList()
Destructor. Any expired timers have their timeouts called.
Definition: gtimerlist.cpp:39
GNet::TimerList::update
void update(TimerBase &)
Called when a timer changes its value.
Definition: gtimerlist.cpp:77
GNet::TimerBase
An interface used by GNet::TimerList to keep track of pending timeouts and to deliver timeout events...
Definition: gtimer.h:40
GNet::TimerBase::immediate
bool immediate() const
Used by TimerList.
Definition: gtimer.cpp:45
GNet::EventLoop::exists
static bool exists()
Returns true if an instance exists.
Definition: geventloop.cpp:50
GNet::TimerList::disarm
void disarm(ExceptionHandler *)
Resets any matching ExceptionHandler pointers.
Definition: gtimerlist.cpp:67
GNet::TimerList::remove
void remove(TimerBase &)
Removes a timer from the list.
Definition: gtimerlist.cpp:51
GNet::TimerList::report
std::string report() const
Returns a line of text reporting the status of the timer list.
Definition: gtimerlist.cpp:194
GNet::EventLoop::instance
static EventLoop & instance()
Returns a reference to an instance of the class, if any.
Definition: geventloop.cpp:42