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
31namespace 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///
76{
77public:
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 {
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
115public:
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
194GNet::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
201inline
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
209inline
211{
212 return Iterator( m_list , false ) ;
213}
214
215inline
217{
218 return Iterator( m_list , true ) ;
219}
220
221inline
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
229inline
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
238inline
239GNet::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
247inline
248const GNet::EventHandlerList::Value & GNet::EventHandlerList::Iterator::operator*() const noexcept
249{
250 return *m_p ;
251}
252
253inline
254GNet::Descriptor GNet::EventHandlerList::Iterator::fd() const noexcept
255{
256 return (*m_p).m_fd ;
257}
258
259inline
260GNet::EventHandler * GNet::EventHandlerList::Iterator::handler() noexcept
261{
262 return (*m_p).m_event_handler ;
263}
264
265inline
266GNet::ExceptionSink GNet::EventHandlerList::Iterator::es() noexcept
267{
268 return (*m_p).m_es ;
269}
270
271inline
272bool GNet::EventHandlerList::Iterator::operator==( const Iterator & other ) const noexcept
273{
274 return m_p == other.m_p ;
275}
276
277inline
278bool GNet::EventHandlerList::Iterator::operator!=( const Iterator & other ) const noexcept
279{
280 return !(*this == other) ;
281}
282
283#endif
A class that encapsulates a network socket file descriptor and an associated windows event handle.
Definition: gdescriptor.h:37
A class that maps from a file descriptor to an event handler and exception handler,...
Iterator begin() const noexcept
Returns a forward iterator.
Iterator find(Descriptor fd) const
Finds an entry in the list.
void lock()
To be called at the start of an begin()/end() iteration if the list might change during the iteration...
bool unlock()
Called at the end of a begin()/end() iteration to match a call to lock().
std::size_t size() const noexcept
Returns the size of the list, ignoring any changes while lock()ed.
EventHandlerList(const std::string &type)
Constructor.
void disarm(ExceptionHandler *) noexcept
Resets any matching ExceptionHandler pointers, so exceptions thrown out of the relevant file descript...
Iterator end() const noexcept
Returns an end iterator.
bool contains(Descriptor fd) const noexcept
Returns true if the list, taking account of any pending changes, contains the given descriptor.
void getHandles(std::vector< HANDLE > &) const
Adds unique, non-zero Descriptor handles to the given sorted list, including any add()ed while lock()...
void remove(Descriptor fd) noexcept
Removes a file-descriptor from the list.
void add(Descriptor fd, EventHandler *handler, ExceptionSink)
Adds a file-descriptor/handler tuple to the list.
A base class for classes that handle asynchronous events from the event loop.
Definition: geventhandler.h:48
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.
Network classes.
Definition: gdef.h:1115
An iterator for GNet::EventHandlerList.
A RAII class to lock and unlock GNet::EventHandlerList.
A tuple for GNet::EventHandlerList.