[Libreoffice-commits] core.git: vcl/inc vcl/win

Jan-Marek Glogowski glogow at fbihome.de
Thu Jul 20 15:55:50 UTC 2017


 vcl/inc/win/saldata.hxx  |    2 ++
 vcl/win/app/salinst.cxx  |   43 ++++++++++++++++++++++++++++++++++---------
 vcl/win/app/saltimer.cxx |   12 +++++++-----
 3 files changed, 43 insertions(+), 14 deletions(-)

New commits:
commit 37436815970b14f8940fc0c547862452a2dc3e1e
Author: Jan-Marek Glogowski <glogow at fbihome.de>
Date:   Wed Jul 19 15:48:39 2017 +0200

    tdf#109123 WIN Run instant timerout with low priority
    
    This busy-lock happens, because user messages have a higher priority
    then some system messages. What happens:
    
    1. The main system loop picks up the LO scheduler
    2. The idle worker (IW) is started
    3. IW checks using AnyInput( VCL_INPUT_ANY ) for system events
    4. A system event is found
    5. The LO scheduler gets posted again
    6. The main system loop picks up the LO scheduler instead of the
       system message => goto 2
    
    Normally it's suggested to use WM_TIMER in this case, as these messages
    are supposed to have the lowest priority. But this doesn't work, if
    you use PostMessage to generate them and SetTimer doesn't accept a
    0ms timeout. At least PeakMessage also picks up the WM_TIMER message
    before the system message, probably because PostMessage is somehow
    related to the threads queue - who knows.
    
    In the end this implements a manual, low priority event, which is checked
    at the end of the ImplSalYield function. It just runs, if there is
    nothing else to do. We still have to emit the timer callback event,
    as ImplSalYield may wait in GetMessage, but wParam now indicates, if
    it's a wakeup and can be ignored. We use the same event, so it's
    easier to filter.
    
    Thanks to Mike Kaganski for the missing information and ideas for the
    final implementation.
    
    Change-Id: Ib8e4f214ab8d3731d5594d68f38f46982c2eb36d
    Reviewed-on: https://gerrit.libreoffice.org/40190
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Jan-Marek Glogowski <glogow at fbihome.de>

diff --git a/vcl/inc/win/saldata.hxx b/vcl/inc/win/saldata.hxx
index b28f3e2c09be..ed1d225b14b8 100644
--- a/vcl/inc/win/saldata.hxx
+++ b/vcl/inc/win/saldata.hxx
@@ -85,6 +85,7 @@ public:
     BYTE*                   mpDitherLow;            // Dither mapping table
     BYTE*                   mpDitherHigh;           // Dither mapping table
     HANDLE                  mnTimerId;              ///< Windows timer id
+    bool                    mbOnIdleRunScheduler;   ///< Run the scheduler, if yield is idle
     HHOOK                   mhSalObjMsgHook;        // hook to get interesting msg for SalObject
     HWND                    mhWantLeaveMsg;         // window handle, that want a MOUSELEAVE message
     AutoTimer*              mpMouseLeaveTimer;      // Timer for MouseLeave Test
@@ -274,6 +275,7 @@ int ImplSalWICompareAscii( const wchar_t* pStr1, const char* pStr2 );
 #define SALOBJ_MSG_POSTFOCUS        (WM_USER+161)
 
 // Call the Timer's callback from the main thread
+// wParam = 1 == run when yield is idle instead of direct
 #define SAL_MSG_TIMER_CALLBACK      (WM_USER+162)
 // Stop the timer from the main thread; wParam = 0, lParam = 0
 #define SAL_MSG_STOPTIMER           (WM_USER+163)
diff --git a/vcl/win/app/salinst.cxx b/vcl/win/app/salinst.cxx
index d6a970e7eca8..7e76cd921273 100644
--- a/vcl/win/app/salinst.cxx
+++ b/vcl/win/app/salinst.cxx
@@ -322,6 +322,7 @@ SalData::SalData()
     mpDitherLow = nullptr;      // Dither mapping table
     mpDitherHigh = nullptr;     // Dither mapping table
     mnTimerId = nullptr;        // windows timer id
+    mbOnIdleRunScheduler = false; // if yield is idle, run the scheduler
     mhSalObjMsgHook = nullptr;  // hook to get interesting msg for SalObject
     mhWantLeaveMsg = nullptr;   // window handle, that want a MOUSELEAVE message
     mpMouseLeaveTimer = nullptr; // Timer for MouseLeave Test
