call OnReadWaiting(), not OnExceptionWaiting(), when we receive EPOLLHUP
[wxWidgets.git] / src / unix / epolldispatcher.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/epolldispatcher.cpp
3 // Purpose: implements dispatcher for epoll_wait() call
4 // Author: Lukasz Michalski
5 // Created: April 2007
6 // RCS-ID: $Id$
7 // Copyright: (c) 2007 Lukasz Michalski
8 // License: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
10
11 // ============================================================================
12 // declarations
13 // ============================================================================
14
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18
19 // for compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
21
22 #if wxUSE_EPOLL_DISPATCHER
23
24 #include "wx/unix/private/epolldispatcher.h"
25 #include "wx/unix/private.h"
26
27 #ifndef WX_PRECOMP
28 #include "wx/log.h"
29 #include "wx/intl.h"
30 #endif
31
32 #include <sys/epoll.h>
33 #include <errno.h>
34 #include <unistd.h>
35
36 #define wxEpollDispatcher_Trace wxT("epolldispatcher")
37
38 // ============================================================================
39 // implementation
40 // ============================================================================
41
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 WXUNUSED_UNLESS_DEBUG(fd))
45 {
46 uint32_t ep = 0;
47
48 if ( flags & wxFDIO_INPUT )
49 {
50 ep |= EPOLLIN;
51 wxLogTrace(wxEpollDispatcher_Trace,
52 _T("Registered fd %d for input events"), fd);
53 }
54
55 if ( flags & wxFDIO_OUTPUT )
56 {
57 ep |= EPOLLOUT;
58 wxLogTrace(wxEpollDispatcher_Trace,
59 _T("Registered fd %d for output events"), fd);
60 }
61
62 if ( flags & wxFDIO_EXCEPTION )
63 {
64 ep |= EPOLLERR | EPOLLHUP;
65 wxLogTrace(wxEpollDispatcher_Trace,
66 _T("Registered fd %d for exceptional events"), fd);
67 }
68
69 return ep;
70 }
71
72 // ----------------------------------------------------------------------------
73 // wxEpollDispatcher
74 // ----------------------------------------------------------------------------
75
76 /* static */
77 wxEpollDispatcher *wxEpollDispatcher::Create()
78 {
79 int epollDescriptor = epoll_create(1024);
80 if ( epollDescriptor == -1 )
81 {
82 wxLogSysError(_("Failed to create epoll descriptor"));
83 return NULL;
84 }
85 wxLogTrace(wxEpollDispatcher_Trace,
86 _T("Epoll fd %d created"), epollDescriptor);
87 return new wxEpollDispatcher(epollDescriptor);
88 }
89
90 wxEpollDispatcher::wxEpollDispatcher(int epollDescriptor)
91 {
92 wxASSERT_MSG( epollDescriptor != -1, _T("invalid descriptor") );
93
94 m_epollDescriptor = epollDescriptor;
95 }
96
97 wxEpollDispatcher::~wxEpollDispatcher()
98 {
99 if ( close(m_epollDescriptor) != 0 )
100 {
101 wxLogSysError(_("Error closing epoll descriptor"));
102 }
103 }
104
105 bool wxEpollDispatcher::RegisterFD(int fd, wxFDIOHandler* handler, int flags)
106 {
107 epoll_event ev;
108 ev.events = GetEpollMask(flags, fd);
109 ev.data.ptr = handler;
110
111 const int ret = epoll_ctl(m_epollDescriptor, EPOLL_CTL_ADD, fd, &ev);
112 if ( ret != 0 )
113 {
114 wxLogSysError(_("Failed to add descriptor %d to epoll descriptor %d"),
115 fd, m_epollDescriptor);
116
117 return false;
118 }
119 wxLogTrace(wxEpollDispatcher_Trace,
120 _T("Added fd %d (handler %p) to epoll %d"), fd, handler, m_epollDescriptor);
121
122 return true;
123 }
124
125 bool wxEpollDispatcher::ModifyFD(int fd, wxFDIOHandler* handler, int flags)
126 {
127 epoll_event ev;
128 ev.events = GetEpollMask(flags, fd);
129 ev.data.ptr = handler;
130
131 const int ret = epoll_ctl(m_epollDescriptor, EPOLL_CTL_MOD, fd, &ev);
132 if ( ret != 0 )
133 {
134 wxLogSysError(_("Failed to modify descriptor %d in epoll descriptor %d"),
135 fd, m_epollDescriptor);
136
137 return false;
138 }
139
140 wxLogTrace(wxEpollDispatcher_Trace,
141 _T("Modified fd %d (handler: %p) on epoll %d"), fd, handler, m_epollDescriptor);
142 return true;
143 }
144
145 bool wxEpollDispatcher::UnregisterFD(int fd)
146 {
147 epoll_event ev;
148 ev.events = 0;
149 ev.data.ptr = NULL;
150
151 if ( epoll_ctl(m_epollDescriptor, EPOLL_CTL_DEL, fd, &ev) != 0 )
152 {
153 wxLogSysError(_("Failed to unregister descriptor %d from epoll descriptor %d"),
154 fd, m_epollDescriptor);
155 }
156 wxLogTrace(wxEpollDispatcher_Trace,
157 _T("removed fd %d from %d"), fd, m_epollDescriptor);
158 return true;
159 }
160
161 void wxEpollDispatcher::Dispatch(int timeout)
162 {
163 epoll_event events[16];
164
165 const int e_num = epoll_wait
166 (
167 m_epollDescriptor,
168 events,
169 WXSIZEOF(events),
170 timeout == TIMEOUT_INFINITE ? -1 : timeout
171 );
172
173 if ( e_num == -1 )
174 {
175 if ( errno != EINTR )
176 {
177 wxLogSysError(_("Waiting for IO on epoll descriptor %d failed"),
178 m_epollDescriptor);
179 return;
180 }
181 }
182
183 for ( epoll_event *p = events; p < events + e_num; p++ )
184 {
185 wxFDIOHandler * const handler = (wxFDIOHandler *)(p->data.ptr);
186 if ( !handler )
187 {
188 wxFAIL_MSG( _T("NULL handler in epoll_event?") );
189 continue;
190 }
191
192 // note that for compatibility with wxSelectDispatcher we call
193 // OnReadWaiting() on EPOLLHUP as this is what epoll_wait() returns
194 // when the write end of a pipe is closed while with select() the
195 // remaining pipe end becomes ready for reading when this happens
196 if ( p->events & (EPOLLIN | EPOLLHUP) )
197 handler->OnReadWaiting();
198 else if ( p->events & EPOLLOUT )
199 handler->OnWriteWaiting();
200 else if ( p->events & EPOLLERR )
201 handler->OnExceptionWaiting();
202 }
203 }
204
205 #endif // wxUSE_EPOLL_DISPATCHER