// unregister descriptor previously registered with RegisterFD()
virtual bool UnregisterFD(int fd) = 0;
+ // check if any events are currently available without dispatching them
+ virtual bool HasPending() const = 0;
+
// wait for an event for at most timeout milliseconds and process it;
- // return true if we processed any events or false if timeout expired
- // without anything happening
- virtual bool Dispatch(int timeout = TIMEOUT_INFINITE) = 0;
+ // return the number of events processed (possibly 0 if timeout expired) or
+ // -1 if an error occurred
+ virtual int Dispatch(int timeout = TIMEOUT_INFINITE) = 0;
virtual ~wxFDIODispatcher() { }
};
// select() itself
int Select(int nfds, struct timeval *tv);
- // call the handler methods corresponding to the sets having this fd
- void Handle(int fd, wxFDIOHandler& handler) const;
+ // call the handler methods corresponding to the sets having this fd if it
+ // is present in any set and return true if it is
+ bool Handle(int fd, wxFDIOHandler& handler) const;
private:
typedef void (wxFDIOHandler::*Callback)();
virtual bool RegisterFD(int fd, wxFDIOHandler *handler, int flags = wxFDIO_ALL);
virtual bool ModifyFD(int fd, wxFDIOHandler *handler, int flags = wxFDIO_ALL);
virtual bool UnregisterFD(int fd);
- virtual bool Dispatch(int timeout = TIMEOUT_INFINITE);
+ virtual bool HasPending() const;
+ virtual int Dispatch(int timeout = TIMEOUT_INFINITE);
private:
// common part of RegisterFD() and ModifyFD()
bool DoUpdateFDAndHandler(int fd, wxFDIOHandler *handler, int flags);
- // call the handlers for the fds present in the given sets, return true if
- // we called any handlers
- bool ProcessSets(const wxSelectSets& sets);
+ // call the handlers for the fds present in the given sets, return the
+ // number of handlers we called
+ int ProcessSets(const wxSelectSets& sets);
// helper of ProcessSets(): call the handler if its fd is in the set
void DoProcessFD(int fd, const fd_set& fds, wxFDIOHandler *handler,
const char *name);
+ // common part of HasPending() and Dispatch(): calls select() with the
+ // specified timeout
+ int DoSelect(wxSelectSets& sets, int timeout) const;
+
// the select sets containing all the registered fds
wxSelectSets m_sets;
#include "wx/private/fdiodispatcher.h"
+struct epoll_event;
+
class WXDLLIMPEXP_CORE wxEpollDispatcher : public wxFDIODispatcher
{
public:
virtual bool RegisterFD(int fd, wxFDIOHandler* handler, int flags = wxFDIO_ALL);
virtual bool ModifyFD(int fd, wxFDIOHandler* handler, int flags = wxFDIO_ALL);
virtual bool UnregisterFD(int fd);
- virtual bool Dispatch(int timeout = TIMEOUT_INFINITE);
+ virtual bool HasPending() const;
+ virtual int Dispatch(int timeout = TIMEOUT_INFINITE);
private:
// ctor is private, use Create()
wxEpollDispatcher(int epollDescriptor);
+ // common part of HasPending() and Dispatch(): calls epoll_wait() with the
+ // given timeout
+ int DoPoll(epoll_event *events, int numEvents, int timeout) const;
+
+
int m_epollDescriptor;
};
return select(nfds, &m_fds[Read], &m_fds[Write], &m_fds[Except], tv);
}
-void wxSelectSets::Handle(int fd, wxFDIOHandler& handler) const
+bool wxSelectSets::Handle(int fd, wxFDIOHandler& handler) const
{
for ( int n = 0; n < Max; n++ )
{
(handler.*ms_handlers[n])();
// callback can modify sets and destroy handler
// this forces that one event can be processed at one time
- return;
+ return true;
}
}
+
+ return false;
}
// ----------------------------------------------------------------------------
return true;
}
-bool wxSelectDispatcher::ProcessSets(const wxSelectSets& sets)
+int wxSelectDispatcher::ProcessSets(const wxSelectSets& sets)
{
- bool gotEvent = false;
+ int numEvents = 0;
for ( int fd = 0; fd <= m_maxFD; fd++ )
{
if ( !sets.HasFD(fd) )
continue;
}
- gotEvent = true;
-
- sets.Handle(fd, *handler);
+ if ( sets.Handle(fd, *handler) )
+ numEvents++;
}
- return gotEvent;
+ return numEvents;
}
-bool wxSelectDispatcher::Dispatch(int timeout)
+int wxSelectDispatcher::DoSelect(wxSelectSets& sets, int timeout) const
{
struct timeval tv,
*ptv;
ptv = NULL;
}
- wxSelectSets sets = m_sets;
+ int ret = sets.Select(m_maxFD + 1, ptv);
- const int ret = sets.Select(m_maxFD + 1, ptv);
- switch ( ret )
+ // TODO: we need to restart select() in this case but for now just return
+ // as if timeout expired
+ if ( ret == -1 && errno == EINTR )
+ ret = 0;
+
+ return ret;
+}
+
+bool wxSelectDispatcher::HasPending() const
+{
+ wxSelectSets sets(m_sets);
+ return DoSelect(sets, 0) > 0;
+}
+
+int wxSelectDispatcher::Dispatch(int timeout)
+{
+ wxSelectSets sets(m_sets);
+ switch ( DoSelect(sets, timeout) )
{
case -1:
- if ( errno != EINTR )
- {
- wxLogSysError(_("Failed to monitor I/O channels"));
- }
- break;
+ wxLogSysError(_("Failed to monitor I/O channels"));
+ return -1;
case 0:
// timeout expired without anything happening
- break;
+ return 0;
default:
- if ( ProcessSets(sets) )
- return true;
+ return ProcessSets(sets);
}
-
- // nothing happened
- return false;
}
#endif // wxUSE_SELECT_DISPATCHER
return true;
}
-bool wxEpollDispatcher::Dispatch(int timeout)
+int
+wxEpollDispatcher::DoPoll(epoll_event *events, int numEvents, int timeout) const
{
- epoll_event events[16];
-
// the code below relies on TIMEOUT_INFINITE being -1 so that we can pass
// timeout value directly to epoll_wait() which interprets -1 as meaning to
// wait forever and would need to be changed if the value of
wxCOMPILE_TIME_ASSERT( TIMEOUT_INFINITE == -1, UpdateThisCode );
wxMilliClock_t timeEnd;
- if ( timeout != -1 )
+ if ( timeout > 0 )
timeEnd = wxGetLocalTimeMillis();
int rc;
for ( ;; )
{
- rc = epoll_wait(m_epollDescriptor, events, WXSIZEOF(events), timeout);
+ rc = epoll_wait(m_epollDescriptor, events, numEvents, timeout);
if ( rc != -1 || errno != EINTR )
break;
// we got interrupted, update the timeout and restart
- if ( timeout == -1 )
- continue;
-
- timeout = wxMilliClockToLong(timeEnd - wxGetLocalTimeMillis());
- if ( timeout < 0 )
- return false;
+ if ( timeout > 0 )
+ {
+ timeout = wxMilliClockToLong(timeEnd - wxGetLocalTimeMillis());
+ if ( timeout < 0 )
+ return 0;
+ }
}
+ return rc;
+}
+
+bool wxEpollDispatcher::HasPending() const
+{
+ epoll_event event;
+ return DoPoll(&event, 1, 0) == 1;
+}
+
+int wxEpollDispatcher::Dispatch(int timeout)
+{
+ epoll_event events[16];
+
+ const int rc = DoPoll(events, WXSIZEOF(events), timeout);
+
if ( rc == -1 )
{
wxLogSysError(_("Waiting for IO on epoll descriptor %d failed"),
m_epollDescriptor);
- return false;
+ return -1;
}
- bool gotEvents = false;
+ int numEvents = 0;
for ( epoll_event *p = events; p < events + rc; p++ )
{
wxFDIOHandler * const handler = (wxFDIOHandler *)(p->data.ptr);
else
continue;
- gotEvents = true;
+ numEvents++;
}
- return gotEvents;
+ return numEvents;
}
#endif // wxUSE_EPOLL_DISPATCHER
void wxConsoleEventLoop::PipeIOHandler::OnReadWaiting()
{
// got wakeup from child thread: read all data available in pipe just to
- // make it empty (evevn though we write one byte at a time from WakeUp(),
+ // make it empty (even though we write one byte at a time from WakeUp(),
// it could have been called several times)
char buf[4];
for ( ;; )
}
}
- wxTheApp->ProcessPendingEvents();
+ // writing to the wake up pipe will make wxConsoleEventLoop return from
+ // wxFDIODispatcher::Dispatch() it might be currently blocking in, nothing
+ // else needs to be done
}
// ===========================================================================
bool wxConsoleEventLoop::Pending() const
{
- return wxTheApp->HasPendingEvents();
+ if ( m_dispatcher->HasPending() )
+ return true;
+
+#if wxUSE_TIMER
+ wxUsecClock_t nextTimer;
+ if ( wxTimerScheduler::Get().GetNext(&nextTimer) &&
+ !wxMilliClockToLong(nextTimer) )
+ return true;
+#endif // wxUSE_TIMER
+
+ return false;
}
bool wxConsoleEventLoop::Dispatch()
}
#endif // wxUSE_TIMER
- bool hadEvent = m_dispatcher->Dispatch(timeout);
+ bool hadEvent = m_dispatcher->Dispatch(timeout) > 0;
#if wxUSE_TIMER
if ( wxTimerScheduler::Get().NotifyExpired() )