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/thread.h"
34 #include "wx/module.h"
35 #include "wx/unix/pipe.h"
36 #include "wx/unix/private/timer.h"
37 #include "wx/unix/private/epolldispatcher.h"
38 #include "wx/private/selectdispatcher.h"
40 #define TRACE_EVENTS wxT("events")
42 // ===========================================================================
43 // wxEventLoop::PipeIOHandler implementation
44 // ===========================================================================
49 // pipe used for wake up messages: when a child thread wants to wake up
50 // the event loop in the main thread it writes to this pipe
51 class PipeIOHandler
: public wxFDIOHandler
54 // default ctor does nothing, call Create() to really initialize the
60 // this method can be, and normally is, called from another thread
63 int GetReadFd() { return m_pipe
[wxPipe::Read
]; }
65 // implement wxFDIOHandler pure virtual methods
66 virtual void OnReadWaiting();
67 virtual void OnWriteWaiting() { }
68 virtual void OnExceptionWaiting() { }
74 // ----------------------------------------------------------------------------
76 // ----------------------------------------------------------------------------
78 bool PipeIOHandler::Create()
80 if ( !m_pipe
.Create() )
82 wxLogError(_("Failed to create wake up pipe used by event loop."));
86 const int fdRead
= GetReadFd();
88 int flags
= fcntl(fdRead
, F_GETFL
, 0);
89 if ( flags
== -1 || fcntl(fdRead
, F_SETFL
, flags
| O_NONBLOCK
) == -1 )
91 wxLogSysError(_("Failed to switch wake up pipe to non-blocking mode"));
95 wxLogTrace(TRACE_EVENTS
, wxT("Wake up pipe (%d, %d) created"),
96 fdRead
, m_pipe
[wxPipe::Write
]);
101 // ----------------------------------------------------------------------------
103 // ----------------------------------------------------------------------------
105 void PipeIOHandler::WakeUp()
107 if ( write(m_pipe
[wxPipe::Write
], "s", 1) != 1 )
109 // don't use wxLog here, we can be in another thread and this could
110 // result in dead locks
111 perror("write(wake up pipe)");
115 void PipeIOHandler::OnReadWaiting()
117 // got wakeup from child thread: read all data available in pipe just to
118 // make it empty (even though we write one byte at a time from WakeUp(),
119 // it could have been called several times)
123 const int size
= read(GetReadFd(), buf
, WXSIZEOF(buf
));
125 if ( size
== 0 || (size
== -1 && (errno
== EAGAIN
|| errno
== EINTR
)) )
127 // nothing left in the pipe (EAGAIN is expected for an FD with
134 wxLogSysError(_("Failed to read from wake-up pipe"));
140 // writing to the wake up pipe will make wxConsoleEventLoop return from
141 // wxFDIODispatcher::Dispatch() it might be currently blocking in, nothing
142 // else needs to be done
145 } // namespace wxPrivate
147 // ===========================================================================
148 // wxEventLoop implementation
149 // ===========================================================================
151 //-----------------------------------------------------------------------------
153 //-----------------------------------------------------------------------------
155 wxConsoleEventLoop::wxConsoleEventLoop()
157 m_wakeupPipe
= new wxPrivate::PipeIOHandler();
158 if ( !m_wakeupPipe
->Create() )
160 wxDELETE(m_wakeupPipe
);
165 m_dispatcher
= wxFDIODispatcher::Get();
169 m_dispatcher
->RegisterFD
171 m_wakeupPipe
->GetReadFd(),
177 wxConsoleEventLoop::~wxConsoleEventLoop()
183 m_dispatcher
->UnregisterFD(m_wakeupPipe
->GetReadFd());
190 //-----------------------------------------------------------------------------
191 // adding & removing sources
192 //-----------------------------------------------------------------------------
194 #if wxUSE_EVENTLOOP_SOURCE
196 // This class is a temporary bridge between event loop sources and
197 // FDIODispatcher. It is going to be removed soon, when all subject interfaces
199 class wxFDIOEventLoopSourceHandler
: public wxFDIOHandler
202 wxFDIOEventLoopSourceHandler(wxEventLoopSourceHandler
* handler
) :
205 virtual void OnReadWaiting()
207 m_impl
->OnReadWaiting();
209 virtual void OnWriteWaiting()
211 m_impl
->OnWriteWaiting();
214 virtual void OnExceptionWaiting()
216 m_impl
->OnExceptionWaiting();
220 wxEventLoopSourceHandler
* m_impl
;
223 bool wxConsoleEventLoop::DoAddSource(wxAbstractEventLoopSource
* src
)
225 Source
* source
= dynamic_cast<Source
*>(src
);
226 wxCHECK_MSG( source
, false, "Invalid source type" );
228 wxLogTrace(wxTRACE_EVT_SOURCE
,
229 "wxConsoleEventLoop::AddSource() source=%d",
230 source
->GetResource());
232 // translating into wxFDIOHandler
233 // XXX this is a memory leak of course, but this is really temporary, so
234 // we are not creating another map of handlers
235 wxFDIOHandler
* h
= new wxFDIOEventLoopSourceHandler(source
->GetHandler());
237 return m_dispatcher
->RegisterFD(source
->GetResource(), h
,
241 bool wxConsoleEventLoop::DoRemoveSource(wxAbstractEventLoopSource
* src
)
243 Source
* source
= dynamic_cast<Source
*>(src
);
244 wxCHECK_MSG( source
, false, "Invalid source type" );
246 wxLogTrace(wxTRACE_EVT_SOURCE
,
247 "wxConsoleEventLoop::RemoveSource() source=%d",
248 source
->GetResource());
250 return m_dispatcher
->UnregisterFD(source
->GetResource());
254 //-----------------------------------------------------------------------------
255 // events dispatch and loop handling
256 //-----------------------------------------------------------------------------
258 bool wxConsoleEventLoop::Pending() const
260 if ( m_dispatcher
->HasPending() )
264 wxUsecClock_t nextTimer
;
265 if ( wxTimerScheduler::Get().GetNext(&nextTimer
) &&
266 !wxMilliClockToLong(nextTimer
) )
268 #endif // wxUSE_TIMER
273 bool wxConsoleEventLoop::Dispatch()
275 DispatchTimeout(static_cast<unsigned long>(
276 wxFDIODispatcher::TIMEOUT_INFINITE
));
281 int wxConsoleEventLoop::DispatchTimeout(unsigned long timeout
)
284 // check if we need to decrease the timeout to account for a timer
285 wxUsecClock_t nextTimer
;
286 if ( wxTimerScheduler::Get().GetNext(&nextTimer
) )
288 unsigned long timeUntilNextTimer
= wxMilliClockToLong(nextTimer
/ 1000);
289 if ( timeUntilNextTimer
< timeout
)
290 timeout
= timeUntilNextTimer
;
292 #endif // wxUSE_TIMER
294 bool hadEvent
= m_dispatcher
->Dispatch(timeout
) > 0;
297 if ( wxTimerScheduler::Get().NotifyExpired() )
299 #endif // wxUSE_TIMER
301 return hadEvent
? 1 : -1;
304 void wxConsoleEventLoop::WakeUp()
306 m_wakeupPipe
->WakeUp();
309 void wxConsoleEventLoop::OnNextIteration()
311 // call the signal handlers for any signals we caught recently
312 wxTheApp
->CheckSignal();
316 wxEventLoopBase
*wxConsoleAppTraits::CreateEventLoop()
318 return new wxEventLoop();
321 #endif // wxUSE_CONSOLE_EVENTLOOP