Make main thread wake up code more efficient and less error-prone in wxMSW.
Use a kernel event object to signal the thread wake up instead of sending WM_NULL to one of its windows. This is simpler as we don't need to look for any windows and doesn't suffer from the problem of overflowing the Windows message queue if we do it too many times as signalling an already signalled event simply doesn't do anything. Closes #9053. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@78041 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -42,6 +42,17 @@ wxMSWEventLoopBase::wxMSWEventLoopBase()
|
||||
{
|
||||
m_shouldExit = false;
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
const BOOL rc = ::GetMessage(msg, NULL, 0, 0);
|
||||
|
||||
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;
|
||||
return GetNextMessageTimeout(msg, INFINITE) == TRUE;
|
||||
}
|
||||
|
||||
int wxMSWEventLoopBase::GetNextMessageTimeout(WXMSG *msg, unsigned long timeout)
|
||||
@@ -86,14 +107,12 @@ int wxMSWEventLoopBase::GetNextMessageTimeout(WXMSG *msg, unsigned long timeout)
|
||||
// it is not available in very old Windows versions
|
||||
if ( !::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
|
||||
(
|
||||
0, NULL,
|
||||
1, &m_heventWake,
|
||||
FALSE,
|
||||
timeout,
|
||||
QS_ALLINPUT
|
||||
QS_ALLINPUT | QS_ALLPOSTMESSAGE
|
||||
);
|
||||
|
||||
switch ( rc )
|
||||
@@ -107,6 +126,15 @@ int wxMSWEventLoopBase::GetNextMessageTimeout(WXMSG *msg, unsigned long timeout)
|
||||
return -1;
|
||||
|
||||
case WAIT_OBJECT_0:
|
||||
// We were woken up by a background thread, which means there
|
||||
// is no actual input message available, but we should still
|
||||
// return to the event loop, so pretend there was WM_NULL in
|
||||
// the queue.
|
||||
wxZeroMemory(*msg);
|
||||
break;
|
||||
|
||||
case WAIT_OBJECT_0 + 1:
|
||||
// Some message is supposed to be available.
|
||||
if ( !::PeekMessage(msg, 0, 0, 0, PM_REMOVE) )
|
||||
{
|
||||
// somehow it may happen that MsgWaitForMultipleObjects()
|
||||
@@ -127,13 +155,6 @@ int wxMSWEventLoopBase::GetNextMessageTimeout(WXMSG *msg, unsigned long timeout)
|
||||
|
||||
#if wxUSE_CONSOLE_EVENTLOOP
|
||||
|
||||
void wxConsoleEventLoop::WakeUp()
|
||||
{
|
||||
#if wxUSE_THREADS
|
||||
wxWakeUpMainThread();
|
||||
#endif
|
||||
}
|
||||
|
||||
void wxConsoleEventLoop::ProcessMessage(WXMSG *msg)
|
||||
{
|
||||
::DispatchMessage(msg);
|
||||
|
||||
Reference in New Issue
Block a user