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 const int fdRead
= GetReadFd();
93 int flags
= fcntl(fdRead
, F_GETFL
, 0);
94 if ( flags
== -1 || fcntl(fdRead
, F_SETFL
, flags
| O_NONBLOCK
) == -1 )
96 wxLogSysError(_("Failed to switch wake up pipe to non-blocking mode"));
100 wxLogTrace(TRACE_EVENTS
, wxT("Wake up pipe (%d, %d) created"),
101 fdRead
, m_pipe
[wxPipe::Write
]);
106 // ----------------------------------------------------------------------------
108 // ----------------------------------------------------------------------------
110 void PipeIOHandler::WakeUp()
112 if ( write(m_pipe
[wxPipe::Write
], "s", 1) != 1 )
114 // don't use wxLog here, we can be in another thread and this could
115 // result in dead locks
116 perror("write(wake up pipe)");
120 void PipeIOHandler::OnReadWaiting()
122 // got wakeup from child thread: read all data available in pipe just to
123 // make it empty (even though we write one byte at a time from WakeUp(),
124 // it could have been called several times)
128 const int size
= read(GetReadFd(), buf
, WXSIZEOF(buf
));
130 if ( size
== 0 || (size
== -1 && (errno
== EAGAIN
|| errno
== EINTR
)) )
132 // nothing left in the pipe (EAGAIN is expected for an FD with
139 wxLogSysError(_("Failed to read from wake-up pipe"));
145 // writing to the wake up pipe will make wxConsoleEventLoop return from
146 // wxFDIODispatcher::Dispatch() it might be currently blocking in, nothing
147 // else needs to be done
150 } // namespace wxPrivate
152 // ===========================================================================
153 // wxEventLoop implementation
154 // ===========================================================================
156 //-----------------------------------------------------------------------------
158 //-----------------------------------------------------------------------------
160 wxConsoleEventLoop::wxConsoleEventLoop()
162 m_wakeupPipe
= new wxPrivate::PipeIOHandler();
163 if ( !m_wakeupPipe
->Create() )
165 wxDELETE(m_wakeupPipe
);
170 m_dispatcher
= wxFDIODispatcher::Get();
174 m_dispatcher
->RegisterFD
176 m_wakeupPipe
->GetReadFd(),
182 wxConsoleEventLoop::~wxConsoleEventLoop()
188 m_dispatcher
->UnregisterFD(m_wakeupPipe
->GetReadFd());
195 //-----------------------------------------------------------------------------
196 // adding & removing sources
197 //-----------------------------------------------------------------------------
199 #if wxUSE_EVENTLOOP_SOURCE
201 // This class is a temporary bridge between event loop sources and
202 // FDIODispatcher. It is going to be removed soon, when all subject interfaces
204 class wxFDIOEventLoopSourceHandler
: public wxFDIOHandler
207 wxFDIOEventLoopSourceHandler(wxEventLoopSourceHandler
* handler
) :
210 virtual void OnReadWaiting()
212 m_impl
->OnReadWaiting();
214 virtual void OnWriteWaiting()
216 m_impl
->OnWriteWaiting();
219 virtual void OnExceptionWaiting()
221 m_impl
->OnExceptionWaiting();
225 wxEventLoopSourceHandler
* m_impl
;
229 wxConsoleEventLoop::AddSourceForFD(int fd
,
230 wxEventLoopSourceHandler
*handler
,
233 wxCHECK_MSG( fd
!= -1, NULL
, "can't monitor invalid fd" );
235 wxLogTrace(wxTRACE_EVT_SOURCE
,
236 "Adding event loop source for fd=%d", fd
);
238 // we need a bridge to wxFDIODispatcher
240 // TODO: refactor the code so that only wxEventLoopSourceHandler is used
241 wxScopedPtr
<wxFDIOHandler
>
242 fdioHandler(new wxFDIOEventLoopSourceHandler(handler
));
244 if ( !m_dispatcher
->RegisterFD(fd
, fdioHandler
.get(), flags
) )
247 return new wxUnixEventLoopSource(m_dispatcher
, fdioHandler
.release(),
251 wxUnixEventLoopSource::~wxUnixEventLoopSource()
253 wxLogTrace(wxTRACE_EVT_SOURCE
,
254 "Removing event loop source for fd=%d", m_fd
);
256 m_dispatcher
->UnregisterFD(m_fd
);
258 delete m_fdioHandler
;
261 #endif // wxUSE_EVENTLOOP_SOURCE
263 //-----------------------------------------------------------------------------
264 // events dispatch and loop handling
265 //-----------------------------------------------------------------------------
267 bool wxConsoleEventLoop::Pending() const
269 if ( m_dispatcher
->HasPending() )
273 wxUsecClock_t nextTimer
;
274 if ( wxTimerScheduler::Get().GetNext(&nextTimer
) &&
275 !wxMilliClockToLong(nextTimer
) )
277 #endif // wxUSE_TIMER
282 bool wxConsoleEventLoop::Dispatch()
284 DispatchTimeout(static_cast<unsigned long>(
285 wxFDIODispatcher::TIMEOUT_INFINITE
));
290 int wxConsoleEventLoop::DispatchTimeout(unsigned long timeout
)
293 // check if we need to decrease the timeout to account for a timer
294 wxUsecClock_t nextTimer
;
295 if ( wxTimerScheduler::Get().GetNext(&nextTimer
) )
297 unsigned long timeUntilNextTimer
= wxMilliClockToLong(nextTimer
/ 1000);
298 if ( timeUntilNextTimer
< timeout
)
299 timeout
= timeUntilNextTimer
;
301 #endif // wxUSE_TIMER
303 bool hadEvent
= m_dispatcher
->Dispatch(timeout
) > 0;
306 if ( wxTimerScheduler::Get().NotifyExpired() )
308 #endif // wxUSE_TIMER
310 return hadEvent
? 1 : -1;
313 void wxConsoleEventLoop::WakeUp()
315 m_wakeupPipe
->WakeUp();
318 void wxConsoleEventLoop::OnNextIteration()
320 // call the signal handlers for any signals we caught recently
321 wxTheApp
->CheckSignal();
325 wxEventLoopBase
*wxConsoleAppTraits::CreateEventLoop()
327 return new wxEventLoop();
330 #endif // wxUSE_CONSOLE_EVENTLOOP