]>
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
6 // Copyright: (c) 2007 Lukasz Michalski
7 // Licence: wxWindows licence
8 ///////////////////////////////////////////////////////////////////////////////
10 // ============================================================================
12 // ============================================================================
14 // ----------------------------------------------------------------------------
16 // ----------------------------------------------------------------------------
18 // for compilers that support precompilation, includes "wx.h".
19 #include "wx/wxprec.h"
21 #if wxUSE_EPOLL_DISPATCHER
23 #include "wx/unix/private/epolldispatcher.h"
24 #include "wx/unix/private.h"
25 #include "wx/stopwatch.h"
32 #include <sys/epoll.h>
36 #define wxEpollDispatcher_Trace wxT("epolldispatcher")
38 // ============================================================================
40 // ============================================================================
42 // helper: return EPOLLxxx mask corresponding to the given flags (and also log
43 // debugging messages about it)
44 static uint32_t GetEpollMask(int flags
, int fd
)
46 wxUnusedVar(fd
); // unused if wxLogTrace() disabled
50 if ( flags
& wxFDIO_INPUT
)
53 wxLogTrace(wxEpollDispatcher_Trace
,
54 wxT("Registered fd %d for input events"), fd
);
57 if ( flags
& wxFDIO_OUTPUT
)
60 wxLogTrace(wxEpollDispatcher_Trace
,
61 wxT("Registered fd %d for output events"), fd
);
64 if ( flags
& wxFDIO_EXCEPTION
)
66 ep
|= EPOLLERR
| EPOLLHUP
;
67 wxLogTrace(wxEpollDispatcher_Trace
,
68 wxT("Registered fd %d for exceptional events"), fd
);
74 // ----------------------------------------------------------------------------
76 // ----------------------------------------------------------------------------
79 wxEpollDispatcher
*wxEpollDispatcher::Create()
81 int epollDescriptor
= epoll_create(1024);
82 if ( epollDescriptor
== -1 )
84 wxLogSysError(_("Failed to create epoll descriptor"));
87 wxLogTrace(wxEpollDispatcher_Trace
,
88 wxT("Epoll fd %d created"), epollDescriptor
);
89 return new wxEpollDispatcher(epollDescriptor
);
92 wxEpollDispatcher::wxEpollDispatcher(int epollDescriptor
)
94 wxASSERT_MSG( epollDescriptor
!= -1, wxT("invalid descriptor") );
96 m_epollDescriptor
= epollDescriptor
;
99 wxEpollDispatcher::~wxEpollDispatcher()
101 if ( close(m_epollDescriptor
) != 0 )
103 wxLogSysError(_("Error closing epoll descriptor"));
107 bool wxEpollDispatcher::RegisterFD(int fd
, wxFDIOHandler
* handler
, int flags
)
110 ev
.events
= GetEpollMask(flags
, fd
);
111 ev
.data
.ptr
= handler
;
113 const int ret
= epoll_ctl(m_epollDescriptor
, EPOLL_CTL_ADD
, fd
, &ev
);
116 wxLogSysError(_("Failed to add descriptor %d to epoll descriptor %d"),
117 fd
, m_epollDescriptor
);
121 wxLogTrace(wxEpollDispatcher_Trace
,
122 wxT("Added fd %d (handler %p) to epoll %d"), fd
, handler
, m_epollDescriptor
);
127 bool wxEpollDispatcher::ModifyFD(int fd
, wxFDIOHandler
* handler
, int flags
)
130 ev
.events
= GetEpollMask(flags
, fd
);
131 ev
.data
.ptr
= handler
;
133 const int ret
= epoll_ctl(m_epollDescriptor
, EPOLL_CTL_MOD
, fd
, &ev
);
136 wxLogSysError(_("Failed to modify descriptor %d in epoll descriptor %d"),
137 fd
, m_epollDescriptor
);
142 wxLogTrace(wxEpollDispatcher_Trace
,
143 wxT("Modified fd %d (handler: %p) on epoll %d"), fd
, handler
, m_epollDescriptor
);
147 bool wxEpollDispatcher::UnregisterFD(int fd
)
153 if ( epoll_ctl(m_epollDescriptor
, EPOLL_CTL_DEL
, fd
, &ev
) != 0 )
155 wxLogSysError(_("Failed to unregister descriptor %d from epoll descriptor %d"),
156 fd
, m_epollDescriptor
);
158 wxLogTrace(wxEpollDispatcher_Trace
,
159 wxT("removed fd %d from %d"), fd
, m_epollDescriptor
);
164 wxEpollDispatcher::DoPoll(epoll_event
*events
, int numEvents
, int timeout
) const
166 // the code below relies on TIMEOUT_INFINITE being -1 so that we can pass
167 // timeout value directly to epoll_wait() which interprets -1 as meaning to
168 // wait forever and would need to be changed if the value of
169 // TIMEOUT_INFINITE ever changes
170 wxCOMPILE_TIME_ASSERT( TIMEOUT_INFINITE
== -1, UpdateThisCode
);
172 wxMilliClock_t timeEnd
;
174 timeEnd
= wxGetLocalTimeMillis();
179 rc
= epoll_wait(m_epollDescriptor
, events
, numEvents
, timeout
);
180 if ( rc
!= -1 || errno
!= EINTR
)
183 // we got interrupted, update the timeout and restart
186 timeout
= wxMilliClockToLong(timeEnd
- wxGetLocalTimeMillis());
195 bool wxEpollDispatcher::HasPending() const
199 // NB: it's not really clear if epoll_wait() can return a number greater
200 // than the number of events passed to it but just in case it can, use
201 // >= instead of == here, see #10397
202 return DoPoll(&event
, 1, 0) >= 1;
205 int wxEpollDispatcher::Dispatch(int timeout
)
207 epoll_event events
[16];
209 const int rc
= DoPoll(events
, WXSIZEOF(events
), timeout
);
213 wxLogSysError(_("Waiting for IO on epoll descriptor %d failed"),
219 for ( epoll_event
*p
= events
; p
< events
+ rc
; p
++ )
221 wxFDIOHandler
* const handler
= (wxFDIOHandler
*)(p
->data
.ptr
);
224 wxFAIL_MSG( wxT("NULL handler in epoll_event?") );
228 // note that for compatibility with wxSelectDispatcher we call
229 // OnReadWaiting() on EPOLLHUP as this is what epoll_wait() returns
230 // when the write end of a pipe is closed while with select() the
231 // remaining pipe end becomes ready for reading when this happens
232 if ( p
->events
& (EPOLLIN
| EPOLLHUP
) )
233 handler
->OnReadWaiting();
234 else if ( p
->events
& EPOLLOUT
)
235 handler
->OnWriteWaiting();
236 else if ( p
->events
& EPOLLERR
)
237 handler
->OnExceptionWaiting();
247 #endif // wxUSE_EPOLL_DISPATCHER