]> git.saurik.com Git - wxWidgets.git/blame - src/unix/epolldispatcher.cpp
Simplified event based Drag API for wxDataViewCtrl
[wxWidgets.git] / src / unix / epolldispatcher.cpp
CommitLineData
b46b1d59
VZ
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
9550ee98 22#if wxUSE_EPOLL_DISPATCHER
b46b1d59
VZ
23
24#include "wx/unix/private/epolldispatcher.h"
25#include "wx/unix/private.h"
e169ac81 26#include "wx/stopwatch.h"
b46b1d59 27
b5ef33b2
VS
28#ifndef WX_PRECOMP
29 #include "wx/log.h"
30 #include "wx/intl.h"
31#endif
32
b46b1d59
VZ
33#include <sys/epoll.h>
34#include <errno.h>
98883bca 35#include <unistd.h>
b46b1d59
VZ
36
37#define wxEpollDispatcher_Trace wxT("epolldispatcher")
38
b46b1d59
VZ
39// ============================================================================
40// implementation
41// ============================================================================
42
43// helper: return EPOLLxxx mask corresponding to the given flags (and also log
44// debugging messages about it)
e0d1fd7f 45static uint32_t GetEpollMask(int flags, int WXUNUSED_UNLESS_DEBUG(fd))
b46b1d59
VZ
46{
47 uint32_t ep = 0;
48
49 if ( flags & wxFDIO_INPUT )
50 {
51 ep |= EPOLLIN;
52 wxLogTrace(wxEpollDispatcher_Trace,
53 _T("Registered fd %d for input events"), fd);
54 }
55
56 if ( flags & wxFDIO_OUTPUT )
57 {
58 ep |= EPOLLOUT;
59 wxLogTrace(wxEpollDispatcher_Trace,
60 _T("Registered fd %d for output events"), fd);
61 }
62
63 if ( flags & wxFDIO_EXCEPTION )
64 {
65 ep |= EPOLLERR | EPOLLHUP;
66 wxLogTrace(wxEpollDispatcher_Trace,
67 _T("Registered fd %d for exceptional events"), fd);
68 }
69
70 return ep;
71}
72
73// ----------------------------------------------------------------------------
74// wxEpollDispatcher
75// ----------------------------------------------------------------------------
76
5e1eac14
VZ
77/* static */
78wxEpollDispatcher *wxEpollDispatcher::Create()
b46b1d59 79{
5e1eac14
VZ
80 int epollDescriptor = epoll_create(1024);
81 if ( epollDescriptor == -1 )
b46b1d59
VZ
82 {
83 wxLogSysError(_("Failed to create epoll descriptor"));
5e1eac14 84 return NULL;
b46b1d59 85 }
2804f77d
VZ
86 wxLogTrace(wxEpollDispatcher_Trace,
87 _T("Epoll fd %d created"), epollDescriptor);
5e1eac14
VZ
88 return new wxEpollDispatcher(epollDescriptor);
89}
90
91wxEpollDispatcher::wxEpollDispatcher(int epollDescriptor)
92{
93 wxASSERT_MSG( epollDescriptor != -1, _T("invalid descriptor") );
94
95 m_epollDescriptor = epollDescriptor;
b46b1d59
VZ
96}
97
d31a4a84
VZ
98wxEpollDispatcher::~wxEpollDispatcher()
99{
100 if ( close(m_epollDescriptor) != 0 )
101 {
102 wxLogSysError(_("Error closing epoll descriptor"));
103 }
104}
105
b46b1d59
VZ
106bool wxEpollDispatcher::RegisterFD(int fd, wxFDIOHandler* handler, int flags)
107{
b46b1d59
VZ
108 epoll_event ev;
109 ev.events = GetEpollMask(flags, fd);
110 ev.data.ptr = handler;
111
112 const int ret = epoll_ctl(m_epollDescriptor, EPOLL_CTL_ADD, fd, &ev);
113 if ( ret != 0 )
114 {
115 wxLogSysError(_("Failed to add descriptor %d to epoll descriptor %d"),
116 fd, m_epollDescriptor);
117
118 return false;
119 }
2804f77d
VZ
120 wxLogTrace(wxEpollDispatcher_Trace,
121 _T("Added fd %d (handler %p) to epoll %d"), fd, handler, m_epollDescriptor);
b46b1d59
VZ
122
123 return true;
124}
125
126bool wxEpollDispatcher::ModifyFD(int fd, wxFDIOHandler* handler, int flags)
127{
b46b1d59
VZ
128 epoll_event ev;
129 ev.events = GetEpollMask(flags, fd);
130 ev.data.ptr = handler;
131
132 const int ret = epoll_ctl(m_epollDescriptor, EPOLL_CTL_MOD, fd, &ev);
133 if ( ret != 0 )
134 {
135 wxLogSysError(_("Failed to modify descriptor %d in epoll descriptor %d"),
136 fd, m_epollDescriptor);
137
138 return false;
139 }
140
2804f77d
VZ
141 wxLogTrace(wxEpollDispatcher_Trace,
142 _T("Modified fd %d (handler: %p) on epoll %d"), fd, handler, m_epollDescriptor);
b46b1d59
VZ
143 return true;
144}
145
af57c51a 146bool wxEpollDispatcher::UnregisterFD(int fd)
b46b1d59 147{
b46b1d59
VZ
148 epoll_event ev;
149 ev.events = 0;
150 ev.data.ptr = NULL;
151
152 if ( epoll_ctl(m_epollDescriptor, EPOLL_CTL_DEL, fd, &ev) != 0 )
153 {
154 wxLogSysError(_("Failed to unregister descriptor %d from epoll descriptor %d"),
155 fd, m_epollDescriptor);
156 }
2804f77d
VZ
157 wxLogTrace(wxEpollDispatcher_Trace,
158 _T("removed fd %d from %d"), fd, m_epollDescriptor);
ad8d42f8 159 return true;
b46b1d59
VZ
160}
161
a12698ab
VZ
162int
163wxEpollDispatcher::DoPoll(epoll_event *events, int numEvents, int timeout) const
b46b1d59 164{
e169ac81
VZ
165 // the code below relies on TIMEOUT_INFINITE being -1 so that we can pass
166 // timeout value directly to epoll_wait() which interprets -1 as meaning to
167 // wait forever and would need to be changed if the value of
168 // TIMEOUT_INFINITE ever changes
169 wxCOMPILE_TIME_ASSERT( TIMEOUT_INFINITE == -1, UpdateThisCode );
b46b1d59 170
e169ac81 171 wxMilliClock_t timeEnd;
a12698ab 172 if ( timeout > 0 )
e169ac81
VZ
173 timeEnd = wxGetLocalTimeMillis();
174
175 int rc;
176 for ( ;; )
b46b1d59 177 {
a12698ab 178 rc = epoll_wait(m_epollDescriptor, events, numEvents, timeout);
e169ac81
VZ
179 if ( rc != -1 || errno != EINTR )
180 break;
181
182 // we got interrupted, update the timeout and restart
a12698ab
VZ
183 if ( timeout > 0 )
184 {
185 timeout = wxMilliClockToLong(timeEnd - wxGetLocalTimeMillis());
186 if ( timeout < 0 )
187 return 0;
188 }
e169ac81
VZ
189 }
190
a12698ab
VZ
191 return rc;
192}
193
194bool wxEpollDispatcher::HasPending() const
195{
196 epoll_event event;
a7132f4b
VZ
197
198 // NB: it's not really clear if epoll_wait() can return a number greater
199 // than the number of events passed to it but just in case it can, use
200 // >= instead of == here, see #10397
fa00c4e3 201 return DoPoll(&event, 1, 0) >= 1;
a12698ab
VZ
202}
203
204int wxEpollDispatcher::Dispatch(int timeout)
205{
206 epoll_event events[16];
207
208 const int rc = DoPoll(events, WXSIZEOF(events), timeout);
209
e169ac81
VZ
210 if ( rc == -1 )
211 {
212 wxLogSysError(_("Waiting for IO on epoll descriptor %d failed"),
213 m_epollDescriptor);
a12698ab 214 return -1;
b46b1d59
VZ
215 }
216
a12698ab 217 int numEvents = 0;
e169ac81 218 for ( epoll_event *p = events; p < events + rc; p++ )
b46b1d59
VZ
219 {
220 wxFDIOHandler * const handler = (wxFDIOHandler *)(p->data.ptr);
221 if ( !handler )
222 {
223 wxFAIL_MSG( _T("NULL handler in epoll_event?") );
224 continue;
225 }
226
1a781247
VZ
227 // note that for compatibility with wxSelectDispatcher we call
228 // OnReadWaiting() on EPOLLHUP as this is what epoll_wait() returns
229 // when the write end of a pipe is closed while with select() the
230 // remaining pipe end becomes ready for reading when this happens
231 if ( p->events & (EPOLLIN | EPOLLHUP) )
b46b1d59 232 handler->OnReadWaiting();
7523de90 233 else if ( p->events & EPOLLOUT )
b46b1d59 234 handler->OnWriteWaiting();
1a781247 235 else if ( p->events & EPOLLERR )
b46b1d59 236 handler->OnExceptionWaiting();
5a557d1e
VZ
237 else
238 continue;
239
a12698ab 240 numEvents++;
b46b1d59 241 }
5a557d1e 242
a12698ab 243 return numEvents;
b46b1d59
VZ
244}
245
a1873279 246#endif // wxUSE_EPOLL_DISPATCHER