summaryrefslogtreecommitdiff
path: root/vcl/win
diff options
context:
space:
mode:
authorJan-Marek Glogowski <glogow@fbihome.de>2017-10-12 16:00:42 +0200
committerJan-Marek Glogowski <glogow@fbihome.de>2017-10-13 16:48:32 +0200
commitfb4e7be5d4eac6d7c429c215e72de45ea28d86cd (patch)
tree82b4d4282baa970cbc6990d77b5f7ac3451aa3af /vcl/win
parent21ccc64782f485f4fce7cd645f24dabb4b6eb985 (diff)
WIN another system loop integration attempt
This time we skip the intention to handle our Scheduler completely via the system event loop. Instead we basically guarantee to process a Scheduler event during each DoYield, if one is available. This way we won't block system events when busy in our event loop. Change-Id: I37094e61cbf928733151d9cc3299cdac76b3a5cd Reviewed-on: https://gerrit.libreoffice.org/43349 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Jan-Marek Glogowski <glogow@fbihome.de>
Diffstat (limited to 'vcl/win')
-rw-r--r--vcl/win/app/salinst.cxx41
-rw-r--r--vcl/win/app/saltimer.cxx49
2 files changed, 43 insertions, 47 deletions
diff --git a/vcl/win/app/salinst.cxx b/vcl/win/app/salinst.cxx
index a0a323b2d037..38db3d3bb17c 100644
--- a/vcl/win/app/salinst.cxx
+++ b/vcl/win/app/salinst.cxx
@@ -472,11 +472,11 @@ static void ImplSalDispatchMessage( MSG* pMsg )
ImplSalPostDispatchMsg( pMsg, lResult );
}
-static bool ImplSalYield( bool bWait, bool bHandleAllCurrentEvents )
+bool ImplSalYield( bool bWait, bool bHandleAllCurrentEvents )
{
static sal_uInt32 nLastTicks = 0;
MSG aMsg;
- bool bWasMsg = false, bOneEvent = false;
+ bool bWasMsg = false, bOneEvent = false, bWasTimeoutMsg = false;
ImplSVData *const pSVData = ImplGetSVData();
WinSalTimer* pTimer = static_cast<WinSalTimer*>( pSVData->maSchedCtx.mpSalTimer );
@@ -491,6 +491,8 @@ static bool ImplSalYield( bool bWait, bool bHandleAllCurrentEvents )
if ( bOneEvent )
{
bWasMsg = true;
+ if ( !bWasTimeoutMsg )
+ bWasTimeoutMsg = (SAL_MSG_TIMER_CALLBACK == aMsg.message);
TranslateMessage( &aMsg );
ImplSalDispatchMessage( &aMsg );
if ( bHandleAllCurrentEvents
@@ -499,23 +501,26 @@ static bool ImplSalYield( bool bWait, bool bHandleAllCurrentEvents )
bHadNewerEvent = true;
bOneEvent = !bHadNewerEvent;
}
- // busy loop to catch a message, eventually the 0ms timer.
- // we don't need to loop, if we wait anyway.
- if ( !bWait && !bWasMsg && pTimer && pTimer->PollForMessage() )
- {
- SwitchToThread();
- continue;
- }
+
if ( !(bHandleAllCurrentEvents && bOneEvent) )
break;
}
while( true );
+ // 0ms timeouts are handled out-of-bounds to prevent busy-locking the
+ // event loop with timeout massages.
+ // We ensure we never handle more then one timeout per call.
+ // This way we'll always process a normal system message.
+ if ( !bWasTimeoutMsg && pTimer && pTimer->IsDirectTimeout() )
+ {
+ pTimer->ImplHandleElapsedTimer();
+ bWasMsg = true;
+ }
+
if ( bHandleAllCurrentEvents )
nLastTicks = nCurTicks;
- // Also check that we don't wait when application already has quit
- if ( bWait && !bWasMsg && !pSVData->maAppData.mbAppQuit )
+ if ( bWait && !bWasMsg )
{
if ( GetMessageW( &aMsg, nullptr, 0, 0 ) )
{
@@ -540,8 +545,6 @@ bool WinSalInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents)
SolarMutexReleaser aReleaser;
if ( !IsMainThread() )
{
- // If you change the SendMessageW function, you might need to update
- // the PeekMessage( ... PM_QS_POSTMESSAGE) calls!
bDidWork = SendMessageW( mhComWnd, SAL_MSG_THREADYIELD,
(WPARAM) false, (LPARAM) bHandleAllCurrentEvents );
if ( !bDidWork && bWait )
@@ -659,17 +662,7 @@ LRESULT CALLBACK SalComWndProc( HWND, UINT nMsg, WPARAM wParam, LPARAM lParam, i
{
WinSalTimer *const pTimer = static_cast<WinSalTimer*>( ImplGetSVData()->maSchedCtx.mpSalTimer );
assert( pTimer != nullptr );
- MSG aMsg;
- bool bValidMSG = pTimer->IsValidWPARAM( wParam );
- // PM_QS_POSTMESSAGE is needed, so we don't process the SendMessage from DoYield!
- while ( PeekMessageW(&aMsg, pInst->mhComWnd, SAL_MSG_TIMER_CALLBACK,
- SAL_MSG_TIMER_CALLBACK, PM_REMOVE | PM_NOYIELD | PM_QS_POSTMESSAGE) )
- {
- assert( !bValidMSG && "Unexpected non-last valid message" );
- bValidMSG = pTimer->IsValidWPARAM( aMsg.wParam );
- }
- if ( bValidMSG )
- pTimer->ImplEmitTimerCallback();
+ pTimer->ImplHandleTimerEvent( wParam );
break;
}
}
diff --git a/vcl/win/app/saltimer.cxx b/vcl/win/app/saltimer.cxx
index 93b93fbb832f..fe22d53db8c8 100644
--- a/vcl/win/app/saltimer.cxx
+++ b/vcl/win/app/saltimer.cxx
@@ -46,16 +46,11 @@ void WinSalTimer::ImplStop()
return;
m_nTimerId = nullptr;
+ m_bDirectTimeout = false;
DeleteTimerQueueTimer( nullptr, hTimer, INVALID_HANDLE_VALUE );
- // Keep both after DeleteTimerQueueTimer, because they are set in SalTimerProc
+ // Keep InvalidateEvent after DeleteTimerQueueTimer, because the event id
+ // is set in SalTimerProc, which DeleteTimerQueueTimer will finish or cancel.
InvalidateEvent();
- m_bPollForMessage = false;
-
- // remove as many pending SAL_MSG_TIMER_CALLBACK messages as possible
- // PM_QS_POSTMESSAGE is needed, so we don't process the SendMessage from DoYield!
- MSG aMsg;
- while ( PeekMessageW(&aMsg, pInst->mhComWnd, SAL_MSG_TIMER_CALLBACK,
- SAL_MSG_TIMER_CALLBACK, PM_REMOVE | PM_NOYIELD | PM_QS_POSTMESSAGE) );
}
void WinSalTimer::ImplStart( sal_uLong nMS )
@@ -70,20 +65,21 @@ void WinSalTimer::ImplStart( sal_uLong nMS )
// cannot change a one-shot timer, so delete it and create a new one
ImplStop();
- // keep the yield running, if a 0ms Idle is scheduled
- m_bPollForMessage = ( 0 == nMS );
+ // directly indicate an elapsed timer
+ m_bDirectTimeout = ( 0 == nMS );
// probably WT_EXECUTEONLYONCE is not needed, but it enforces Period
// to be 0 and should not hurt; also see
// https://www.microsoft.com/msj/0499/pooling/pooling.aspx
- CreateTimerQueueTimer(&m_nTimerId, nullptr, SalTimerProc,
- reinterpret_cast<void*>(
- sal_IntPtr(GetNextEventVersion())),
- nMS, 0, WT_EXECUTEINTIMERTHREAD | WT_EXECUTEONLYONCE);
+ if ( !m_bDirectTimeout )
+ CreateTimerQueueTimer(&m_nTimerId, nullptr, SalTimerProc, this,
+ nMS, 0, WT_EXECUTEINTIMERTHREAD | WT_EXECUTEONLYONCE);
+ // We don't need any wakeup message, as this code can just run in the
+ // main thread!
}
WinSalTimer::WinSalTimer()
: m_nTimerId( nullptr )
- , m_bPollForMessage( false )
+ , m_bDirectTimeout( false )
{
}
@@ -126,12 +122,10 @@ void CALLBACK SalTimerProc(PVOID data, BOOLEAN)
{
__try
{
- // always post message when the timer fires, we will remove the ones
- // that happened during execution of the callback later directly from
- // the message queue
- BOOL const ret = PostMessageW(GetSalData()->mpInstance->mhComWnd,
- SAL_MSG_TIMER_CALLBACK,
- reinterpret_cast<WPARAM>(data), 0);
+ WinSalTimer *pTimer = reinterpret_cast<WinSalTimer*>( data );
+ BOOL const ret = PostMessageW(
+ GetSalData()->mpInstance->mhComWnd, SAL_MSG_TIMER_CALLBACK,
+ static_cast<WPARAM>(pTimer->GetNextEventVersion()), 0 );
#if OSL_DEBUG_LEVEL > 0
if (0 == ret) // SEH prevents using SAL_WARN here?
fputs("ERROR: PostMessage() failed!\n", stderr);
@@ -142,15 +136,24 @@ void CALLBACK SalTimerProc(PVOID data, BOOLEAN)
}
}
-void WinSalTimer::ImplEmitTimerCallback()
+void WinSalTimer::ImplHandleElapsedTimer()
{
// Test for MouseLeave
SalTestMouseLeave();
- m_bPollForMessage = false;
+ m_bDirectTimeout = false;
ImplSalYieldMutexAcquireWithWait();
CallCallback();
ImplSalYieldMutexRelease();
}
+void WinSalTimer::ImplHandleTimerEvent( const WPARAM aWPARAM )
+{
+ assert( aWPARAM <= SAL_MAX_INT32 );
+ if ( !IsValidEventVersion( static_cast<sal_Int32>( aWPARAM ) ) )
+ return;
+
+ ImplHandleElapsedTimer();
+}
+
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */