E-MailRelay

geventhandlerlist.h
Go to the documentation of this file.
1//
2// Copyright (C) 2001-2021 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 geventhandlerlist.h
19///
20
21#ifndef G_NET_EVENT_HANDLER_LIST_H
22#define G_NET_EVENT_HANDLER_LIST_H
23
24#include "gdef.h"
25#include "geventhandler.h"
26#include "gexceptionsink.h"
27#include "gdescriptor.h"
28#include <vector>
29#include <string>
30
31 namespace GNet
32{
33 class EventHandlerList ;
34}
35
36//| \class GNet::EventHandlerList
37/// A class that maps from a file descriptor to an event handler and
38/// exception handler, used in the implemention of classes derived
39/// from GNet::EventLoop.
40///
41/// If an event handler is removed from the list while the list is
42/// being iterated over then the relevant pointer is reset without
43/// affecting the iteration. The unlock() method does garbage collection
44/// once the iteration is complete.
45///
46/// If an event handler is added to the list while the list is being
47/// iterated over then it is added to a pending-list. The pending
48/// list is added to the main list by unlock() once the iteration
49/// is complete.
50///
51/// Each event handler has an associated exception handler, typically a
52/// more long-lived object that has the event handler as a sub-object.
53/// If the event hander throws an exception then the event
54/// handler list catches it and invokes the exception handler -- and
55/// if that throws then the exception escapes the event loop. This is
56/// safe even if the exception handler object is destroyed by the
57/// original exception because the exception handler base-class
58/// destructor uses the list's disarm() mechanism. This is the same
59/// behaviour as in the TimerList.
60///
61/// Exception handlers are combined with an additional 'source' pointer
62/// in an ExceptionSink tuple. The exception source pointer can be used
63/// to provide additional information to the exception handler, typically
64/// as a pointer to the event handler object. (The EventHandler class
65/// is not used as the exception source type because timers also refer
66/// to exception sources and because of possible multiple inheritance of
67/// the EventHandler base.)
68///
69/// Note that the Descriptor class is actually in two parts for Windows:
70/// a socket handle (file descriptor) and an event-object handle. The
71/// event handler list is keyed by the full Descriptor object rather than
72/// just the socket handle and this allows it to contain event-handling
73/// objects that are not sockets. See GNet::FutureEvent.
74///
75 class GNet::EventHandlerList
76{
77 public:
78 struct Value /// A tuple for GNet::EventHandlerList.
79 {
80 Descriptor m_fd ;
81 EventHandler * m_event_handler ; // handler for the event
82 ExceptionSink m_es ; // handler for any thrown exception
83 explicit Value( Descriptor fd ) noexcept ;
84 Value( Descriptor fd , EventHandler * , ExceptionSink ) noexcept ;
85 } ;
86 struct Iterator /// An iterator for GNet::EventHandlerList.
87 {
88 using Value = EventHandlerList::Value ;
89 Iterator( const std::vector<Value> & , bool ) noexcept ;
90 Iterator( std::vector<Value>::const_iterator , std::vector<Value>::const_iterator ) noexcept ;
91 Iterator & operator++() noexcept ;
92 const Value & operator*() const noexcept ;
93 bool operator==( const Iterator & ) const noexcept ;
94 bool operator!=( const Iterator & ) const noexcept ;
95 Descriptor fd() const noexcept ;
96 EventHandler * handler() noexcept ;
97 ExceptionSink es() noexcept ;
98 void raiseEvent( void (EventHandler::*method)() ) ;
99 void raiseEvent( void (EventHandler::*method)(EventHandler::Reason) , EventHandler::Reason ) ;
100 std::vector<Value>::const_iterator m_p ;
101 std::vector<Value>::const_iterator m_end ;
102 } ;
103 struct Lock /// A RAII class to lock and unlock GNet::EventHandlerList.
104 {
105 explicit Lock( EventHandlerList & , bool * invalid_p = nullptr ) ;
106 ~Lock() ;
107 Lock( const Lock & ) = delete ;
108 Lock( Lock && ) = delete ;
109 void operator=( const Lock & ) = delete ;
110 void operator=( Lock && ) = delete ;
111 EventHandlerList & m_list ;
112 bool * m_invalid_p ;
113 } ;
114
115 public:
116 explicit EventHandlerList( const std::string & type ) ;
117 ///< Constructor. The type parameter (eg. "read") is used only in
118 ///< debugging messages.
119
120 void add( Descriptor fd , EventHandler * handler , ExceptionSink ) ;
121 ///< Adds a file-descriptor/handler tuple to the list.
122
123 void remove( Descriptor fd ) noexcept ;
124 ///< Removes a file-descriptor from the list. Does nothing if the
125 ///< file-descriptor is not in the list.
126
127 Iterator find( Descriptor fd ) const ;
128 ///< Finds an entry in the list. Returns end() if not found.
129 ///< This ignores any pending changes, ie. descriptors add()ed
130 ///< or remove()d while lock()ed.
131
132 bool contains( Descriptor fd ) const noexcept ;
133 ///< Returns true if the list, taking account of any pending
134 ///< changes, contains the given descriptor.
135
136 void lock() ;
137 ///< To be called at the start of an begin()/end() iteration if the
138 ///< list might change during the iteration. Must be paired with
139 ///< unlock().
140
141 bool unlock() ;
142 ///< Called at the end of a begin()/end() iteration to match a call
143 ///< to lock(). Does garbage collection. Returns true if anything
144 ///< might have changed.
145
146 Iterator begin() const noexcept ;
147 ///< Returns a forward iterator. If the list is lock()ed then the
148 ///< iterator will skip over descriptors that have been remove()d
149 ///< or add()ed while locked.
150
151 Iterator end() const noexcept ;
152 ///< Returns an end iterator.
153
154 void disarm( ExceptionHandler * ) noexcept ;
155 ///< Resets any matching ExceptionHandler pointers, so exceptions
156 ///< thrown out of the relevant file descriptors' event handlers
157 ///< are rethrown by this class rather than being delivered to
158 ///< the exception handler interface.
159
160 void getHandles( std::vector<HANDLE> & ) const ;
161 ///< Adds unique, non-zero Descriptor handles to the given
162 ///< sorted list, including any add()ed while lock()ed.
163
164 std::size_t size() const noexcept ;
165 ///< Returns the size of the list, ignoring any changes while
166 ///< lock()ed.
167
168public:
169 ~EventHandlerList() = default ;
170 EventHandlerList( const EventHandlerList & ) = delete ;
171 EventHandlerList( EventHandlerList && ) = delete ;
172 void operator=( const EventHandlerList & ) = delete ;
173 void operator=( EventHandlerList && ) = delete ;
174
175private:
176 using List = std::vector<Value> ;
177 static void addImp( List & list , Descriptor fd , EventHandler * , ExceptionSink ) ;
178 static bool disable( List & list , Descriptor fd ) noexcept ;
179 static bool remove( List & list , Descriptor fd ) noexcept ;
180 static void getHandles( const List & , std::vector<HANDLE> & ) ;
181 void disarm( List & , ExceptionHandler * ) noexcept ;
182 void commitPending() ;
183 void collectGarbage() ;
184
185private:
186 std::string m_type ;
187 List m_list ;
188 List m_pending_list ;
189 unsigned int m_lock ;
190 bool m_has_garbage ;
191} ;
192
193inline
194 GNet::EventHandlerList::Value::Value( Descriptor fd , EventHandler * event_handler , ExceptionSink es ) noexcept :
195 m_fd(fd),
196 m_event_handler(event_handler),
197 m_es(es)
198{
199}
200
201 inline
202GNet::EventHandlerList::Value::Value( Descriptor fd ) noexcept :
203 m_fd(fd),
204 m_event_handler(nullptr),
205 m_es(ExceptionSink(ExceptionSink::Type::Null))
206{
207}
208
209 inline
210 GNet::EventHandlerList::Iterator GNet::EventHandlerList::begin() const noexcept
211{
212 return Iterator( m_list , false ) ;
213}
214
215 inline
216 GNet::EventHandlerList::Iterator GNet::EventHandlerList::end() const noexcept
217{
218 return Iterator( m_list , true ) ;
219}
220
221 inline
222GNet::EventHandlerList::Iterator::Iterator( std::vector<Value>::const_iterator p ,
223 std::vector<Value>::const_iterator end ) noexcept :
224 m_p(p) ,
225 m_end(end)
226{
227}
228
229 inline
230GNet::EventHandlerList::Iterator::Iterator( const std::vector<Value> & v , bool end ) noexcept :
231 m_p(end?v.end():v.begin()) ,
232 m_end(v.end())
233{
234 while( m_p != m_end && (*m_p).m_event_handler == nullptr )
235 ++m_p ;
236}
237
238 inline
239 GNet::EventHandlerList::Iterator & GNet::EventHandlerList::Iterator::operator++() noexcept
240{
241 ++m_p ;
242 while( m_p != m_end && (*m_p).m_event_handler == nullptr )
243 ++m_p ;
244 return *this ;
245}
246
247 inline
248 const GNet::EventHandlerList::Value & GNet::EventHandlerList::Iterator::operator*() const noexcept
249{
250 return *m_p ;
251}
252
253 inline
254 GNet::Descriptor GNet::EventHandlerList::Iterator::fd() const noexcept
255{
256 return (*m_p).m_fd ;
257}
258
259 inline
260 GNet::EventHandler * GNet::EventHandlerList::Iterator::handler() noexcept
261{
262 return (*m_p).m_event_handler ;
263}
264
265 inline
266 GNet::ExceptionSink GNet::EventHandlerList::Iterator::es() noexcept
267{
268 return (*m_p).m_es ;
269}
270
271 inline
272 bool GNet::EventHandlerList::Iterator::operator==( const Iterator & other ) const noexcept
273{
274 return m_p == other.m_p ;
275}
276
277 inline
278 bool GNet::EventHandlerList::Iterator::operator!=( const Iterator & other ) const noexcept
279{
280 return !(*this == other) ;
281}
282
283#endif
GNet::Descriptor
A class that encapsulates a network socket file descriptor and an associated windows event handle.
Definition: gdescriptor.h:37
GNet::EventHandlerList
A class that maps from a file descriptor to an event handler and exception handler,...
Definition: geventhandlerlist.h:76
GNet::EventHandlerList::begin
Iterator begin() const noexcept
Returns a forward iterator.
Definition: geventhandlerlist.h:210
GNet::EventHandlerList::find
Iterator find(Descriptor fd) const
Finds an entry in the list.
Definition: geventhandlerlist.cpp:124
GNet::EventHandlerList::lock
void lock()
To be called at the start of an begin()/end() iteration if the list might change during the iteration...
Definition: geventhandlerlist.cpp:168
GNet::EventHandlerList::unlock
bool unlock()
Called at the end of a begin()/end() iteration to match a call to lock().
Definition: geventhandlerlist.cpp:173
GNet::EventHandlerList::size
std::size_t size() const noexcept
Returns the size of the list, ignoring any changes while lock()ed.
Definition: geventhandlerlist.cpp:143
GNet::EventHandlerList::EventHandlerList
EventHandlerList(const std::string &type)
Constructor.
Definition: geventhandlerlist.cpp:44
GNet::EventHandlerList::disarm
void disarm(ExceptionHandler *) noexcept
Resets any matching ExceptionHandler pointers, so exceptions thrown out of the relevant file descript...
Definition: geventhandlerlist.cpp:109
GNet::EventHandlerList::end
Iterator end() const noexcept
Returns an end iterator.
Definition: geventhandlerlist.h:216
GNet::EventHandlerList::contains
bool contains(Descriptor fd) const noexcept
Returns true if the list, taking account of any pending changes, contains the given descriptor.
Definition: geventhandlerlist.cpp:132
GNet::EventHandlerList::getHandles
void getHandles(std::vector< HANDLE > &) const
Adds unique, non-zero Descriptor handles to the given sorted list, including any add()ed while lock()...
Definition: geventhandlerlist.cpp:148
GNet::EventHandlerList::remove
void remove(Descriptor fd) noexcept
Removes a file-descriptor from the list.
Definition: geventhandlerlist.cpp:71
GNet::EventHandlerList::add
void add(Descriptor fd, EventHandler *handler, ExceptionSink)
Adds a file-descriptor/handler tuple to the list.
Definition: geventhandlerlist.cpp:51
GNet::EventHandler
A base class for classes that handle asynchronous events from the event loop.
Definition: geventhandler.h:48
GNet::ExceptionHandler
An abstract interface for handling exceptions thrown out of event-loop callbacks (socket/future event...
Definition: gexceptionhandler.h:44
GNet::ExceptionSink
A tuple containing an ExceptionHandler interface pointer and a bound 'exception source' pointer.
Definition: gexceptionsink.h:100
gdescriptor.h
geventhandler.h
gexceptionsink.h
GNet
Network classes.
Definition: gdef.h:1115
GNet::EventHandlerList::Iterator
An iterator for GNet::EventHandlerList.
Definition: geventhandlerlist.h:87
GNet::EventHandlerList::Lock
A RAII class to lock and unlock GNet::EventHandlerList.
Definition: geventhandlerlist.h:104
GNet::EventHandlerList::Value
A tuple for GNet::EventHandlerList.
Definition: geventhandlerlist.h:79