]>
git.saurik.com Git - wxWidgets.git/blob - src/unix/epolldispatcher.cpp
   1 /////////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/unix/epolldispatcher.cpp 
   3 // Purpose:     implements dispatcher for epoll_wait() call 
   4 // Author:      Lukasz Michalski 
   7 // Copyright:   (c) 2007 Lukasz Michalski 
   8 // Licence:     wxWindows licence 
   9 /////////////////////////////////////////////////////////////////////////////// 
  11 // ============================================================================ 
  13 // ============================================================================ 
  15 // ---------------------------------------------------------------------------- 
  17 // ---------------------------------------------------------------------------- 
  19 // for compilers that support precompilation, includes "wx.h". 
  20 #include "wx/wxprec.h" 
  22 #if wxUSE_EPOLL_DISPATCHER 
  24 #include "wx/unix/private/epolldispatcher.h" 
  25 #include "wx/unix/private.h" 
  26 #include "wx/stopwatch.h" 
  33 #include <sys/epoll.h> 
  37 #define wxEpollDispatcher_Trace wxT("epolldispatcher") 
  39 // ============================================================================ 
  41 // ============================================================================ 
  43 // helper: return EPOLLxxx mask corresponding to the given flags (and also log 
  44 // debugging messages about it) 
  45 static uint32_t GetEpollMask(int flags
, int fd
) 
  47     wxUnusedVar(fd
); // unused if wxLogTrace() disabled 
  51     if ( flags 
& wxFDIO_INPUT 
) 
  54         wxLogTrace(wxEpollDispatcher_Trace
, 
  55                    wxT("Registered fd %d for input events"), fd
); 
  58     if ( flags 
& wxFDIO_OUTPUT 
) 
  61         wxLogTrace(wxEpollDispatcher_Trace
, 
  62                    wxT("Registered fd %d for output events"), fd
); 
  65     if ( flags 
& wxFDIO_EXCEPTION 
) 
  67         ep 
|= EPOLLERR 
| EPOLLHUP
; 
  68         wxLogTrace(wxEpollDispatcher_Trace
, 
  69                    wxT("Registered fd %d for exceptional events"), fd
); 
  75 // ---------------------------------------------------------------------------- 
  77 // ---------------------------------------------------------------------------- 
  80 wxEpollDispatcher 
*wxEpollDispatcher::Create() 
  82     int epollDescriptor 
= epoll_create(1024); 
  83     if ( epollDescriptor 
== -1 ) 
  85         wxLogSysError(_("Failed to create epoll descriptor")); 
  88     wxLogTrace(wxEpollDispatcher_Trace
, 
  89                    wxT("Epoll fd %d created"), epollDescriptor
); 
  90     return new wxEpollDispatcher(epollDescriptor
); 
  93 wxEpollDispatcher::wxEpollDispatcher(int epollDescriptor
) 
  95     wxASSERT_MSG( epollDescriptor 
!= -1, wxT("invalid descriptor") ); 
  97     m_epollDescriptor 
= epollDescriptor
; 
 100 wxEpollDispatcher::~wxEpollDispatcher() 
 102     if ( close(m_epollDescriptor
) != 0 ) 
 104         wxLogSysError(_("Error closing epoll descriptor")); 
 108 bool wxEpollDispatcher::RegisterFD(int fd
, wxFDIOHandler
* handler
, int flags
) 
 111     ev
.events 
= GetEpollMask(flags
, fd
); 
 112     ev
.data
.ptr 
= handler
; 
 114     const int ret 
= epoll_ctl(m_epollDescriptor
, EPOLL_CTL_ADD
, fd
, &ev
); 
 117         wxLogSysError(_("Failed to add descriptor %d to epoll descriptor %d"), 
 118                       fd
, m_epollDescriptor
); 
 122     wxLogTrace(wxEpollDispatcher_Trace
, 
 123                wxT("Added fd %d (handler %p) to epoll %d"), fd
, handler
, m_epollDescriptor
); 
 128 bool wxEpollDispatcher::ModifyFD(int fd
, wxFDIOHandler
* handler
, int flags
) 
 131     ev
