42class GNet::EventLoopImp :
public EventLoop
45 G_EXCEPTION( Error ,
tx(
"select error") )
49 std::
string run() override ;
50 bool running() const override ;
51 void quit( const
std::
string & ) override ;
52 void quit( const
G::SignalSafe & ) override ;
53 void addRead( Descriptor , EventHandler & , EventState ) override ;
54 void addWrite( Descriptor , EventHandler & , EventState ) override ;
55 void addOther( Descriptor , EventHandler & , EventState ) override ;
56 void dropRead( Descriptor ) noexcept override ;
57 void dropWrite( Descriptor ) noexcept override ;
58 void dropOther( Descriptor ) noexcept override ;
59 void drop( Descriptor ) noexcept override ;
60 void disarm( ExceptionHandler * ) noexcept override ;
63 ~EventLoopImp() override = default ;
64 EventLoopImp( const EventLoopImp & ) = delete ;
65 EventLoopImp( EventLoopImp && ) = delete ;
66 EventLoopImp & operator=( const EventLoopImp & ) = delete ;
67 EventLoopImp & operator=( EventLoopImp && ) = delete ;
72 EventHandler * m_handler {
nullptr} ;
73 EventState m_es {EventState::Private(),
nullptr,
nullptr} ;
74 void update( EventHandler * handler , EventState es )
noexcept { m_handler = handler ; m_es = es ; }
76 using List = std::vector<ListItem> ;
78 static void addImp(
int fd , EventHandler & , EventState , fd_set & , List & ,
int & ) ;
79 static void disarmImp( List & , ExceptionHandler * ) noexcept ;
80 static void disarmImp( EventState & , ExceptionHandler * ) noexcept ;
81 static void dropImp(
int fd , fd_set & , fd_set & ,
int & ) noexcept ;
82 static int events(
int nfds , fd_set * ) noexcept ;
83 static int fdmaxof(
int nfds , fd_set * ) noexcept ;
84 static int fdmaxof( std::size_t nfds , fd_set * sp ) noexcept ;
88 std::string m_quit_reason ;
89 bool m_running {
false} ;
93 int m_read_fdmax {-1} ;
94 int m_write_fdmax {-1} ;
95 int m_other_fdmax {-1} ;
96 fd_set m_read_set_copy ;
97 fd_set m_write_set_copy ;
98 fd_set m_other_set_copy ;
102 EventState m_es_current {EventState::Private(),
nullptr,
nullptr} ;
109 return std::make_unique<EventLoopImp>() ;
114GNet::EventLoopImp::EventLoopImp()
116 FD_ZERO( &m_read_set ) ;
117 FD_ZERO( &m_write_set ) ;
118 FD_ZERO( &m_other_set ) ;
119 FD_ZERO( &m_read_set_copy ) ;
120 FD_ZERO( &m_write_set_copy ) ;
121 FD_ZERO( &m_other_set_copy ) ;
122 m_read_list.reserve( FD_SETSIZE ) ;
123 m_write_list.reserve( FD_SETSIZE ) ;
124 m_other_list.reserve( FD_SETSIZE ) ;
134 std::string quit_reason = m_quit_reason ;
135 m_quit_reason.clear() ;
148 m_quit_reason = reason ;
156void GNet::EventLoopImp::runOnce()
160 using Timeval =
struct timeval ;
162 Timeval * timeout_p = nullptr ;
163 bool immediate = false ;
167 bool infinite = false ;
169 timeout.tv_sec = interval.
s() ;
170 timeout.tv_usec = interval.
us() ;
171 timeout_p = infinite ? nullptr : &timeout ;
172 immediate = !infinite && interval.
s() == 0 && interval.
us() == 0U ;
182 if( m_read_fdmax == -1 ) m_read_fdmax = fdmaxof( m_read_list.size() , &m_read_set ) ;
183 if( m_write_fdmax == -1 ) m_write_fdmax = fdmaxof( m_write_list.size() , &m_write_set ) ;
184 if( m_other_fdmax == -1 ) m_other_fdmax = fdmaxof( m_other_list.size() , &m_other_set ) ;
185 int nfds = 1 + std::max( {m_read_fdmax,m_write_fdmax,m_other_fdmax} ) ;
187 G_ASSERT( fdmaxof(FD_SETSIZE,&m_read_set) == m_read_fdmax ) ;
188 G_ASSERT( fdmaxof(FD_SETSIZE,&m_write_set) == m_write_fdmax ) ;
189 G_ASSERT( fdmaxof(FD_SETSIZE,&m_other_set) == m_other_fdmax ) ;
190 G_ASSERT( m_read_list.size() >= std::size_t(m_read_fdmax+1) ) ;
191 G_ASSERT( m_write_list.size() >= std::size_t(m_write_fdmax+1) ) ;
192 G_ASSERT( m_other_list.size() >= std::size_t(m_other_fdmax+1) ) ;
198 m_read_set_copy = m_read_set ;
199 m_write_set_copy = m_write_set ;
200 m_other_set_copy = m_other_set ;
201 int rc = ::select( nfds , &m_read_set_copy , &m_write_set_copy , &m_other_set_copy , timeout_p ) ;
209 rc == (events(nfds,&m_read_set_copy)+events(nfds,&m_write_set_copy)+events(nfds,&m_other_set_copy)) ) ;
213 if( rc == 0 || immediate )
226 for(
int fd = 0 ; ecount < rc && fd < nfds ; fd++ )
228 if( FD_ISSET(fd,&m_read_set_copy) )
230 G_ASSERT(
static_cast<unsigned int>(fd) < m_read_list.size() ) ;
232 m_es_current = m_read_list[fd].m_es ;
235 if( FD_ISSET(fd,&m_write_set_copy) )
237 G_ASSERT(
static_cast<unsigned int>(fd) < m_write_list.size() ) ;
239 m_es_current = m_write_list[fd].m_es ;
242 if( FD_ISSET(fd,&m_other_set_copy) )
244 G_ASSERT(
static_cast<unsigned int>(fd) < m_other_list.size() ) ;
246 m_es_current = m_other_list[fd].m_es ;
252int GNet::EventLoopImp::events(
int nfds , fd_set * sp )
noexcept
255 for(
int fd = 0 ; fd < nfds ; fd++ )
257 if( FD_ISSET(fd,sp) )
263inline int GNet::EventLoopImp::fdmaxof( std::size_t nfds , fd_set * sp )
noexcept
265 return fdmaxof(
static_cast<int>(nfds) , sp ) ;
268int GNet::EventLoopImp::fdmaxof(
int nfds , fd_set * sp )
noexcept
271 for(
int fd = 0 ; fd < nfds ; fd++ )
273 if( FD_ISSET(fd,sp) )
282 addImp( fdd.fd() , handler , es , m_read_set , m_read_list , m_read_fdmax ) ;
288 addImp( fdd.fd() , handler , es , m_write_set , m_write_list , m_write_fdmax ) ;
294 addImp( fdd.fd() , handler , es , m_other_set , m_other_list , m_other_fdmax ) ;
297void GNet::EventLoopImp::addImp(
int fd , EventHandler & handler , EventState es , fd_set & set , List & list ,
int & fdmax )
299 G_ASSERT( fd >= 0 ) ;
300 G_ASSERT( fdmax >= -1 ) ;
301 if( fd >= FD_SETSIZE )
302 throw EventLoop::Overflow(
"too many open file descriptors for select()" ) ;
305 handler.setDescriptor( Descriptor(fd) ) ;
308 if( list.size() < std::size_t(fd+1) )
309 list.resize( fd+1 ) ;
310 list[fd].update( &handler , es ) ;
313 FD_SET( fd , &set ) ;
314 fdmax = std::max( fdmax , fd ) ;
316 G_ASSERT( list.size() >=
static_cast<std::size_t
>(fdmax+1) ) ;
322 dropImp( fdd.fd() , m_read_set , m_read_set_copy , m_read_fdmax ) ;
328 dropImp( fdd.fd() , m_write_set , m_write_set_copy , m_write_fdmax ) ;
334 dropImp( fdd.fd() , m_read_set , m_read_set_copy , m_read_fdmax ) ;
337void GNet::EventLoopImp::dropImp(
int fd , fd_set & set , fd_set & set_copy ,
int & fdmax )
noexcept
339 G_ASSERT( fd >= 0 ) ;
340 G_ASSERT( fdmax >= -1 ) ;
343 FD_CLR( fd , &set ) ;
344 FD_CLR( fd , &set_copy ) ;
354 dropImp( fdd.fd() , m_read_set , m_read_set_copy , m_read_fdmax ) ;
355 dropImp( fdd.fd() , m_write_set , m_write_set_copy , m_write_fdmax ) ;
356 dropImp( fdd.fd() , m_other_set , m_other_set_copy , m_other_fdmax ) ;
359 std::size_t ufd =
static_cast<unsigned int>(fdd.fd()) ;
360 if( ufd < m_read_list.size() )
361 m_read_list[ufd].m_handler =
nullptr ;
362 if( ufd < m_write_list.size() )
363 m_write_list[ufd].m_handler =
nullptr ;
364 if( ufd < m_other_list.size() )
365 m_other_list[ufd].m_handler =
nullptr ;
372 disarmImp( m_es_current , eh ) ;
379 disarmImp( m_read_list , eh ) ;
380 disarmImp( m_write_list , eh ) ;
381 disarmImp( m_other_list , eh ) ;
384void GNet::EventLoopImp::disarmImp( List & list , ExceptionHandler * eh )
noexcept
386 for(
auto & list_item : list )
388 if( list_item.m_es.eh() == eh )
389 list_item.m_es.disarm() ;
393void GNet::EventLoopImp::disarmImp( EventState & es , ExceptionHandler * eh )
noexcept
static void raiseReadEvent(EventHandler *, EventState &)
Calls readEvent() on the event handler and catches any exceptions and delivers them to the EventState...
static void raiseOtherEvent(EventHandler *, EventState &, EventHandler::Reason)
Calls otherEvent() on the event handler and catches any exceptions and delivers them to the EventStat...
static void raiseWriteEvent(EventHandler *, EventState &)
Calls writeEvent() on the event handler and catches any exceptions and delivers them to the EventStat...
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 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 std::string run()=0
Runs the main event loop.
virtual void addWrite(Descriptor fd, EventHandler &, EventState)=0
Adds the given event source descriptor and associated handler to the write list.
virtual void dropOther(Descriptor fd) noexcept=0
Removes the given event descriptor from the list of other-event sources.
virtual void addRead(Descriptor fd, EventHandler &, EventState)=0
Adds the given event source descriptor and associated handler to the read list.
virtual void addOther(Descriptor fd, EventHandler &, EventState)=0
Adds the given event source descriptor and associated handler to the exception list.
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 int errno_(const SignalSafe &=G::SignalSafe()) noexcept
Returns the process's current 'errno' value.
A class that sets a simple variable to a particular value 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.
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) noexcept
A briefer alternative to G::gettext_noop().