X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/5e1eac149fc18f51d5a25ac00d957ccaad87b3fa..e87d78bb36f371d593137761158118fb09b69fa2:/src/unix/evtloopunix.cpp diff --git a/src/unix/evtloopunix.cpp b/src/unix/evtloopunix.cpp index c147a7651d..4b7d8fded1 100644 --- a/src/unix/evtloopunix.cpp +++ b/src/unix/evtloopunix.cpp @@ -5,6 +5,8 @@ // Created: 2007-05-07 // RCS-ID: $Id$ // Copyright: (c) 2006 Zork Lukasz Michalski +// (c) 2009, 2013 Vadim Zeitlin +// (c) 2013 Rob Bresalier // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// @@ -21,168 +23,198 @@ #if wxUSE_CONSOLE_EVENTLOOP +#include "wx/evtloop.h" + #ifndef WX_PRECOMP #include "wx/app.h" #include "wx/log.h" #endif -#include -#include "wx/evtloop.h" +#include "wx/apptrait.h" +#include "wx/scopedptr.h" #include "wx/thread.h" #include "wx/module.h" #include "wx/unix/private/timer.h" #include "wx/unix/private/epolldispatcher.h" +#include "wx/unix/private/wakeuppipe.h" #include "wx/private/selectdispatcher.h" +#include "wx/private/eventloopsourcesmanager.h" +#include "wx/private/fdioeventloopsourcehandler.h" +#include "wx/private/eventloopsourcesmanager.h" -#define TRACE_EVENTS _T("events") +#if wxUSE_EVENTLOOP_SOURCE + #include "wx/evtloopsrc.h" +#endif // wxUSE_EVENTLOOP_SOURCE // =========================================================================== -// wxEventLoop::PipeIOHandler implementation +// wxEventLoop implementation // =========================================================================== -// ---------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // initialization -// ---------------------------------------------------------------------------- +//----------------------------------------------------------------------------- -bool wxConsoleEventLoop::PipeIOHandler::Create() +wxConsoleEventLoop::wxConsoleEventLoop() { - if ( !m_pipe.Create() ) - { - wxLogError(_("Failed to create wake up pipe used by event loop.")); - return false; - } + // Be pessimistic initially and assume that we failed to initialize. + m_dispatcher = NULL; + m_wakeupPipe = NULL; + m_wakeupSource = NULL; + + // Create the pipe. + wxScopedPtr wakeupPipe(new wxWakeUpPipeMT); + const int pipeFD = wakeupPipe->GetReadFd(); + if ( pipeFD == wxPipe::INVALID_FD ) + return; - const int fdRead = GetReadFd(); + // And start monitoring it in our event loop. + m_wakeupSource = wxEventLoopBase::AddSourceForFD + ( + pipeFD, + wakeupPipe.get(), + wxFDIO_INPUT + ); - int flags = fcntl(fdRead, F_GETFL, 0); - if ( flags == -1 || fcntl(fdRead, F_SETFL, flags | O_NONBLOCK) == -1 ) - { - wxLogSysError(_("Failed to switch wake up pipe to non-blocking mode")); - return false; - } + if ( !m_wakeupSource ) + return; - wxLogTrace(TRACE_EVENTS, wxT("Wake up pipe (%d, %d) created"), - fdRead, m_pipe[wxPipe::Write]); + // This is a bit ugly but we know that AddSourceForFD() used the currently + // active dispatcher to register this source, so use the same one for our + // other operations. Of course, currently the dispatcher returned by + // wxFDIODispatcher::Get() is always the same one anyhow so it doesn't + // really matter, but if we started returning different things later, it + // would. + m_dispatcher = wxFDIODispatcher::Get(); - return true; + m_wakeupPipe = wakeupPipe.release(); } -// ---------------------------------------------------------------------------- -// wakeup handling -// ---------------------------------------------------------------------------- - -void wxConsoleEventLoop::PipeIOHandler::WakeUp() +wxConsoleEventLoop::~wxConsoleEventLoop() { - if ( write(m_pipe[wxPipe::Write], "s", 1) != 1 ) + if ( m_wakeupPipe ) { - // don't use wxLog here, we can be in another thread and this could - // result in dead locks - perror("write(wake up pipe)"); + delete m_wakeupSource; + + delete m_wakeupPipe; } } -void wxConsoleEventLoop::PipeIOHandler::OnReadWaiting() +//----------------------------------------------------------------------------- +// adding & removing sources +//----------------------------------------------------------------------------- + +#if wxUSE_EVENTLOOP_SOURCE + +class wxConsoleEventLoopSourcesManager : public wxEventLoopSourcesManagerBase { - // 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(), - // it could have been called several times) - char buf[4]; - for ( ;; ) +public: + wxEventLoopSource* AddSourceForFD( int fd, + wxEventLoopSourceHandler *handler, + int flags) { - const int size = read(GetReadFd(), buf, WXSIZEOF(buf)); + wxCHECK_MSG( fd != -1, NULL, "can't monitor invalid fd" ); - if ( size == 0 || (size == -1 && errno == EAGAIN) ) - { - // nothing left in the pipe (EAGAIN is expected for an FD with - // O_NONBLOCK) - break; - } + wxLogTrace(wxTRACE_EVT_SOURCE, + "Adding event loop source for fd=%d", fd); - if ( size == -1 ) - { - wxLogSysError(_("Failed to read from wake-up pipe")); + // we need a bridge to wxFDIODispatcher + // + // TODO: refactor the code so that only wxEventLoopSourceHandler is used + wxScopedPtr + fdioHandler(new wxFDIOEventLoopSourceHandler(handler)); - break; - } - } + if ( !wxFDIODispatcher::Get()->RegisterFD(fd, fdioHandler.get(), flags) ) + return NULL; - wxTheApp->ProcessPendingEvents(); -} + return new wxUnixEventLoopSource(wxFDIODispatcher::Get(), fdioHandler.release(), + fd, handler, flags); + } +}; -// =========================================================================== -// wxEventLoop implementation -// =========================================================================== +wxEventLoopSourcesManagerBase* wxAppTraits::GetEventLoopSourcesManager() +{ + static wxConsoleEventLoopSourcesManager s_eventLoopSourcesManager; -//----------------------------------------------------------------------------- -// initialization -//----------------------------------------------------------------------------- + return &s_eventLoopSourcesManager; +} -wxConsoleEventLoop::wxConsoleEventLoop() +wxUnixEventLoopSource::~wxUnixEventLoopSource() { - if ( !m_wakeupPipe.Create() ) - { - m_dispatcher = NULL; - return; - } + wxLogTrace(wxTRACE_EVT_SOURCE, + "Removing event loop source for fd=%d", m_fd); - m_dispatcher = wxFDIODispatcher::Get(); - if ( !m_dispatcher ) - return; + m_dispatcher->UnregisterFD(m_fd); - m_dispatcher->RegisterFD - ( - m_wakeupPipe.GetReadFd(), - &m_wakeupPipe, - wxFDIO_INPUT - ); + delete m_fdioHandler; } +#endif // wxUSE_EVENTLOOP_SOURCE + //----------------------------------------------------------------------------- // events dispatch and loop handling //----------------------------------------------------------------------------- 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() { - wxTheApp->ProcessPendingEvents(); - return true; -} + DispatchTimeout(static_cast( + wxFDIODispatcher::TIMEOUT_INFINITE)); -void wxConsoleEventLoop::WakeUp() -{ - m_wakeupPipe.WakeUp(); + return true; } -void wxConsoleEventLoop::OnNextIteration() +int wxConsoleEventLoop::DispatchTimeout(unsigned long timeout) { - // calculate the timeout until the next timer expiration - int timeout; - #if wxUSE_TIMER + // check if we need to decrease the timeout to account for a timer wxUsecClock_t nextTimer; if ( wxTimerScheduler::Get().GetNext(&nextTimer) ) { - // timeout is in ms - timeout = (nextTimer / 1000).ToLong(); + unsigned long timeUntilNextTimer = wxMilliClockToLong(nextTimer / 1000); + if ( timeUntilNextTimer < timeout ) + timeout = timeUntilNextTimer; } - else // no timers, we can block forever #endif // wxUSE_TIMER - { - timeout = wxFDIODispatcher::TIMEOUT_INFINITE; - } - m_dispatcher->RunLoop(timeout); + bool hadEvent = m_dispatcher->Dispatch(timeout) > 0; #if wxUSE_TIMER - wxTimerScheduler::Get().NotifyExpired(); -#endif + if ( wxTimerScheduler::Get().NotifyExpired() ) + hadEvent = true; +#endif // wxUSE_TIMER + + return hadEvent ? 1 : -1; +} + +void wxConsoleEventLoop::WakeUp() +{ + m_wakeupPipe->WakeUp(); +} +void wxConsoleEventLoop::OnNextIteration() +{ // call the signal handlers for any signals we caught recently wxTheApp->CheckSignal(); } + +wxEventLoopBase *wxConsoleAppTraits::CreateEventLoop() +{ + return new wxEventLoop(); +} + #endif // wxUSE_CONSOLE_EVENTLOOP