1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/unix/evtloopunix.cpp 
   3 // Purpose:     wxEventLoop implementation 
   4 // Author:      Lukasz Michalski (lm@zork.pl) 
   7 // Copyright:   (c) 2006 Zork Lukasz Michalski 
   8 // Licence:     wxWindows licence 
   9 ///////////////////////////////////////////////////////////////////////////// 
  11 // =========================================================================== 
  13 // =========================================================================== 
  15 // --------------------------------------------------------------------------- 
  17 // --------------------------------------------------------------------------- 
  19 // For compilers that support precompilation, includes "wx.h". 
  20 #include "wx/wxprec.h" 
  22 #if wxUSE_CONSOLE_EVENTLOOP 
  24 #include "wx/evtloop.h" 
  32 #include "wx/apptrait.h" 
  33 #include "wx/scopedptr.h" 
  34 #include "wx/thread.h" 
  35 #include "wx/module.h" 
  36 #include "wx/unix/pipe.h" 
  37 #include "wx/unix/private/timer.h" 
  38 #include "wx/unix/private/epolldispatcher.h" 
  39 #include "wx/private/selectdispatcher.h" 
  41 #if wxUSE_EVENTLOOP_SOURCE 
  42     #include "wx/evtloopsrc.h" 
  43 #endif // wxUSE_EVENTLOOP_SOURCE 
  45 #define TRACE_EVENTS wxT("events") 
  47 // =========================================================================== 
  48 // wxEventLoop::PipeIOHandler implementation 
  49 // =========================================================================== 
  54 // pipe used for wake up messages: when a child thread wants to wake up 
  55 // the event loop in the main thread it writes to this pipe 
  56 class PipeIOHandler 
: public wxFDIOHandler
 
  59     // default ctor does nothing, call Create() to really initialize the 
  65     // this method can be, and normally is, called from another thread 
  68     int GetReadFd() { return m_pipe
[wxPipe::Read
]; } 
  70     // implement wxFDIOHandler pure virtual methods 
  71     virtual void OnReadWaiting(); 
  72     virtual void OnWriteWaiting() { } 
  73     virtual void OnExceptionWaiting() { } 
  79 // ---------------------------------------------------------------------------- 
  81 // ---------------------------------------------------------------------------- 
  83 bool PipeIOHandler::Create() 
  85     if ( !m_pipe
.Create() ) 
  87         wxLogError(_("Failed to create wake up pipe used by event loop.")); 
  91     if ( !m_pipe
.MakeNonBlocking(wxPipe::Read
) ) 
  93         wxLogSysError(_("Failed to switch wake up pipe to non-blocking mode")); 
  97     wxLogTrace(TRACE_EVENTS
, wxT("Wake up pipe (%d, %d) created"), 
  98                m_pipe
[wxPipe::Read
], m_pipe
[wxPipe::Write
]); 
 103 // ---------------------------------------------------------------------------- 
 105 // ---------------------------------------------------------------------------- 
 107 void PipeIOHandler::WakeUp() 
 109     if ( write(m_pipe
[wxPipe::Write
], "s", 1) != 1 ) 
 111         // don't use wxLog here, we can be in another thread and this could 
 112         // result in dead locks 
 113         perror("write(wake up pipe)"); 
 117 void PipeIOHandler::OnReadWaiting() 
 119     // got wakeup from child thread: read all data available in pipe just to 
 120     // make it empty (even though we write one byte at a time from WakeUp(), 
 121     // it could have been called several times) 
 125         const int size 
= read(GetReadFd(), buf
, WXSIZEOF(buf
)); 
 127         if ( size 
== 0 || (size 
== -1 && (errno 
== EAGAIN 
|| errno 
== EINTR
)) ) 
 129             // nothing left in the pipe (EAGAIN is expected for an FD with 
 136             wxLogSysError(_("Failed to read from wake-up pipe")); 
 142     // writing to the wake up pipe will make wxConsoleEventLoop return from 
 143     // wxFDIODispatcher::Dispatch() it might be currently blocking in, nothing 
 144     // else needs to be done 
 147 } // namespace wxPrivate 
 149 // =========================================================================== 
 150 // wxEventLoop implementation 
 151 // =========================================================================== 
 153 //----------------------------------------------------------------------------- 
 155 //----------------------------------------------------------------------------- 
 157 wxConsoleEventLoop::wxConsoleEventLoop() 
 159     m_wakeupPipe 
= new wxPrivate::PipeIOHandler(); 
 160     if ( !m_wakeupPipe
->Create() ) 
 162         wxDELETE(m_wakeupPipe
); 
 167     m_dispatcher 