.events 
= GetEpollMask(flags
, fd
); 
 132     ev
.data
.ptr 
= handler
; 
 134     const int ret 
= epoll_ctl(m_epollDescriptor
, EPOLL_CTL_MOD
, fd
, &ev
); 
 137         wxLogSysError(_("Failed to modify descriptor %d in epoll descriptor %d"), 
 138                       fd
, m_epollDescriptor
); 
 143     wxLogTrace(wxEpollDispatcher_Trace
, 
 144                 wxT("Modified fd %d (handler: %p) on epoll %d"), fd
, handler
, m_epollDescriptor
); 
 148 bool wxEpollDispatcher::UnregisterFD(int fd
) 
 154     if ( epoll_ctl(m_epollDescriptor
, EPOLL_CTL_DEL
, fd
, &ev
) != 0 ) 
 156         wxLogSysError(_("Failed to unregister descriptor %d from epoll descriptor %d"), 
 157                       fd
, m_epollDescriptor
); 
 159     wxLogTrace(wxEpollDispatcher_Trace
, 
 160                 wxT("removed fd %d from %d"), fd
, m_epollDescriptor
); 
 165 wxEpollDispatcher::DoPoll(epoll_event 
*events
, int numEvents
, int timeout
) const 
 167     // the code below relies on TIMEOUT_INFINITE being -1 so that we can pass 
 168     // timeout value directly to epoll_wait() which interprets -1 as meaning to 
 169     // wait forever and would need to be changed if the value of 
 170     // TIMEOUT_INFINITE ever changes 
 171     wxCOMPILE_TIME_ASSERT( TIMEOUT_INFINITE 
== -1, UpdateThisCode 
); 
 173     wxMilliClock_t timeEnd
; 
 175         timeEnd 
= wxGetLocalTimeMillis(); 
 180         rc 
= epoll_wait(m_epollDescriptor
, events
, numEvents
, timeout
); 
 181         if ( rc 
!= -1 || errno 
!= EINTR 
) 
 184         // we got interrupted, update the timeout and restart 
 187             timeout 
= wxMilliClockToLong(timeEnd 
- wxGetLocalTimeMillis()); 
 196 bool wxEpollDispatcher::HasPending() const 
 200     // NB: it's not really clear if epoll_wait() can return a number greater 
 201     //     than the number of events passed to it but just in case it can, use 
 202     //     >= instead of == here, see #10397 
 203     return DoPoll(&event
, 1, 0) >= 1; 
 206 int wxEpollDispatcher::Dispatch(int timeout
) 
 208     epoll_event events
[16]; 
 210     const int rc 
= DoPoll(events
, WXSIZEOF(events
), timeout
); 
 214         wxLogSysError(_("Waiting for IO on epoll descriptor %d failed"), 
 220     for ( epoll_event 
*p 
= events
; p 
< events 
+ rc
; p
++ ) 
 222         wxFDIOHandler 
* const handler 
= (wxFDIOHandler 
*)(p
->data
.ptr
); 
 225             wxFAIL_MSG( wxT("NULL handler in epoll_event?") ); 
 229         // note that for compatibility with wxSelectDispatcher we call 
 230         // OnReadWaiting() on EPOLLHUP as this is what epoll_wait() returns 
 231         // when the write end of a pipe is closed while with select() the 
 232         // remaining pipe end becomes ready for reading when this happens 
 233         if ( p
->events 
& (EPOLLIN 
| EPOLLHUP
) ) 
 234             handler
->OnReadWaiting(); 
 235         else if ( p
->events 
& EPOLLOUT 
) 
 236             handler
->OnWriteWaiting(); 
 237         else if ( p
->events 
& EPOLLERR 
) 
 238             handler
->OnExceptionWaiting(); 
 248 #endif // wxUSE_EPOLL_DISPATCHER