~brian-sidebotham/wxwidgets-cmake/wxpython-2.9.4

« back to all changes in this revision

Viewing changes to src/unix/epolldispatcher.cpp

  • Committer: Brian Sidebotham
  • Date: 2013-08-03 14:30:08 UTC
  • Revision ID: brian.sidebotham@gmail.com-20130803143008-c7806tkych1tp6fc
Initial import into Bazaar

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
///////////////////////////////////////////////////////////////////////////////
 
2
// Name:        src/unix/epolldispatcher.cpp
 
3
// Purpose:     implements dispatcher for epoll_wait() call
 
4
// Author:      Lukasz Michalski
 
5
// Created:     April 2007
 
6
// RCS-ID:      $Id: epolldispatcher.cpp 67254 2011-03-20 00:14:35Z DS $
 
7
// Copyright:   (c) 2007 Lukasz Michalski
 
8
// Licence:     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
#include "wx/stopwatch.h"
 
27
 
 
28
#ifndef WX_PRECOMP
 
29
    #include "wx/log.h"
 
30
    #include "wx/intl.h"
 
31
#endif
 
32
 
 
33
#include <sys/epoll.h>
 
34
#include <errno.h>
 
35
#include <unistd.h>
 
36
 
 
37
#define wxEpollDispatcher_Trace wxT("epolldispatcher")
 
38
 
 
39
// ============================================================================
 
40
// implementation
 
41
// ============================================================================
 
42
 
 
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)
 
46
{
 
47
    wxUnusedVar(fd); // unused if wxLogTrace() disabled
 
48
 
 
49
    uint32_t ep = 0;
 
50
 
 
51
    if ( flags & wxFDIO_INPUT )
 
52
    {
 
53
        ep |= EPOLLIN;
 
54
        wxLogTrace(wxEpollDispatcher_Trace,
 
55
                   wxT("Registered fd %d for input events"), fd);
 
56
    }
 
57
 
 
58
    if ( flags & wxFDIO_OUTPUT )
 
59
    {
 
60
        ep |= EPOLLOUT;
 
61
        wxLogTrace(wxEpollDispatcher_Trace,
 
62
                   wxT("Registered fd %d for output events"), fd);
 
63
    }
 
64
 
 
65
    if ( flags & wxFDIO_EXCEPTION )
 
66
    {
 
67
        ep |= EPOLLERR | EPOLLHUP;
 
68
        wxLogTrace(wxEpollDispatcher_Trace,
 
69
                   wxT("Registered fd %d for exceptional events"), fd);
 
70
    }
 
71
 
 
72
    return ep;
 
73
}
 
74
 
 
75
// ----------------------------------------------------------------------------
 
76
// wxEpollDispatcher
 
77
// ----------------------------------------------------------------------------
 
78
 
 
79
/* static */
 
80
wxEpollDispatcher *wxEpollDispatcher::Create()
 
81
{
 
82
    int epollDescriptor = epoll_create(1024);
 
83
    if ( epollDescriptor == -1 )
 
84
    {
 
85
        wxLogSysError(_("Failed to create epoll descriptor"));
 
86
        return NULL;
 
87
    }
 
88
    wxLogTrace(wxEpollDispatcher_Trace,
 
89
                   wxT("Epoll fd %d created"), epollDescriptor);
 
90
    return new wxEpollDispatcher(epollDescriptor);
 
91
}
 
92
 
 
93
wxEpollDispatcher::wxEpollDispatcher(int epollDescriptor)
 
94
{
 
95
    wxASSERT_MSG( epollDescriptor != -1, wxT("invalid descriptor") );
 
96
 
 
97
    m_epollDescriptor = epollDescriptor;
 
98
}
 
99
 
 
100
wxEpollDispatcher::~wxEpollDispatcher()
 
101
{
 
102
    if ( close(m_epollDescriptor) != 0 )
 
103
    {
 
104
        wxLogSysError(_("Error closing epoll descriptor"));
 
105
    }
 
106
}
 
107
 
 
108
bool wxEpollDispatcher::RegisterFD(int fd, wxFDIOHandler* handler, int flags)
 
