Revert "Revert using an event object for waking up event loop in wxMSW"
This reverts commitebb3a791b9
, effectively reapplying6c40531fb7
once again. This breaks wake up when not running our own event loop once again (see #17579), but this will be fixed in the next commit.
This commit is contained in:
@@ -53,7 +53,6 @@ public:
|
|||||||
// override/implement base class virtuals
|
// override/implement base class virtuals
|
||||||
virtual bool Dispatch() wxOVERRIDE;
|
virtual bool Dispatch() wxOVERRIDE;
|
||||||
virtual int DispatchTimeout(unsigned long timeout) wxOVERRIDE;
|
virtual int DispatchTimeout(unsigned long timeout) wxOVERRIDE;
|
||||||
virtual void WakeUp() wxOVERRIDE;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void OnNextIteration() wxOVERRIDE;
|
virtual void OnNextIteration() wxOVERRIDE;
|
||||||
|
@@ -15,9 +15,20 @@ class WXDLLIMPEXP_BASE wxMSWEventLoopBase : public wxEventLoopManual
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
wxMSWEventLoopBase();
|
wxMSWEventLoopBase();
|
||||||
|
virtual ~wxMSWEventLoopBase();
|
||||||
|
|
||||||
// implement base class pure virtuals
|
// implement base class pure virtuals
|
||||||
virtual bool Pending() const wxOVERRIDE;
|
virtual bool Pending() const wxOVERRIDE;
|
||||||
|
virtual void WakeUp() wxOVERRIDE;
|
||||||
|
|
||||||
|
#if wxUSE_THREADS
|
||||||
|
// MSW-specific method to wait for the termination of the specified (by its
|
||||||
|
// native handle) thread or any input message arriving (in GUI case).
|
||||||
|
//
|
||||||
|
// Return value is WAIT_OBJECT_0 if the thread terminated, WAIT_OBJECT_0+1
|
||||||
|
// if a message arrived with anything else indicating an error.
|
||||||
|
WXDWORD MSWWaitForThread(WXHANDLE hThread);
|
||||||
|
#endif // wxUSE_THREADS
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// get the next message from queue and return true or return false if we
|
// get the next message from queue and return true or return false if we
|
||||||
@@ -25,8 +36,13 @@ protected:
|
|||||||
bool GetNextMessage(WXMSG *msg);
|
bool GetNextMessage(WXMSG *msg);
|
||||||
|
|
||||||
// same as above but with a timeout and return value can be -1 meaning that
|
// same as above but with a timeout and return value can be -1 meaning that
|
||||||
// time out expired in addition to
|
// time out expired in addition to true/false
|
||||||
int GetNextMessageTimeout(WXMSG *msg, unsigned long timeout);
|
int GetNextMessageTimeout(WXMSG *msg, unsigned long timeout);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// An auto-reset Win32 event which is signalled when we need to wake up the
|
||||||
|
// main thread waiting in GetNextMessage[Timeout]().
|
||||||
|
WXHANDLE m_heventWake;
|
||||||
};
|
};
|
||||||
|
|
||||||
#if wxUSE_CONSOLE_EVENTLOOP
|
#if wxUSE_CONSOLE_EVENTLOOP
|
||||||
@@ -39,7 +55,6 @@ public:
|
|||||||
// override/implement base class virtuals
|
// override/implement base class virtuals
|
||||||
virtual bool Dispatch() wxOVERRIDE;
|
virtual bool Dispatch() wxOVERRIDE;
|
||||||
virtual int DispatchTimeout(unsigned long timeout) wxOVERRIDE;
|
virtual int DispatchTimeout(unsigned long timeout) wxOVERRIDE;
|
||||||
virtual void WakeUp() wxOVERRIDE;
|
|
||||||
|
|
||||||
// Windows-specific function to process a single message
|
// Windows-specific function to process a single message
|
||||||
virtual void ProcessMessage(WXMSG *msg);
|
virtual void ProcessMessage(WXMSG *msg);
|
||||||
|
@@ -248,23 +248,16 @@ WXDWORD wxGUIAppTraits::WaitForThread(WXHANDLE hThread, int flags)
|
|||||||
// have a running event loop as we would never remove them from the message
|
// have a running event loop as we would never remove them from the message
|
||||||
// queue then and so we would enter an infinite loop as
|
// queue then and so we would enter an infinite loop as
|
||||||
// MsgWaitForMultipleObjects() keeps returning WAIT_OBJECT_0 + 1.
|
// MsgWaitForMultipleObjects() keeps returning WAIT_OBJECT_0 + 1.
|
||||||
if ( flags == wxTHREAD_WAIT_BLOCK ||
|
if ( flags == wxTHREAD_WAIT_YIELD && wxIsMainThread() )
|
||||||
!wxIsMainThread() ||
|
|
||||||
!wxEventLoop::GetActive() )
|
|
||||||
{
|
{
|
||||||
// Simple blocking wait.
|
wxMSWEventLoopBase* const
|
||||||
return DoSimpleWaitForThread(hThread);
|
evtLoop = static_cast<wxMSWEventLoopBase *>(wxEventLoop::GetActive());
|
||||||
|
if ( evtLoop )
|
||||||
|
return evtLoop->MSWWaitForThread(hThread);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ::MsgWaitForMultipleObjects
|
// Simple blocking wait.
|
||||||
(
|
return DoSimpleWaitForThread(hThread);
|
||||||
1, // number of objects to wait for
|
|
||||||
(HANDLE *)&hThread, // the objects
|
|
||||||
false, // wait for any objects, not all
|
|
||||||
INFINITE, // no timeout
|
|
||||||
QS_ALLINPUT | // return as soon as there are any events
|
|
||||||
QS_ALLPOSTMESSAGE
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
#endif // wxUSE_THREADS
|
#endif // wxUSE_THREADS
|
||||||
|
|
||||||
@@ -785,42 +778,16 @@ void wxApp::OnIdle(wxIdleEvent& WXUNUSED(event))
|
|||||||
|
|
||||||
void wxApp::WakeUpIdle()
|
void wxApp::WakeUpIdle()
|
||||||
{
|
{
|
||||||
// Send the top window a dummy message so idle handler processing will
|
wxEventLoopBase * const evtLoop = wxEventLoop::GetActive();
|
||||||
// start up again. Doing it this way ensures that the idle handler
|
if ( !evtLoop )
|
||||||
// wakes up in the right thread (see also wxWakeUpMainThread() which does
|
|
||||||
// the same for the main app thread only)
|
|
||||||
wxWindow * const topWindow = wxTheApp->GetTopWindow();
|
|
||||||
if ( topWindow )
|
|
||||||
{
|
{
|
||||||
HWND hwndTop = GetHwndOf(topWindow);
|
// We can't wake up the event loop if there is none and there is just
|
||||||
|
// no need to do anything in this case, any pending events will be
|
||||||
|
// handled when the event loop starts.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Do not post WM_NULL if there's already a pending WM_NULL to avoid
|
evtLoop->WakeUp();
|
||||||
// overflowing the message queue.
|
|
||||||
//
|
|
||||||
// Notice that due to a limitation of PeekMessage() API (which handles
|
|
||||||
// 0,0 range specially), we have to check the range from 0-1 instead.
|
|
||||||
// This still makes it possible to overflow the queue with WM_NULLs by
|
|
||||||
// interspersing the calles to WakeUpIdle() with windows creation but
|
|
||||||
// it should be rather hard to do it accidentally.
|
|
||||||
MSG msg;
|
|
||||||
if ( !::PeekMessage(&msg, hwndTop, 0, 1, PM_NOREMOVE) ||
|
|
||||||
::PeekMessage(&msg, hwndTop, 1, 1, PM_NOREMOVE) )
|
|
||||||
{
|
|
||||||
// If this fails too, there is really not much we can do, but then
|
|
||||||
// neither do we need to, as it normally indicates that the window
|
|
||||||
// queue is full to the brim with the messages and so the main loop
|
|
||||||
// is running and doesn't need to be woken up.
|
|
||||||
//
|
|
||||||
// Notice that we especially should not try use wxLogLastError()
|
|
||||||
// here as this would lead to another call to wxWakeUpIdle() from
|
|
||||||
// inside wxLog and stack overflow due to the resulting recursion.
|
|
||||||
::PostMessage(hwndTop, WM_NULL, 0, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#if wxUSE_THREADS
|
|
||||||
else
|
|
||||||
wxWakeUpMainThread();
|
|
||||||
#endif // wxUSE_THREADS
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@@ -248,11 +248,6 @@ void wxGUIEventLoop::OnNextIteration()
|
|||||||
#endif // wxUSE_THREADS
|
#endif // wxUSE_THREADS
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxGUIEventLoop::WakeUp()
|
|
||||||
{
|
|
||||||
::PostMessage(NULL, WM_NULL, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Yield to incoming messages
|
// Yield to incoming messages
|
||||||
|
@@ -42,6 +42,17 @@ wxMSWEventLoopBase::wxMSWEventLoopBase()
|
|||||||
{
|
{
|
||||||
m_shouldExit = false;
|
m_shouldExit = false;
|
||||||
m_exitcode = 0;
|
m_exitcode = 0;
|
||||||
|
|
||||||
|
// Create initially not signalled auto-reset event object.
|
||||||
|
m_heventWake = ::CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||||
|
if ( !m_heventWake )
|
||||||
|
wxLogLastError(wxS("CreateEvent(wake)"));
|
||||||
|
}
|
||||||
|
|
||||||
|
wxMSWEventLoopBase::~wxMSWEventLoopBase()
|
||||||
|
{
|
||||||
|
if ( m_heventWake && !::CloseHandle(m_heventWake) )
|
||||||
|
wxLogLastError(wxS("CloseHandle(wake)"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
@@ -54,26 +65,36 @@ bool wxMSWEventLoopBase::Pending() const
|
|||||||
return ::PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE) != 0;
|
return ::PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void wxMSWEventLoopBase::WakeUp()
|
||||||
|
{
|
||||||
|
if ( !::SetEvent(m_heventWake) )
|
||||||
|
wxLogLastError(wxS("SetEvent(wake)"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if wxUSE_THREADS
|
||||||
|
|
||||||
|
WXDWORD wxMSWEventLoopBase::MSWWaitForThread(WXHANDLE hThread)
|
||||||
|
{
|
||||||
|
// The order is important here, the code using this function assumes that
|
||||||
|
// WAIT_OBJECT_0 indicates the thread termination and anything else -- the
|
||||||
|
// availability of an input event. So the thread handle must come first.
|
||||||
|
HANDLE handles[2] = { hThread, m_heventWake };
|
||||||
|
return ::MsgWaitForMultipleObjects
|
||||||
|
(
|
||||||
|
WXSIZEOF(handles), // number of objects to wait for
|
||||||
|
handles, // the objects
|
||||||
|
false, // wait for any objects, not all
|
||||||
|
INFINITE, // no timeout
|
||||||
|
QS_ALLINPUT | // return as soon as there are any events
|
||||||
|
QS_ALLPOSTMESSAGE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // wxUSE_THREADS
|
||||||
|
|
||||||
bool wxMSWEventLoopBase::GetNextMessage(WXMSG* msg)
|
bool wxMSWEventLoopBase::GetNextMessage(WXMSG* msg)
|
||||||
{
|
{
|
||||||
const BOOL rc = ::GetMessage(msg, NULL, 0, 0);
|
return GetNextMessageTimeout(msg, INFINITE) == TRUE;
|
||||||
|
|
||||||
if ( rc == 0 )
|
|
||||||
{
|
|
||||||
// got WM_QUIT
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( rc == -1 )
|
|
||||||
{
|
|
||||||
// should never happen, but let's test for it nevertheless
|
|
||||||
wxLogLastError(wxT("GetMessage"));
|
|
||||||
|
|
||||||
// still break from the loop
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int wxMSWEventLoopBase::GetNextMessageTimeout(WXMSG *msg, unsigned long timeout)
|
int wxMSWEventLoopBase::GetNextMessageTimeout(WXMSG *msg, unsigned long timeout)
|
||||||
@@ -81,16 +102,14 @@ int wxMSWEventLoopBase::GetNextMessageTimeout(WXMSG *msg, unsigned long timeout)
|
|||||||
// MsgWaitForMultipleObjects() won't notice any input which was already
|
// MsgWaitForMultipleObjects() won't notice any input which was already
|
||||||
// examined (e.g. using PeekMessage()) but not yet removed from the queue
|
// examined (e.g. using PeekMessage()) but not yet removed from the queue
|
||||||
// so we need to remove any immediately messages manually
|
// so we need to remove any immediately messages manually
|
||||||
if ( !::PeekMessage(msg, 0, 0, 0, PM_REMOVE) )
|
while ( !::PeekMessage(msg, 0, 0, 0, PM_REMOVE) )
|
||||||
{
|
{
|
||||||
// we use this function just in order to not block longer than the
|
|
||||||
// given timeout, so we don't pass any handles to it at all
|
|
||||||
DWORD rc = ::MsgWaitForMultipleObjects
|
DWORD rc = ::MsgWaitForMultipleObjects
|
||||||
(
|
(
|
||||||
0, NULL,
|
1, &m_heventWake,
|
||||||
FALSE,
|
FALSE,
|
||||||
timeout,
|
timeout,
|
||||||
QS_ALLINPUT
|
QS_ALLINPUT | QS_ALLPOSTMESSAGE
|
||||||
);
|
);
|
||||||
|
|
||||||
switch ( rc )
|
switch ( rc )
|
||||||
@@ -104,13 +123,17 @@ int wxMSWEventLoopBase::GetNextMessageTimeout(WXMSG *msg, unsigned long timeout)
|
|||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
case WAIT_OBJECT_0:
|
case WAIT_OBJECT_0:
|
||||||
if ( !::PeekMessage(msg, 0, 0, 0, PM_REMOVE) )
|
// We were woken up by a background thread, which means there
|
||||||
{
|
// is no actual input message available, but we should still
|
||||||
// somehow it may happen that MsgWaitForMultipleObjects()
|
// return to the event loop, so pretend there was WM_NULL in
|
||||||
// returns true but there are no messages -- just treat it
|
// the queue.
|
||||||
// the same as timeout then
|
wxZeroMemory(*msg);
|
||||||
return -1;
|
return TRUE;
|
||||||
}
|
|
||||||
|
case WAIT_OBJECT_0 + 1:
|
||||||
|
// Some message is supposed to be available, but spurious
|
||||||
|
// wake ups are also possible, so just return to the loop:
|
||||||
|
// either we'll get the message or start waiting again.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -124,13 +147,6 @@ int wxMSWEventLoopBase::GetNextMessageTimeout(WXMSG *msg, unsigned long timeout)
|
|||||||
|
|
||||||
#if wxUSE_CONSOLE_EVENTLOOP
|
#if wxUSE_CONSOLE_EVENTLOOP
|
||||||
|
|
||||||
void wxConsoleEventLoop::WakeUp()
|
|
||||||
{
|
|
||||||
#if wxUSE_THREADS
|
|
||||||
wxWakeUpMainThread();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void wxConsoleEventLoop::ProcessMessage(WXMSG *msg)
|
void wxConsoleEventLoop::ProcessMessage(WXMSG *msg)
|
||||||
{
|
{
|
||||||
::DispatchMessage(msg);
|
::DispatchMessage(msg);
|
||||||
|
Reference in New Issue
Block a user