VideoTools
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
geventhandler.cpp
Go to the documentation of this file.
1 //
2 // Copyright (C) 2017 Graeme Walker
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 // geventhandler.cpp
19 //
20 
21 #include "gdef.h"
22 #include "gnet.h"
23 #include "geventhandler.h"
24 #include "geventloop.h"
25 #include "gexception.h"
26 #include "gdebug.h"
27 #include "gassert.h"
28 #include "gdescriptor.h"
29 #include "glog.h"
30 #include <algorithm>
31 
33 {
34 }
35 
37 {
38  G_DEBUG( "GNet::EventHandler::readEvent: no override" ) ;
39 }
40 
42 {
43  G_DEBUG( "GNet::EventHandler::writeEvent: no override" ) ;
44 }
45 
47 {
48  throw G::Exception( "socket disconnect event" ) ; // "exception event" is confusing
49 }
50 
51 // ===
52 
53 namespace
54 {
55  struct fdless
56  {
57  bool operator()( const std::pair<GNet::Descriptor,GNet::EventHandler*> & p1 , const std::pair<GNet::Descriptor,GNet::EventHandler*> & p2 )
58  {
59  return p1.first < p2.first ;
60  }
61  } ;
62 }
63 
64 GNet::EventHandlerList::EventHandlerList( const std::string & type ) :
65  m_type(type) ,
66  m_lock(0U) ,
67  m_has_garbage(false)
68 {
69 }
70 
72 {
73  return contains(m_list,fd) || (m_lock && contains(m_pending_list,fd)) ;
74 }
75 
76 bool GNet::EventHandlerList::contains( const List & list , Descriptor fd )
77 {
78  List::const_iterator p = std::lower_bound( list.begin() , list.end() , List::value_type(fd,nullptr) , fdless() ) ;
79  return p != list.end() && (*p).first == fd && (*p).second != nullptr ;
80 }
81 
83 {
84  EventHandler * p1 = find( m_list , fd ) ;
85  EventHandler * p2 = m_lock ? find( m_pending_list , fd ) : nullptr ;
86  return p2 ? p2 : p1 ;
87 }
88 
90 {
91  List::const_iterator p = std::lower_bound( list.begin() , list.end() , List::value_type(fd,nullptr) , fdless() ) ;
92  return ( p != list.end() && (*p).first == fd ) ? (*p).second : nullptr ;
93 }
94 
96 {
97  G_ASSERT( fd.valid() && handler != nullptr ) ; if( !fd.valid() || handler == nullptr ) return ;
98  G_DEBUG( "GNet::EventHandlerList::add: " << m_type << "-list: " << "adding " << fd ) ;
99 
100  add( m_lock?m_pending_list:m_list , fd , handler ) ;
101 }
102 
103 void GNet::EventHandlerList::add( List & list , Descriptor fd , EventHandler * handler )
104 {
105  typedef std::pair<List::iterator,List::iterator> Range ;
106  Range range = std::equal_range( list.begin() , list.end() , List::value_type(fd,nullptr) , fdless() ) ;
107  if( range.first == range.second )
108  list.insert( range.second , List::value_type(fd,handler) ) ;
109  else
110  (*range.first).second = handler ;
111 }
112 
114 {
115  G_DEBUG( "GNet::EventHandlerList::remove: " << m_type << "-list: " << "removing " << fd ) ;
116  if( m_lock )
117  {
118  if( disable(m_list,fd) ) m_has_garbage = true ;
119  disable( m_pending_list , fd ) ;
120  }
121  else
122  {
123  remove( m_list , fd ) ;
124  }
125 }
126 
127 bool GNet::EventHandlerList::disable( List & list , Descriptor fd )
128 {
129  typedef std::pair<List::iterator,List::iterator> Range ;
130  Range range = std::equal_range( list.begin() , list.end() , List::value_type(fd,nullptr) , fdless() ) ;
131  const bool found = range.first != range.second ;
132  if( found )
133  (*range.first).second = nullptr ;
134  return found ;
135 }
136 
137 bool GNet::EventHandlerList::remove( List & list , Descriptor fd )
138 {
139  typedef std::pair<List::iterator,List::iterator> Range ;
140  Range range = std::equal_range( list.begin() , list.end() , List::value_type(fd,nullptr) , fdless() ) ;
141  const bool found = range.first != range.second ;
142  if( found )
143  list.erase( range.first ) ;
144  return found ;
145 }
146 
148 {
149  m_lock++ ;
150 }
151 
153 {
154  G_ASSERT( m_lock != 0U ) ;
155  m_lock-- ;
156  if( m_lock == 0U )
157  {
158  commit() ;
159  if( m_has_garbage )
160  collectGarbage() ;
161  }
162 }
163 
164 void GNet::EventHandlerList::commit()
165 {
166  const List::iterator end = m_pending_list.end() ;
167  for( List::iterator p = m_pending_list.begin() ; p != end ; ++p )
168  {
169  if( (*p).second != nullptr )
170  add( m_list , (*p).first , (*p).second ) ;
171  }
172  m_pending_list.clear() ;
173 }
174 
176 {
177  if( false ) // probably not worthwhile
178  {
179  const List::iterator end = m_list.end() ;
180  for( List::iterator p = m_list.begin() ; p != end ; )
181  {
182  if( (*p).second == nullptr )
183  p = m_list.erase( p ) ;
184  else
185  ++p ;
186  }
187  m_has_garbage = false ;
188  }
189 }
190 
191 // ==
192 
194 {
195 }
196 
197 /// \file geventhandler.cpp
void collectGarbage()
Collects garbage resulting from remove()s.
virtual void readEvent()
Called for a read event.
A class that encapsulates a network file descriptor and hides knowledge of its o/s-spefific error val...
Definition: gdescriptor.h:37
void lock()
To be called at the start of an begin()/end() iteration if the list might change during the iteration...
virtual void writeEvent()
Called for a write event.
bool valid() const
Returns true if the descriptor is valid.
bool contains(Descriptor fd) const
Returns true if the list contains the given file-descriptor.
A base class for classes that handle asynchronous events from the event loop.
Definition: geventhandler.h:78
void add(Descriptor fd, EventHandler *handler)
Adds a file-descriptor/handler pair to the list.
virtual ~EventExceptionHandler()
Destructor.
void unlock()
Called at the end of a begin()/end() iteration to match a call to lock().
void remove(Descriptor fd)
Removes a file-descriptor from the list.
A general-purpose exception class derived from std::exception and containing a std::string.
Definition: gexception.h:43
EventHandlerList(const std::string &type)
Constructor.
EventHandler * find(Descriptor fd)
Finds the handler associated with the given file descriptor.
virtual ~EventHandler()
Destructor.
virtual void exceptionEvent()
Called for a socket-exception event.