= wxFDIODispatcher::Get(); 
 171     m_dispatcher
->RegisterFD
 
 173                     m_wakeupPipe
->GetReadFd(), 
 179 wxConsoleEventLoop::~wxConsoleEventLoop() 
 185             m_dispatcher
->UnregisterFD(m_wakeupPipe
->GetReadFd()); 
 192 //----------------------------------------------------------------------------- 
 193 // adding & removing sources 
 194 //----------------------------------------------------------------------------- 
 196 #if wxUSE_EVENTLOOP_SOURCE 
 198 // This class is a temporary bridge between event loop sources and 
 199 // FDIODispatcher. It is going to be removed soon, when all subject interfaces 
 201 class wxFDIOEventLoopSourceHandler 
: public wxFDIOHandler
 
 204     wxFDIOEventLoopSourceHandler(wxEventLoopSourceHandler
* handler
) : 
 207     virtual void OnReadWaiting() 
 209         m_impl
->OnReadWaiting(); 
 211     virtual void OnWriteWaiting() 
 213         m_impl
->OnWriteWaiting(); 
 216     virtual void OnExceptionWaiting() 
 218         m_impl
->OnExceptionWaiting(); 
 222     wxEventLoopSourceHandler
* m_impl
; 
 226 wxConsoleEventLoop::AddSourceForFD(int fd
, 
 227                                    wxEventLoopSourceHandler 
*handler
, 
 230     wxCHECK_MSG( fd 
!= -1, NULL
, "can't monitor invalid fd" ); 
 232     wxLogTrace(wxTRACE_EVT_SOURCE
, 
 233                 "Adding event loop source for fd=%d", fd
); 
 235     // we need a bridge to wxFDIODispatcher 
 237     // TODO: refactor the code so that only wxEventLoopSourceHandler is used 
 238     wxScopedPtr
<wxFDIOHandler
> 
 239         fdioHandler(new wxFDIOEventLoopSourceHandler(handler
)); 
 241     if ( !m_dispatcher
->RegisterFD(fd
, fdioHandler
.get(), flags
) ) 
 244     return new wxUnixEventLoopSource(m_dispatcher
, fdioHandler
.release(), 
 248 wxUnixEventLoopSource::~wxUnixEventLoopSource() 
 250     wxLogTrace(wxTRACE_EVT_SOURCE
, 
 251                "Removing event loop source for fd=%d", m_fd
); 
 253     m_dispatcher
->UnregisterFD(m_fd
); 
 255     delete m_fdioHandler
; 
 258 #endif // wxUSE_EVENTLOOP_SOURCE 
 260 //----------------------------------------------------------------------------- 
 261 // events dispatch and loop handling 
 262 //----------------------------------------------------------------------------- 
 264 bool wxConsoleEventLoop::Pending() const 
 266     if ( m_dispatcher
->HasPending() ) 
 270     wxUsecClock_t nextTimer
; 
 271     if ( wxTimerScheduler::Get().GetNext(&nextTimer
) && 
 272             !wxMilliClockToLong(nextTimer
) ) 
 274 #endif // wxUSE_TIMER 
 279 bool wxConsoleEventLoop::Dispatch() 
 281     DispatchTimeout(static_cast<unsigned long>( 
 282         wxFDIODispatcher::TIMEOUT_INFINITE
)); 
 287 int wxConsoleEventLoop::DispatchTimeout(unsigned long timeout
) 
 290     // check if we need to decrease the timeout to account for a timer 
 291     wxUsecClock_t nextTimer
; 
 292     if ( wxTimerScheduler::Get().GetNext(&nextTimer
) ) 
 294         unsigned long timeUntilNextTimer 
= wxMilliClockToLong(nextTimer 
/ 1000); 
 295         if ( timeUntilNextTimer 
< timeout 
) 
 296             timeout 
= timeUntilNextTimer
; 
 298 #endif // wxUSE_TIMER 
 300     bool hadEvent 
= m_dispatcher
->Dispatch(timeout
) > 0; 
 303     if ( wxTimerScheduler::Get().NotifyExpired() ) 
 305 #endif // wxUSE_TIMER 
 307     return hadEvent 
? 1 : -1; 
 310 void wxConsoleEventLoop::WakeUp() 
 312     m_wakeupPipe
->WakeUp(); 
 315 void wxConsoleEventLoop::OnNextIteration() 
 317     // call the signal handlers for any signals we caught recently 
 318     wxTheApp
->CheckSignal(); 
 322 wxEventLoopBase 
*wxConsoleAppTraits::CreateEventLoop() 
 324     return new wxEventLoop(); 
 327 #endif // wxUSE_CONSOLE_EVENTLOOP