don't leak epoll descriptor
[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 #ifdef 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
35 #define wxEpollDispatcher_Trace wxT("epolldispatcher")
36
37 // ============================================================================
38 // implementation
39 // ============================================================================
40
41 // helper: return EPOLLxxx mask corresponding to the given flags (and also log
42 // debugging messages about it)
43 static uint32_t GetEpollMask(int flags, int fd)
44 {
45 uint32_t ep = 0;
46
47 if ( flags & wxFDIO_INPUT )
48 {
49 ep |= EPOLLIN;
50 wxLogTrace(wxEpollDispatcher_Trace,
51 _T("Registered fd %d for input events"), fd);
52 }
53
54 if ( flags & wxFDIO_OUTPUT )
55 {
56 ep |= EPOLLOUT;
57 wxLogTrace(wxEpollDispatcher_Trace,
58 _T("Registered fd %d for output events"), fd);
59 }
60
61 if ( flags & wxFDIO_EXCEPTION )
62 {
63 ep |= EPOLLERR | EPOLLHUP;
64 wxLogTrace(wxEpollDispatcher_Trace,
65 _T("Registered fd %d for exceptional events"), fd);
66 }
67
68 return ep;
69 }
70
71 // ----------------------------------------------------------------------------
72 // wxEpollDispatcher
73 // ----------------------------------------------------------------------------
74
75 /* static */
76 wxEpollDispatcher *wxEpollDispatcher::Create()
77 {
78 int epollDescriptor = epoll_create(1024);
79 if ( epollDescriptor == -1 )
80 {
81 wxLogSysError(_("Failed to create epoll descriptor"));
82 return NULL;
83 }
84
85 return new wxEpollDispatcher(epollDescriptor);
86 }
87
88 wxEpollDispatcher::wxEpollDispatcher(int epollDescriptor)
89 {
90 wxASSERT_MSG( epollDescriptor != -1, _T("invalid descriptor") );
91
92 m_epollDescriptor = epollDescriptor;
93 }
94
95 wxEpollDispatcher::~wxEpollDispatcher()
96 {
97 if ( close(m_epollDescriptor) != 0 )
98 {
99 wxLogSysError(_("Error closing epoll descriptor"));
100 }
101 }
102
103 bool wxEpollDispatcher::RegisterFD(int fd, wxFDIOHandler* handler, int flags)
104 {
105 epoll_event ev;
106 ev.events = GetEpollMask(flags, fd);
107 ev.data.ptr = handler;
108
109 const int ret = epoll_ctl(m_epollDescriptor, EPOLL_CTL_ADD, fd, &ev);
110 if ( ret != 0 )
111 {
112 wxLogSysError(_("Failed to add descriptor %d to epoll descriptor %d"),
113 fd, m_epollDescriptor);
114
115 return false;
116 }
117
118 return true;
119 }
120
121 bool wxEpollDispatcher::ModifyFD(int fd, wxFDIOHandler* handler, int flags)
122 {
123 epoll_event ev;
124 ev.events = GetEpollMask(flags, fd);
125 ev.data.ptr = handler;
126
127 const int ret = epoll_ctl(m_epollDescriptor, EPOLL_CTL_MOD, fd, &ev);
128 if ( ret != 0 )
129 {
130 wxLogSysError(_("Failed to modify descriptor %d in epoll descriptor %d"),
131 fd, m_epollDescriptor);
132
133 return false;
134 }
135
136 return true;
137 }
138
139 bool wxEpollDispatcher::UnregisterFD(int fd)
140 {
141 epoll_event ev;
142 ev.events = 0;
143 ev.data.ptr = NULL;
144
145 if ( epoll_ctl(m_epollDescriptor, EPOLL_CTL_DEL, fd, &ev) != 0 )
146 {
147 wxLogSysError(_("Failed to unregister descriptor %d from epoll descriptor %d"),
148 fd, m_epollDescriptor);
149 }
150
151 return true;
152 }
153
154 void wxEpollDispatcher::Dispatch(int timeout)
155 {
156 epoll_event events[16];
157
158 const int e_num = epoll_wait
159 (
160 m_epollDescriptor,
161 events,
162 WXSIZEOF(events),
163 timeout == TIMEOUT_INFINITE ? -1 : timeout
164 );
165
166 if ( e_num == -1 )
167 {
168 if ( errno != EINTR )
169 {
170 wxLogSysError(_("Waiting for IO on epoll descriptor %d failed"),
171 m_epollDescriptor);
172 return;
173 }
174 }
175
176 for ( epoll_event *p = events; p < events + e_num; p++ )
177 {
178 wxFDIOHandler * const handler = (wxFDIOHandler *)(p->data.ptr);
179 if ( !handler )
180 {
181 wxFAIL_MSG( _T("NULL handler in epoll_event?") );
182 continue;
183 }
184
185 if ( p->events & EPOLLIN )
186 handler->OnReadWaiting();
187 else if ( p->events & EPOLLOUT )
188 handler->OnWriteWaiting();
189 else if ( p->events & (EPOLLERR | EPOLLHUP) )
190 handler->OnExceptionWaiting();
191 }
192 }
193
194 #endif // wxUSE_EPOLL_DISPATCHER