38class GNet::EventLoopImp :
public EventLoop
41 G_EXCEPTION( Error ,
tx(
"epoll error") ) ;
43 ~EventLoopImp()
override ;
46 std::string
run()
override ;
48 void quit(
const std::string & )
override ;
50 void addRead( Descriptor fd , EventHandler & , ExceptionSink )
override ;
51 void addWrite( Descriptor fd , EventHandler & , ExceptionSink )
override ;
52 void addOther( Descriptor fd , EventHandler & , ExceptionSink )
override ;
53 void dropRead( Descriptor fd )
noexcept override ;
54 void dropWrite( Descriptor fd )
noexcept override ;
55 void dropOther( Descriptor fd )
noexcept override ;
56 void drop( Descriptor fd )
noexcept override ;
57 void disarm( ExceptionHandler * )
noexcept override ;
60 EventLoopImp(
const EventLoopImp & ) = delete ;
61 EventLoopImp( EventLoopImp && ) = delete ;
62 EventLoopImp & operator=(
const EventLoopImp & ) = delete ;
63 EventLoopImp & operator=( EventLoopImp && ) = delete ;
68 unsigned int m_events {0U} ;
69 EventEmitter m_read_emitter ;
70 EventEmitter m_write_emitter ;
72 using List = std::vector<ListItem> ;
76 ListItem * find( Descriptor fd ) noexcept ;
77 ListItem & findOrCreate( Descriptor fd ) ;
79 static int ms(
unsigned int ,
unsigned int ) ;
80 void fdupdate(
int fd ,
unsigned int old_events ,
unsigned int new_events ) ;
81 void fdupdate(
int fd ,
unsigned int old_events ,
unsigned int new_events , std::nothrow_t ) noexcept ;
82 void fdadd(
int fd ,
unsigned int events ) ;
83 void fdmodify(
int fd ,
unsigned int events ) ;
84 int fdmodify(
int fd ,
unsigned int events , std::nothrow_t ) noexcept ;
85 void fdremove(
int fd ) noexcept ;
88 std::vector<struct epoll_event> m_wait_events ;
91 std::string m_quit_reason ;
92 bool m_running {
false} ;
101 return std::make_unique<EventLoopImp>() ;
106GNet::EventLoopImp::EventLoopImp() :
107 m_fd(epoll_create1(EPOLL_CLOEXEC))
110 throw Error(
"epoll_create" ) ;
113GNet::EventLoopImp::~EventLoopImp()
120 for(
auto & item : m_list )
122 item.m_read_emitter.disarm( p ) ;
123 item.m_write_emitter.disarm( p ) ;
140 std::string quit_reason = m_quit_reason ;
141 m_quit_reason.clear() ;
146void GNet::EventLoopImp::runOnce()
150 m_wait_events.resize( std::max(std::size_t(1U),m_list.size()) ) ;
153 int timeout_ms = ms() ;
154 m_wait_rc = epoll_wait( m_fd , &m_wait_events[0] , m_wait_events.size() , timeout_ms ) ;
163 if( m_wait_rc == 0 || timeout_ms == 0 )
169 for(
int i = 0 ; m_wait_rc > 0 && i < m_wait_rc ; i++ )
171 unsigned int e = m_wait_events[i].events ;
172 Descriptor fd( m_wait_events[i].data.fd ) ;
175 ListItem * item = find( fd ) ;
177 item->m_read_emitter.raiseReadEvent( fd ) ;
181 ListItem * item = find( fd ) ;
183 item->m_write_emitter.raiseWriteEvent( fd ) ;
188int GNet::EventLoopImp::ms()
const
190 constexpr int infinite = -1 ;
196 else if( pair.first.s() == 0 && pair.first.us() == 0U )
199 return std::max( 1 , ms(pair.first.s(),pair.first.us()) ) ;
207int GNet::EventLoopImp::ms(
unsigned int s ,
unsigned int us )
209 constexpr unsigned int s_max =
static_cast<unsigned int>( std::numeric_limits<int>::max()/1000 - 1 ) ;
210 static_assert( s_max > 600 ,
"" ) ;
213 std::numeric_limits<int>::max() :
214 static_cast<int>( (s*1000U) + ((us+999U)/1000U) ) ;
219 m_quit_reason = reason ;
228GNet::EventLoopImp::ListItem * GNet::EventLoopImp::find( Descriptor fd )
noexcept
230 std::size_t ufd =
static_cast<unsigned int>(fd.fd()) ;
231 return fd.valid() && ufd < m_list.size() ? &m_list[ufd] : nullptr ;
234GNet::EventLoopImp::ListItem & GNet::EventLoopImp::findOrCreate( Descriptor fd )
236 ListItem * p = find( fd ) ;
239 std::size_t ufd =
static_cast<unsigned int>(fd.fd()) ;
240 m_list.resize( std::max(m_list.size(),ufd+1U) ) ;
249 G_ASSERT( fd.valid() ) ;
250 handler.setDescriptor( fd ) ;
251 unsigned int new_events = EPOLLIN ;
252 ListItem & item = findOrCreate( Descriptor(fd) ) ;
253 fdupdate( fd.fd() , item.m_events , item.m_events | new_events ) ;
254 item.m_events |= new_events ;
255 item.m_read_emitter.update( &handler , es ) ;
260 G_ASSERT( fd.valid() ) ;
261 handler.setDescriptor( fd ) ;
262 unsigned int new_events = EPOLLOUT ;
263 ListItem & item = findOrCreate( Descriptor(fd) ) ;
264 fdupdate( fd.fd() , item.m_events , item.m_events | new_events ) ;
265 item.m_events |= new_events ;
266 item.m_write_emitter.update( &handler , es ) ;
276 ListItem * item = find( Descriptor(fd) ) ;
277 if( item && ( item->m_events & EPOLLIN ) )
279 unsigned int new_events = item->m_events & ~EPOLLIN ;
280 fdupdate( fd.fd() , item->m_events , new_events , std::nothrow ) ;
281 item->m_events = new_events ;
287 ListItem * item = find( Descriptor(fd) ) ;
288 if( item && ( item->m_events & EPOLLOUT ) )
290 unsigned int new_events = item->m_events & ~EPOLLOUT ;
291 fdupdate( fd.fd() , item->m_events , new_events , std::nothrow ) ;
292 item->m_events = new_events ;
303 ListItem * item = find( fd ) ;
307 fdremove( fd.fd() ) ;
308 item->m_events = 0U ;
309 item->m_read_emitter.reset() ;
310 item->m_write_emitter.reset() ;
314void GNet::EventLoopImp::fdupdate(
int fd ,
unsigned int old_events ,
unsigned int new_events )
316 if( new_events == 0U )
318 else if( old_events == 0U )
319 fdadd( fd , new_events ) ;
321 fdmodify( fd , new_events ) ;
324void GNet::EventLoopImp::fdupdate(
int fd ,
unsigned int ,
unsigned int new_events , std::nothrow_t )
noexcept
326 if( new_events == 0U )
329 fdmodify( fd , new_events , std::nothrow ) ;
332void GNet::EventLoopImp::fdadd(
int fd ,
unsigned int events )
334 epoll_event
event {} ;
336 event.events = events ;
337 int rc = epoll_ctl( m_fd , EPOLL_CTL_ADD , fd , &event ) ;
345void GNet::EventLoopImp::fdmodify(
int fd ,
unsigned int events )
347 epoll_event
event {} ;
349 event.events = events ;
350 int rc = epoll_ctl( m_fd , EPOLL_CTL_MOD , fd , &event ) ;
358int GNet::EventLoopImp::fdmodify(
int fd ,
unsigned int events , std::nothrow_t )
noexcept
360 epoll_event
event {} ;
362 event.events = events ;
363 int rc = epoll_ctl( m_fd , EPOLL_CTL_MOD , fd , &event ) ;
365 return rc == -1 ? e : 0 ;
368void GNet::EventLoopImp::fdremove(
int fd )
noexcept
370 epoll_event
event {} ;
371 epoll_ctl( m_fd , EPOLL_CTL_DEL , fd , &event ) ;
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 std::string strerror(int errno_)
Translates an 'errno' value into a meaningful diagnostic string.
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.
constexpr const char * tx(const char *p)
A briefer alternative to G::gettext_noop().