@@ -565,19 +566,38 @@ ImplSalYield( bool bWait, bool bHandleAllCurrentEvents )
 {
     MSG aMsg;
     bool bWasMsg = false, bOneEvent = false;
+    SalData *const pSalData = GetSalData();
 
     int nMaxEvents = bHandleAllCurrentEvents ? 100 : 1;
     do
     {
-        if ( PeekMessageW( &aMsg, nullptr, 0, 0, PM_REMOVE ) )
+        bOneEvent = PeekMessageW( &aMsg, nullptr, 0, 0, PM_REMOVE );
+        if ( bOneEvent )
         {
-            TranslateMessage( &aMsg );
-            ImplSalDispatchMessage( &aMsg );
-
-            bOneEvent = bWasMsg = true;
+            bWasMsg = true;
+            if ( !(aMsg.message == SAL_MSG_TIMER_CALLBACK && 1 == aMsg.wParam) )
+            {
+                TranslateMessage( &aMsg );
+                ImplSalDispatchMessage( &aMsg );
+            }
+            else
+            {
+                // This is just the scheduler wakeup message, in case we're
+                // waiting in GetMessageW
+                // So we can just drop it, but we have to fix the accounting!
+                assert( pSalData->mbOnIdleRunScheduler );
+                ++nMaxEvents;
+            }
         }
         else
-            bOneEvent = false;
+        {
+            if ( nMaxEvents && pSalData->mbOnIdleRunScheduler )
+            {
+                pSalData->mbOnIdleRunScheduler = false;
+                EmitTimerCallback();
+                bOneEvent = true;
+            }
+        }
     } while( --nMaxEvents && bOneEvent );
 
     // Also check that we don't wait when application already has quit
@@ -585,8 +605,12 @@ ImplSalYield( bool bWait, bool bHandleAllCurrentEvents )
     {
         if ( GetMessageW( &aMsg, nullptr, 0, 0 ) )
         {
-            TranslateMessage( &aMsg );
-            ImplSalDispatchMessage( &aMsg );
+            // Ignore the scheduler wakeup message
+            if ( !(aMsg.message == SAL_MSG_TIMER_CALLBACK && 1 == aMsg.wParam) )
+            {
+                TranslateMessage( &aMsg );
+                ImplSalDispatchMessage( &aMsg );
+            }
         }
     }
     return bWasMsg;
@@ -708,7 +732,8 @@ LRESULT CALLBACK SalComWndProc( HWND, UINT nMsg, WPARAM wParam, LPARAM lParam, i
             while ( PeekMessageW(&aMsg, nullptr, SAL_MSG_TIMER_CALLBACK,
                                  SAL_MSG_TIMER_CALLBACK, PM_REMOVE) )
                 assert( "Multiple timer messages in queue" );
-            EmitTimerCallback();
+            if ( 0 == wParam )
+                EmitTimerCallback();
             break;
     }
 
diff --git a/vcl/win/app/saltimer.cxx b/vcl/win/app/saltimer.cxx
index 2ddb34b8f0b6..ae8ed0790bf5 100644
--- a/vcl/win/app/saltimer.cxx
+++ b/vcl/win/app/saltimer.cxx
@@ -22,7 +22,7 @@
 #include <win/saltimer.h>
 #include <win/salinst.h>
 
-void CALLBACK SalTimerProc(PVOID pParameter, BOOLEAN bTimerOrWaitFired);
+static void CALLBACK SalTimerProc(PVOID pParameter, BOOLEAN bTimerOrWaitFired);
 
 // See http://msdn.microsoft.com/en-us/library/windows/desktop/ms687003%28v=vs.85%29.aspx
 // (and related pages) for details about the Timer Queues.
@@ -52,6 +52,7 @@ void ImplSalStopTimer()
                          SAL_MSG_TIMER_CALLBACK, PM_REMOVE) )
         nMsgCount++;
     assert( nMsgCount <= 1 );
+    pSalData->mbOnIdleRunScheduler = false;
 }
 
 void ImplSalStartTimer( sal_uLong nMS )
@@ -66,11 +67,12 @@ void ImplSalStartTimer( sal_uLong nMS )
     // cannot change a one-shot timer, so delete it and create a new one
     ImplSalStopTimer();
 
-    // directly post a timer callback message for instant timers / idles
-    if ( 0 == nMS )
+    // run the scheduler, if yield is idle for the 0ms case
+    pSalData->mbOnIdleRunScheduler = ( 0 == nMS );
+    if ( pSalData->mbOnIdleRunScheduler )
     {
         BOOL const ret = PostMessageW(pSalData->mpFirstInstance->mhComWnd,
-                                      SAL_MSG_TIMER_CALLBACK, 0, 0);
+                                      SAL_MSG_TIMER_CALLBACK, 1, 0);
         SAL_WARN_IF(0 == ret, "vcl", "ERROR: PostMessage() failed!");
     }
     else
@@ -119,7 +121,7 @@ void WinSalTimer::Stop()
 Don't acquire the SolarMutex to avoid deadlocks, just wake up the main thread
 at better resolution than 10ms.
 */
-void CALLBACK SalTimerProc(PVOID, BOOLEAN)
+static void CALLBACK SalTimerProc(PVOID, BOOLEAN)
 {
     __try
     {


More information about the Libreoffice-commits mailing list