X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/c4239f1920f34dd26e30550bbc7e7d3e6f3f2926..6f026b5b63fe7ccb025e84509886f74772b9df13:/src/unix/evtloopunix.cpp diff --git a/src/unix/evtloopunix.cpp b/src/unix/evtloopunix.cpp index a4f67ecad6..daeac691d1 100644 --- a/src/unix/evtloopunix.cpp +++ b/src/unix/evtloopunix.cpp @@ -3,8 +3,9 @@ // Purpose: wxEventLoop implementation // Author: Lukasz Michalski (lm@zork.pl) // 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 ///////////////////////////////////////////////////////////////////////////// @@ -28,161 +29,22 @@ #include "wx/log.h" #endif -#include #include "wx/apptrait.h" #include "wx/scopedptr.h" #include "wx/thread.h" #include "wx/module.h" -#include "wx/unix/pipe.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" #if wxUSE_EVENTLOOP_SOURCE #include "wx/evtloopsrc.h" #endif // wxUSE_EVENTLOOP_SOURCE -#define TRACE_EVENTS wxT("events") - -// =========================================================================== -// wxEventLoop::PipeIOHandler implementation -// =========================================================================== - -namespace wxPrivate -{ - -// pipe used for wake up messages: when a child thread wants to wake up -// the event loop in the main thread it writes to this pipe -class PipeIOHandler : public wxFDIOHandler -{ -public: - // default ctor does nothing, call Create() to really initialize the - // object - PipeIOHandler() : m_pipeIsEmpty(true) { } - - bool Create(); - - // this method can be, and normally is, called from another thread - void WakeUp(); - - int GetReadFd() { return m_pipe[wxPipe::Read]; } - - // implement wxFDIOHandler pure virtual methods - virtual void OnReadWaiting(); - virtual void OnWriteWaiting() { } - virtual void OnExceptionWaiting() { } - -private: - wxPipe m_pipe; - - // Protects access to m_pipeIsEmpty. - wxCriticalSection m_pipeLock; - - // This flag is set to true after writing to the pipe and reset to false - // after reading from it in the main thread. Having it allows us to avoid - // overflowing the pipe with too many writes if the main thread can't keep - // up with reading from it. - bool m_pipeIsEmpty; -}; - -// ---------------------------------------------------------------------------- -// initialization -// ---------------------------------------------------------------------------- - -bool PipeIOHandler::Create() -{ - if ( !m_pipe.Create() ) - { - wxLogError(_("Failed to create wake up pipe used by event loop.")); - return false; - } - - - if ( !m_pipe.MakeNonBlocking(wxPipe::Read) ) - { - wxLogSysError(_("Failed to switch wake up pipe to non-blocking mode")); - return false; - } - - wxLogTrace(TRACE_EVENTS, wxT("Wake up pipe (%d, %d) created"), - m_pipe[wxPipe::Read], m_pipe[wxPipe::Write]); - - return true; -} - -// ---------------------------------------------------------------------------- -// wakeup handling -// ---------------------------------------------------------------------------- - -void PipeIOHandler::WakeUp() -{ - wxCriticalSectionLocker lock(m_pipeLock); - - // No need to do anything if the pipe already contains something. - if ( !m_pipeIsEmpty ) - return; - - if ( write(m_pipe[wxPipe::Write], "s", 1) != 1 ) - { - // don't use wxLog here, we can be in another thread and this could - // result in dead locks - perror("write(wake up pipe)"); - } - else - { - // We just wrote to it, so it's not empty any more. - m_pipeIsEmpty = false; - } -} - -void PipeIOHandler::OnReadWaiting() -{ - // got wakeup from child thread, remove the data that provoked it from the - // pipe - - wxCriticalSectionLocker lock(m_pipeLock); - - char buf[4]; - for ( ;; ) - { - const int size = read(GetReadFd(), buf, WXSIZEOF(buf)); - - if ( size > 0 ) - { - wxASSERT_MSG( size == 1, "Too many writes to wake-up pipe?" ); - - break; - } - - if ( size == 0 || (size == -1 && errno == EAGAIN) ) - { - // No data available, not an error (but still surprising, - // spurious wakeup?) - break; - } - - if ( errno == EINTR ) - { - // We were interrupted, try again. - continue; - } - - wxLogSysError(_("Failed to read from wake-up pipe")); - - return; - } - - // The pipe is empty now, so future calls to WakeUp() would need to write - // to it again. - m_pipeIsEmpty = true; - - // 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 -} - -} // namespace wxPrivate - // =========================================================================== // wxEventLoop implementation // =========================================================================== @@ -193,34 +55,44 @@ void PipeIOHandler::OnReadWaiting() wxConsoleEventLoop::wxConsoleEventLoop() { - m_wakeupPipe = new wxPrivate::PipeIOHandler(); - if ( !m_wakeupPipe->Create() ) - { - wxDELETE(m_wakeupPipe); - m_dispatcher = NULL; + // 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; - } - m_dispatcher = wxFDIODispatcher::Get(); - if ( !m_dispatcher ) + // And start monitoring it in our event loop. + m_wakeupSource = wxEventLoopBase::AddSourceForFD + ( + pipeFD, + wakeupPipe.get(), + wxFDIO_INPUT + ); + + if ( !m_wakeupSource ) return; - m_dispatcher->RegisterFD - ( - m_wakeupPipe->GetReadFd(), - m_wakeupPipe, - wxFDIO_INPUT - ); + // 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(); + + m_wakeupPipe = wakeupPipe.release(); } wxConsoleEventLoop::~wxConsoleEventLoop() { if ( m_wakeupPipe ) { - if ( m_dispatcher ) - { - m_dispatcher->UnregisterFD(m_wakeupPipe->GetReadFd()); - } + delete m_wakeupSource; delete m_wakeupPipe; } @@ -232,54 +104,37 @@ wxConsoleEventLoop::~wxConsoleEventLoop() #if wxUSE_EVENTLOOP_SOURCE -// This class is a temporary bridge between event loop sources and -// FDIODispatcher. It is going to be removed soon, when all subject interfaces -// are modified -class wxFDIOEventLoopSourceHandler : public wxFDIOHandler +class wxConsoleEventLoopSourcesManager : public wxEventLoopSourcesManagerBase { public: - wxFDIOEventLoopSourceHandler(wxEventLoopSourceHandler* handler) : - m_impl(handler) { } - - virtual void OnReadWaiting() + wxEventLoopSource* AddSourceForFD( int fd, + wxEventLoopSourceHandler *handler, + int flags) { - m_impl->OnReadWaiting(); - } - virtual void OnWriteWaiting() - { - m_impl->OnWriteWaiting(); - } + wxCHECK_MSG( fd != -1, NULL, "can't monitor invalid fd" ); - virtual void OnExceptionWaiting() - { - m_impl->OnExceptionWaiting(); - } + wxLogTrace(wxTRACE_EVT_SOURCE, + "Adding event loop source for fd=%d", fd); -protected: - wxEventLoopSourceHandler* m_impl; -}; + // we need a bridge to wxFDIODispatcher + // + // TODO: refactor the code so that only wxEventLoopSourceHandler is used + wxScopedPtr + fdioHandler(new wxFDIOEventLoopSourceHandler(handler)); -wxEventLoopSource * -wxConsoleEventLoop::AddSourceForFD(int fd, - wxEventLoopSourceHandler *handler, - int flags) -{ - wxCHECK_MSG( fd != -1, NULL, "can't monitor invalid fd" ); + if ( !wxFDIODispatcher::Get()->RegisterFD(fd, fdioHandler.get(), flags) ) + return NULL; - wxLogTrace(wxTRACE_EVT_SOURCE, - "Adding event loop source for fd=%d", fd); - - // we need a bridge to wxFDIODispatcher - // - // TODO: refactor the code so that only wxEventLoopSourceHandler is used - wxScopedPtr - fdioHandler(new wxFDIOEventLoopSourceHandler(handler)); + return new wxUnixEventLoopSource(wxFDIODispatcher::Get(), fdioHandler.release(), + fd, handler, flags); + } +}; - if ( !m_dispatcher->RegisterFD(fd, fdioHandler.get(), flags) ) - return NULL; +wxEventLoopSourcesManagerBase* wxAppTraits::GetEventLoopSourcesManager() +{ + static wxConsoleEventLoopSourcesManager s_eventLoopSourcesManager; - return new wxUnixEventLoopSource(m_dispatcher, fdioHandler.release(), - fd, handler, flags); + return &s_eventLoopSourcesManager; } wxUnixEventLoopSource::~wxUnixEventLoopSource()