109
{
 
110
    epoll_event ev;
 
111
    ev.events = GetEpollMask(flags, fd);
 
112
    ev.data.ptr = handler;
 
113
 
 
114
    const int ret = epoll_ctl(m_epollDescriptor, EPOLL_CTL_ADD, fd, &ev);
 
115
    if ( ret != 0 )
 
116
    {
 
117
        wxLogSysError(_("Failed to add descriptor %d to epoll descriptor %d"),
 
118
                      fd, m_epollDescriptor);
 
119
 
 
120
        return false;
 
121
    }
 
122
    wxLogTrace(wxEpollDispatcher_Trace,
 
123
               wxT("Added fd %d (handler %p) to epoll %d"), fd, handler, m_epollDescriptor);
 
124
 
 
125
    return true;
 
126
}
 
127
 
 
128
bool wxEpollDispatcher::ModifyFD(int fd, wxFDIOHandler* handler, int flags)
 
129
{
 
130
    epoll_event ev;
 
131
    ev.events = GetEpollMask(flags, fd);
 
132
    ev.data.ptr = handler;
 
133
 
 
134
    const int ret = epoll_ctl(m_epollDescriptor, EPOLL_CTL_MOD, fd, &ev);
 
135
    if ( ret != 0 )
 
136
    {
 
137
        wxLogSysError(_("Failed to modify descriptor %d in epoll descriptor %d"),
 
138
                      fd, m_epollDescriptor);
 
139
 
 
140
        return false;
 
141
    }
 
142
 
 
143
    wxLogTrace(wxEpollDispatcher_Trace,
 
144
                wxT("Modified fd %d (handler: %p) on epoll %d"), fd, handler, m_epollDescriptor);
 
145
    return true;
 
146
}
 
147
 
 
148
bool wxEpollDispatcher::UnregisterFD(int fd)
 
149
{
 
150
    epoll_event ev;
 
151
    ev.events = 0;
 
152
    ev.data.ptr = NULL;
 
153
 
 
154
    if ( epoll_ctl(m_epollDescriptor, EPOLL_CTL_DEL, fd, &ev) != 0 )
 
155
    {
 
156
        wxLogSysError(_("Failed to unregister descriptor %d from epoll descriptor %d"),
 
157
                      fd, m_epollDescriptor);
 
158
    }
 
159
    wxLogTrace(wxEpollDispatcher_Trace,
 
160
                wxT("removed fd %d from %d"), fd, m_epollDescriptor);
 
161
    return true;
 
162
}
 
163
 
 
164
int
 
165
wxEpollDispatcher::DoPoll(epoll_event *events, int numEvents, int timeout) const
 
166
{
 
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 );
 
172
 
 
173
    wxMilliClock_t timeEnd;
 
174
    if ( timeout > 0 )
 
175
        timeEnd = wxGetLocalTimeMillis();
 
176
 
 
177
    int rc;
 
178
    for ( ;; )
 
179
    {
 
180
        rc = epoll_wait(m_epollDescriptor, events, numEvents, timeout);
 
181
        if ( rc != -1 || errno != EINTR )
 
182
            break;
 
183
 
 
184
        // we got interrupted, update the timeout and restart
 
185
        if ( timeout > 0 )
 
186
        {
 
187
            timeout = wxMilliClockToLong(timeEnd - wxGetLocalTimeMillis());
 
188
            if ( timeout < 0 )
 
189
                return 0;
 
190
        }
 
191
    }
 
192
 
 
193
    return rc;
 
194
}
 
195
 
 
196
bool wxEpollDispatcher::HasPending() const
 
197
{
 
198
    epoll_event event;
 
199
 
 
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;
 
204
}
 
205
 
 
206
int wxEpollDispatcher::Dispatch(int timeout)
 
207
{
 
208
    epoll_event events[16];
 
209
 
 
210
    const int rc = DoPoll(events, WXSIZEOF(events), timeout);
 
211
 
 
212
    if ( rc == -1 )
 
213
    {
 
214
        wxLogSysError(_("Waiting for IO on epoll descriptor %d failed"),
 
215
                      m_epollDescriptor);
 
216
        return -1;
 
217
    }
 
218
 
 
219
    int numEvents = 0;
 
220
    for ( epoll_event *p = events; p < events + rc; p++ )
 
221
    {
 
222
        wxFDIOHandler * const handler = (wxFDIOHandler *)(p->data.ptr);
 
223
        if ( !handler )
 
224
        {
 
225
            wxFAIL_MSG( wxT("NULL handler in epoll_event?") );
 
226
            continue;
 
227
        }
 
228
 
 
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();
 
239
        else
 
240
            continue;
 
241
 
 
242
        numEvents++;
 
243
    }
 
244
 
 
245
    return numEvents;
 
246
}
 
247
 
 
248
#endif // wxUSE_EPOLL_DISPATCHER