E-MailRelay

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

geventhandlerlist.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 // geventhandlerlist.cpp
19 //
20
21 #include "gdef.h"
22 #include "geventhandlerlist.h"
23 #include "gdebug.h"
24 #include <algorithm>
25
26 namespace
27 {
28 struct fdless
29 {
30 typedef GNet::EventHandlerList::Value Value ;
31 bool operator()( const Value & p1 , const Value & p2 )
32 {
33 return p1.first < p2.first ;
34 }
35 } ;
36 }
37
38 GNet::EventHandlerList::EventHandlerList( const std::string & type ) :
39 m_type(type) ,
40 m_lock(0U) ,
41 m_has_garbage(false)
42 {
43 }
44
45 void GNet::EventHandlerList::add( Descriptor fd , EventHandler * handler , ExceptionHandler * eh )
46 {
47 G_ASSERT( handler != nullptr ) ; if( handler == nullptr ) return ;
48 G_ASSERT( eh != nullptr ) ; if( eh == nullptr ) return ;
49
50 G_DEBUG( "GNet::EventHandlerList::add: " << m_type << "-list: " << "adding " << fd << (m_lock?" (pending)":"") ) ;
51 addImp( m_lock?m_pending_list:m_list , fd , handler , eh ) ;
52 }
53
54 void GNet::EventHandlerList::addImp( List & list , Descriptor fd , EventHandler * handler , ExceptionHandler * eh )
55 {
56 typedef std::pair<List::iterator,List::iterator> Range ;
57 Range range = std::equal_range( list.begin() , list.end() , List::value_type(fd) , fdless() ) ;
58 if( range.first == range.second )
59 list.insert( range.first , List::value_type(fd,handler,eh) ) ;
60 else
61 *range.first = List::value_type(fd,handler,eh) ;
62 }
63
64 void GNet::EventHandlerList::remove( Descriptor fd )
65 {
66 G_DEBUG( "GNet::EventHandlerList::remove: " << m_type << "-list: " << "removing " << fd ) ;
67 if( m_lock )
68 {
69 if( disable(m_list,fd) ) m_has_garbage = true ;
70 disable( m_pending_list , fd ) ;
71 }
72 else
73 {
74 remove( m_list , fd ) ;
75 }
76 }
77
78 bool GNet::EventHandlerList::disable( List & list , Descriptor fd )
79 {
80 typedef std::pair<List::iterator,List::iterator> Range ;
81 Range range = std::equal_range( list.begin() , list.end() , List::value_type(fd) , fdless() ) ;
82 const bool found = range.first != range.second ;
83 if( found )
84 {
85 (*range.first).second = nullptr ;
86 }
87 return found ;
88 }
89
90 bool GNet::EventHandlerList::remove( List & list , Descriptor fd )
91 {
92 typedef std::pair<List::iterator,List::iterator> Range ;
93 Range range = std::equal_range( list.begin() , list.end() , List::value_type(fd) , fdless() ) ;
94 const bool found = range.first != range.second ;
95 if( found )
96 list.erase( range.first ) ;
97 return found ;
98 }
99
100 void GNet::EventHandlerList::disarm( ExceptionHandler * eh )
101 {
102 disarm( m_list , eh ) ;
103 disarm( m_pending_list , eh ) ;
104 }
105
106 void GNet::EventHandlerList::disarm( List & list , ExceptionHandler * eh )
107 {
108 for( List::iterator p = list.begin() ; p != list.end() ; ++p )
109 {
110 if( (*p).third == eh )
111 (*p).third = nullptr ;
112 }
113 }
114
115 GNet::EventHandlerList::Iterator GNet::EventHandlerList::find( Descriptor fd ) const
116 {
117 typedef std::pair<List::const_iterator,List::const_iterator> Range ;
118 Range range = std::equal_range( m_list.begin() , m_list.end() , List::value_type(fd) , fdless() ) ;
119 return range.first == range.second ? Iterator(m_list.end(),m_list.end()) : Iterator(range.first,m_list.end()) ;
120 }
121
122 bool GNet::EventHandlerList::contains( Descriptor fd ) const
123 {
124 typedef std::pair<List::const_iterator,List::const_iterator> Range ;
125 Range range = std::equal_range( m_pending_list.begin() , m_pending_list.end() , List::value_type(fd) , fdless() ) ;
126 if( range.first == range.second )
127 range = std::equal_range( m_list.begin() , m_list.end() , List::value_type(fd) , fdless() ) ;
128 return range.first != range.second && (*range.first).second != nullptr ;
129 }
130
131 void GNet::EventHandlerList::lock()
132 {
133 m_lock++ ;
134 }
135
136 bool GNet::EventHandlerList::unlock()
137 {
138 G_ASSERT( m_lock != 0U ) ;
139 m_lock-- ;
140 bool updated = false ;
141 if( m_lock == 0U )
142 {
143 updated = !m_pending_list.empty() || m_has_garbage ;
144 commitPending() ;
145 collectGarbage() ;
146 }
147 return updated ;
148 }
149
150 void GNet::EventHandlerList::commitPending()
151 {
152 const List::iterator end = m_pending_list.end() ;
153 for( List::iterator p = m_pending_list.begin() ; p != end ; ++p )
154 {
155 if( (*p).second != nullptr )
156 {
157 G_DEBUG( "GNet::EventHandlerList::commitPending: " << m_type << "-list: " << "commiting " << (*p).first ) ;
158 addImp( m_list , (*p).first , (*p).second , (*p).third ) ;
159 }
160 }
161 m_pending_list.clear() ;
162 }
163
164 void GNet::EventHandlerList::collectGarbage()
165 {
166 if( m_has_garbage )
167 {
168 m_has_garbage = false ;
169 for( List::iterator p = m_list.begin() ; p != m_list.end() ; )
170 {
171 if( (*p).second == nullptr )
172 p = m_list.erase( p ) ;
173 else
174 ++p ;
175 }
176 }
177 }
178
179 // ==
180
181 void GNet::EventHandlerList::Iterator::raiseEvent( void (EventHandler::*method)() )
182 {
183 try
184 {
185 if( m_p != m_end && handler() != nullptr )
186 (handler()->*method)() ;
187 }
188 catch( std::exception & e )
189 {
190 if( m_p != m_end && eh() != nullptr )
191 eh()->onException( e ) ;
192 else
193 throw ;
194 }
195 }
196
197 void GNet::EventHandlerList::Iterator::raiseEvent( void (EventHandler::*method)(EventHandler::Reason) , EventHandler::Reason reason )
198 {
199 try
200 {
201 if( m_p != m_end && handler() != nullptr )
202 (handler()->*method)( reason ) ;
203 }
204 catch( std::exception & e )
205 {
206 if( m_p != m_end && eh() != nullptr )
207 eh()->onException( e ) ;
208 else
209 throw ;
210 }
211 }
212
213 // ==
214
215 GNet::EventHandlerList::Lock::Lock( EventHandlerList & list , bool * invalid_p ) :
216 m_list(list) ,
217 m_invalid_p(invalid_p)
218 {
219 m_list.lock() ;
220 }
221
222 GNet::EventHandlerList::Lock::~Lock()
223 {
224 if( m_list.unlock() && m_invalid_p != nullptr )
225 *m_invalid_p = true ;
226 }
227
228 /// \file geventhandlerlist.cpp
GNet::EventHandlerList::find
Iterator find(Descriptor fd) const
Finds an entry in the list.
Definition: geventhandlerlist.cpp:115
GNet::Descriptor
A class that encapsulates a network socket file descriptor and an associated windows event handle...
Definition: gdescriptor.h:36
GNet::EventHandlerList::disarm
void disarm(ExceptionHandler *)
Resets any matching ExceptionHandler pointers.
Definition: geventhandlerlist.cpp:100
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:131
GNet::ExceptionHandler
An abstract interface for handling exceptions thrown out of event-loop callbacks (socket events...
Definition: gexceptionhandler.h:44
GNet::EventHandlerList::unlock
bool unlock()
Called at the end of a begin()/end() iteration to match a call to lock().
Definition: geventhandlerlist.cpp:136
geventhandlerlist.h
GNet::EventHandlerList::contains
bool contains(Descriptor fd) const
Returns true if the list, taking account of any pending changes, contains the given descriptor...
Definition: geventhandlerlist.cpp:122
GNet::EventHandler
A base class for classes that handle asynchronous events from the event loop.
Definition: geventhandler.h:47
GNet::EventHandlerList::add
void add(Descriptor fd, EventHandler *handler, ExceptionHandler *)
Adds a file-descriptor/handler tuple to the list.
Definition: geventhandlerlist.cpp:45
GNet::EventHandlerList::remove
void remove(Descriptor fd)
Removes a file-descriptor from the list.
Definition: geventhandlerlist.cpp:64
GNet::EventHandlerList::Value
A tuple for GNet::EventHandlerList.
Definition: geventhandlerlist.h:66
GNet::ExceptionHandler::onException
virtual void onException(std::exception &)=0
Called by the event loop when an exception is thrown out of an event loop callback.
GNet::EventHandlerList::Iterator
An iterator for GNet::EventHandlerList.
Definition: geventhandlerlist.h:75
GNet::EventHandlerList::EventHandlerList
EventHandlerList(const std::string &type)
Constructor.
Definition: geventhandlerlist.cpp:38
gdebug.h