E-MailRelay
gtimerlist.h
Go to the documentation of this file.
1//
2// Copyright (C) 2001-2023 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/// \file gtimerlist.h
19///
20
21#ifndef G_NET_TIMER_LIST_H
22#define G_NET_TIMER_LIST_H
23
24#include "gdef.h"
25#include "gdatetime.h"
26#include "gtimer.h"
27#include "geventhandler.h"
28#include "gexception.h"
29#include "gexceptionsink.h"
30#include <utility>
31#include <vector>
32
33namespace GNet
34{
35 class TimerList ;
36 class TimerBase ;
37 class TimerListTest ;
38}
39
40//| \class GNet::TimerList
41/// A singleton which maintains a list of all Timer objects, and interfaces
42/// to the event loop on their behalf.
43///
44/// Event loops should call TimerList::interval() to determine how long to
45/// wait before the first Timer goes off. If the timed-wait times-out or
46/// if the interval was zero then they must call TimerList::doTimeouts().
47///
48/// There can be a race where this class incorrectly sees no expired timers
49/// in doTimeouts() if, for example, the system clock is being stretched.
50/// However, the interval() or setTimer() time will be very small and the
51/// race will resolve itself naturally.
52///
53/// Every timer has an associated exception handler, typically a
54/// more long-lived object that has the timer as a sub-object.
55/// If the timer callback throws an exception then timer list catches
56/// it and invokes the exception handler -- and if that throws then the
57/// exception escapes the event loop. This is safe even if the exception
58/// handler object is destroyed by the original exception because the
59/// exception handler base-class destructor uses the timer list's disarm()
60/// mechanism. This is the same behaviour as in the EventHandlerList.
61///
62/// Exception handlers are combined with an additional 'source' pointer
63/// in an ExceptionSink tuple. The source pointer can be used to
64/// provide additional information to the exception handler, typically
65/// as a pointer to the event handler (sic) object.
66///
67/// The implementation maintains a pointer to the timer that will
68/// expire soonest so that interval() is fast and O(1) when the set
69/// of timers is stable and most events are non-timer events.
70///
71/// Zero-length timers expire in the same order as they were started,
72/// which allows them to be used as a mechanism for asynchronous
73/// message-passing.
74///
76{
77public:
78 G_EXCEPTION( NoInstance , tx("no TimerList instance") ) ;
79
80 TimerList() ;
81 ///< Default constructor.
82
83 ~TimerList() ;
84 ///< Destructor.
85
86 void add( TimerBase & , ExceptionSink ) ;
87 ///< Adds a timer. Called from the Timer constructor.
88
89 void remove( TimerBase & ) noexcept ;
90 ///< Removes a timer from the list. Called from the
91 ///< Timer destructor.
92
93 void updateOnStart( TimerBase & ) ;
94 ///< Called by Timer when a timer is started.
95
96 void updateOnCancel( TimerBase & ) ;
97 ///< Called by Timer when a timer is cancelled.
98
99 std::pair<G::TimeInterval,bool> interval() const ;
100 ///< Returns the interval to the first timer expiry. The second
101 ///< part is an 'infinite' flag that is set if there are no
102 ///< timers running. In pathological cases the interval
103 ///< will be capped at the type's maximum value.
104
105 void doTimeouts() ;
106 ///< Triggers the timeout callbacks of any expired timers.
107 ///< Called by the event loop (GNet::EventLoop). Any exception
108 ///< thrown out of an expired timer's callback is caught and
109 ///< delivered back to the ExceptionSink associated with
110 ///< the timer.
111
112 static bool exists() ;
113 ///< Returns true if instance() exists.
114
115 static TimerList * ptr() noexcept ;
116 ///< Singleton access. Returns nullptr if none.
117
118 static TimerList & instance() ;
119 ///< Singleton access. Throws an exception if none.
120
121 void disarm( ExceptionHandler * ) noexcept ;
122 ///< Resets any matching ExceptionHandler pointers.
123
124public:
125 TimerList( const TimerList & ) = delete ;
126 TimerList( TimerList && ) = delete ;
127 TimerList & operator=( const TimerList & ) = delete ;
128 TimerList & operator=( TimerList && ) = delete ;
129
130private:
131 struct Value /// A value type for the GNet::TimerList.
132 {
133 TimerBase * m_timer{nullptr} ; // handler for the timeout event
134 ExceptionSink m_es ; // handler for any exception thrown
135 Value() ; // for uclibc++ std::vector
136 Value( TimerBase * t , ExceptionSink es ) ;
137 bool operator==( const Value & v ) const noexcept ;
138 void resetIf( TimerBase * p ) noexcept ;
139 void disarmIf( ExceptionHandler * eh ) noexcept ;
140 } ;
141 using List = std::vector<Value> ;
142 struct Lock /// A RAII class to lock and unlock GNet::TimerList.
143 {
144 explicit Lock( TimerList & ) ;
145 ~Lock() ;
146 Lock( const Lock & ) = delete ;
147 Lock( Lock && ) = delete ;
148 Lock & operator=( const Lock & ) = delete ;
149 Lock & operator=( Lock && ) = delete ;
150 TimerList & m_timer_list ;
151 } ;
152 friend class GNet::TimerListTest ;
153 friend struct Lock ;
154
155private:
156 const TimerBase * findSoonest() const ;
157 void lock() ;
158 void unlock() ;
159 void purgeRemoved() ;
160 void mergeAdded() ;
161 void doTimeout( Value & ) ;
162 static void removeFrom( List & , TimerBase * ) noexcept ;
163 static void disarmIn( List & , ExceptionHandler * ) noexcept ;
164
165private:
166 static TimerList * m_this ;
167 mutable const TimerBase * m_soonest{nullptr} ;
168 unsigned int m_adjust{0} ;
169 bool m_locked{false} ;
170 bool m_removed{false} ;
171 List m_list ;
172 List m_list_added ; // temporary list for when add()ed from within doTimeouts()
173} ;
174
175#endif
An abstract interface for handling exceptions thrown out of event-loop callbacks (socket/future event...
A tuple containing an ExceptionHandler interface pointer and a bound 'exception source' pointer.
An interface used by GNet::TimerList to keep track of pending timeouts and to deliver timeout events.
Definition: gtimer.h:42
A singleton which maintains a list of all Timer objects, and interfaces to the event loop on their be...
Definition: gtimerlist.h:76
std::pair< G::TimeInterval, bool > interval() const
Returns the interval to the first timer expiry.
Definition: gtimerlist.cpp:152
void remove(TimerBase &) noexcept
Removes a timer from the list.
Definition: gtimerlist.cpp:95
void doTimeouts()
Triggers the timeout callbacks of any expired timers.
Definition: gtimerlist.cpp:226
static bool exists()
Returns true if instance() exists.
Definition: gtimerlist.cpp:179
void disarm(ExceptionHandler *) noexcept
Resets any matching ExceptionHandler pointers.
Definition: gtimerlist.cpp:109
void updateOnStart(TimerBase &)
Called by Timer when a timer is started.
Definition: gtimerlist.cpp:121
static TimerList & instance()
Singleton access. Throws an exception if none.
Definition: gtimerlist.cpp:185
static TimerList * ptr() noexcept
Singleton access. Returns nullptr if none.
Definition: gtimerlist.cpp:173
TimerList()
Default constructor.
Definition: gtimerlist.cpp:78
void updateOnCancel(TimerBase &)
Called by Timer when a timer is cancelled.
Definition: gtimerlist.cpp:133
~TimerList()
Destructor.
Definition: gtimerlist.cpp:84
void add(TimerBase &, ExceptionSink)
Adds a timer. Called from the Timer constructor.
Definition: gtimerlist.cpp:90
Network classes.
Definition: gdef.h:1144
constexpr const char * tx(const char *p)
A briefer alternative to G::gettext_noop().
Definition: ggettext.h:84