45class GNet::EventLoopImp :
public EventLoop
48 G_EXCEPTION( Error ,
tx(
"select error") ) ;
52 std::string
run()
override ;
54 void quit(
const std::string & )
override ;
56 void addRead( Descriptor fd , EventHandler & , ExceptionSink )
override ;
57 void addWrite( Descriptor fd , EventHandler & , ExceptionSink )
override ;
58 void addOther( Descriptor fd , EventHandler & , ExceptionSink )
override ;
59 void dropRead( Descriptor fd )
noexcept override ;
60 void dropWrite( Descriptor fd )
noexcept override ;
61 void dropOther( Descriptor fd )
noexcept override ;
62 void drop( Descriptor fd )
noexcept override ;
63 void disarm( ExceptionHandler * )
noexcept override ;
66 ~EventLoopImp()
override = default ;
67 EventLoopImp(
const EventLoopImp & ) = delete ;
68 EventLoopImp( EventLoopImp && ) = delete ;
69 EventLoopImp & operator=(
const EventLoopImp & ) = delete ;
70 EventLoopImp & operator=( EventLoopImp && ) = delete ;
73 using Emitters = std::vector<EventEmitter> ;
75 void addImp(
int fd , Emitters & , EventHandler & , ExceptionSink ) ;
76 void dropImp(
int fd , Emitters & ) noexcept ;
77 void disarmImp( Emitters & , ExceptionHandler * ) noexcept ;
78 static int events(
int nfds , fd_set * ) ;
82 std::string m_quit_reason ;
83 bool m_running {
false} ;
88 Emitters m_read_emitters ;
89 Emitters m_write_emitters ;
90 Emitters m_other_emitters ;
91 fd_set m_read_set_copy ;
92 fd_set m_write_set_copy ;
93 fd_set m_other_set_copy ;
100 return std::make_unique<EventLoopImp>() ;
105GNet::EventLoopImp::EventLoopImp()
107 FD_ZERO( &m_read_set ) ;
108 FD_ZERO( &m_write_set ) ;
109 FD_ZERO( &m_other_set ) ;
110 FD_ZERO( &m_read_set_copy ) ;
111 FD_ZERO( &m_write_set_copy ) ;
112 FD_ZERO( &m_other_set_copy ) ;
122 std::string quit_reason = m_quit_reason ;
123 m_quit_reason.clear() ;
136 m_quit_reason = reason ;
144void GNet::EventLoopImp::runOnce()
148 using Timeval =
struct timeval ;
150 Timeval * timeout_p = nullptr ;
151 bool immediate = false ;
155 bool infinite = false ;
157 timeout.tv_sec = interval.
s() ;
158 timeout.tv_usec = interval.
us() ;
159 timeout_p = infinite ? nullptr : &timeout ;
160 immediate = !infinite && interval.
s() == 0 && interval.
us() == 0U ;
167 if( timeout_p ==
nullptr || timeout.tv_sec > 0 )
170 timeout.tv_usec = 999999U ;
172 timeout_p = &timeout ;
178 m_read_set_copy = m_read_set ;
179 m_write_set_copy = m_write_set ;
180 m_other_set_copy = m_other_set ;
181 int rc = ::select( nfds , &m_read_set_copy , &m_write_set_copy , &m_other_set_copy , timeout_p ) ;
189 rc == (events(nfds,&m_read_set_copy)+events(nfds,&m_write_set_copy)+events(nfds,&m_other_set_copy)) ) ;
193 if( rc == 0 || immediate )
204 for(
int fd = 0 ; ecount < rc && fd < nfds ; fd++ )
206 if( FD_ISSET(fd,&m_read_set_copy) )
209 G_ASSERT(
static_cast<unsigned int>(fd) < m_read_emitters.size() ) ;
210 m_read_emitters[fd].raiseReadEvent( Descriptor(fd) ) ;
212 if( FD_ISSET(fd,&m_write_set_copy) )
215 G_ASSERT(
static_cast<unsigned int>(fd) < m_write_emitters.size() ) ;
216 m_write_emitters[fd].raiseWriteEvent( Descriptor(fd) ) ;
218 if( FD_ISSET(fd,&m_other_set_copy) )
221 G_ASSERT(
static_cast<unsigned int>(fd) < m_other_emitters.size() ) ;
222 m_other_emitters[fd].raiseOtherEvent( Descriptor(fd) , EventHandler::Reason::other ) ;
228 for(
int fd = 0 ; fd < m_nfds ; fd++ )
230 if( FD_ISSET(fd,&m_read_set) ||
231 FD_ISSET(fd,&m_write_set) ||
232 FD_ISSET(fd,&m_other_set) )
237 m_nfds = fd_max + 1 ;
238 m_read_emitters.resize( m_nfds ) ;
239 m_write_emitters.resize( m_nfds ) ;
240 m_other_emitters.resize( m_nfds ) ;
244 Timeval timeout_slow ;
245 timeout_slow.tv_sec = 0 ;
246 timeout_slow.tv_usec = 100000 ;
247 ::select( 0 ,
nullptr ,
nullptr ,
nullptr , &timeout_slow ) ;
251int GNet::EventLoopImp::events(
int nfds , fd_set * sp )
254 for(
int fd = 0 ; fd < nfds ; fd++ )
256 if( FD_ISSET(fd,sp) )
266 handler.setDescriptor( fd ) ;
267 addImp( fd.fd() , m_read_emitters , handler , es ) ;
268 FD_SET( fd.fd() , &m_read_set ) ;
276 handler.setDescriptor( fd ) ;
277 addImp( fd.fd() , m_write_emitters , handler , es ) ;
278 FD_SET( fd.fd() , &m_write_set ) ;
286 handler.setDescriptor( fd ) ;
287 addImp( fd.fd() , m_other_emitters , handler , es ) ;
288 FD_SET( fd.fd() , &m_other_set ) ;
292void GNet::EventLoopImp::addImp(
int fd , Emitters & emitters , EventHandler & handler , ExceptionSink es )
294 if( fd >= FD_SETSIZE )
295 throw EventLoop::Overflow(
"too many open file descriptors for select()" ) ;
297 m_nfds = std::max( m_nfds , fd+1 ) ;
298 emitters.resize( m_nfds ) ;
299 emitters[fd].update( &handler , es ) ;
306 FD_CLR( fd.fd() , &m_read_set ) ;
307 FD_CLR( fd.fd() , &m_read_set_copy ) ;
315 FD_CLR( fd.fd() , &m_write_set ) ;
316 FD_CLR( fd.fd() , &m_write_set_copy ) ;
324 FD_CLR( fd.fd() , &m_other_set ) ;
325 FD_CLR( fd.fd() , &m_other_set_copy ) ;
334 std::size_t ufd =
static_cast<unsigned int>(fd.fd()) ;
335 if( ufd < m_read_emitters.size() )
336 m_read_emitters[ufd].reset() ;
337 if( ufd < m_write_emitters.size() )
338 m_write_emitters[ufd].reset() ;
339 if( ufd < m_other_emitters.size() )
340 m_other_emitters[ufd].reset() ;
345 disarmImp( m_read_emitters , p ) ;
346 disarmImp( m_write_emitters , p ) ;
347 disarmImp( m_other_emitters , p ) ;
350void GNet::EventLoopImp::disarmImp( Emitters & emitters , ExceptionHandler * p )
noexcept
352 for(
auto & emitter : emitters )
354 emitter.disarm( p ) ;
virtual void dropWrite(Descriptor fd) noexcept=0
Removes the given event descriptor from the list of write sources.
virtual bool running() const =0
Returns true if called from within run().
virtual void drop(Descriptor fd) noexcept=0
Removes the given event descriptor from the event loop as the EventHandler is being destructed.
static std::unique_ptr< EventLoop > create()
A factory method which creates an instance of a derived class on the heap.
virtual void dropRead(Descriptor fd) noexcept=0
Removes the given event descriptor from the list of read sources.
virtual void addOther(Descriptor fd, EventHandler &, ExceptionSink)=0
Adds the given event source descriptor and associated handler to the exception list.
virtual void disarm(ExceptionHandler *) noexcept=0
Used to prevent the given interface from being used, typically called from the ExceptionHandler destr...
virtual void quit(const std::string &reason)=0
Causes run() to return (once the call stack has unwound).
virtual void addWrite(Descriptor fd, EventHandler &, ExceptionSink)=0
Adds the given event source descriptor and associated handler to the write list.
virtual std::string run()=0
Runs the main event loop.
virtual void addRead(Descriptor fd, EventHandler &, ExceptionSink)=0
Adds the given event source descriptor and associated handler to the read list.
virtual void dropOther(Descriptor fd) noexcept=0
Removes the given event descriptor from the list of other-event sources.
std::pair< G::TimeInterval, bool > interval() const
Returns the interval to the first timer expiry.
void doTimeouts()
Triggers the timeout callbacks of any expired timers.
static TimerList & instance()
Singleton access. Throws an exception if none.
static TimerList * ptr() noexcept
Singleton access. Returns nullptr if none.
static bool remove(const Path &path, std::nothrow_t) noexcept
Deletes the file or directory. Returns false on error.
static int errno_(const SignalSafe &=G::SignalSafe()) noexcept
Returns the process's current 'errno' value.
A class that sets a boolean variable to false at the end of its scope.
An empty structure that is used to indicate a signal-safe, reentrant implementation.
static std::string fromInt(int i)
Converts int 'i' to a string.
static bool enabled() noexcept
Returns true if test features are enabled.
An interval between two G::SystemTime values or two G::TimerTime values.
static TimeInterval zero()
Factory function for the zero interval.
unsigned int s() const
Returns the number of seconds.
unsigned int us() const
Returns the fractional microseconds part.
constexpr const char * tx(const char *p)
A briefer alternative to G::gettext_noop().