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

Michael Meeks michael.meeks at collabora.com
Tue Sep 23 13:31:14 PDT 2014


 tools/source/datetime/ttime.cxx |   14 +++++
 vcl/inc/win/saldata.hxx         |   12 ++--
 vcl/source/app/timer.cxx        |    1 
 vcl/win/source/app/salinst.cxx  |    5 +
 vcl/win/source/app/saltimer.cxx |  102 +++++++++++++++++++++++-----------------
 5 files changed, 86 insertions(+), 48 deletions(-)

New commits:
commit da21f7da44dc577a08ea3bc210083dc8decf18bc
Author: Michael Meeks <michael.meeks at collabora.com>
Date:   Tue Sep 23 21:27:46 2014 +0100

    fdo#84000 - unwind recursive timer issues.
    
    Seemingly timers were not being issued or re-queued. Handle recursion
    issues in the main thread, not in the timer thread.
    
    Change-Id: I4f49341115bb7c7b1613e61f77a467154818a8aa

diff --git a/vcl/source/app/timer.cxx b/vcl/source/app/timer.cxx
index f83f55c..1f9870b 100644
--- a/vcl/source/app/timer.cxx
+++ b/vcl/source/app/timer.cxx
@@ -70,6 +70,7 @@ static void ImplStartTimer( ImplSVData* pSVData, sal_uLong nMS )
     if ( !nMS )
         nMS = 1;
 
+    // Assume underlying timers are recurring timers, if same period - just wait.
     if ( nMS != pSVData->mnTimerPeriod )
     {
         pSVData->mnTimerPeriod = nMS;
diff --git a/vcl/win/source/app/saltimer.cxx b/vcl/win/source/app/saltimer.cxx
index 779c691..fdfa5c0 100644
--- a/vcl/win/source/app/saltimer.cxx
+++ b/vcl/win/source/app/saltimer.cxx
@@ -54,11 +54,9 @@ void ImplSalStartTimer( sal_uLong nMS, bool bMutex )
     if (nMS > MAX_SYSPERIOD)
         nMS = MAX_SYSPERIOD;
 
-    // change if it exists, create if not
-    if (pSalData->mnTimerId)
-        ChangeTimerQueueTimer(NULL, pSalData->mnTimerId, nMS, nMS);
-    else
-        CreateTimerQueueTimer(&pSalData->mnTimerId, NULL, SalTimerProc, NULL, nMS, nMS, WT_EXECUTEDEFAULT);
+    // can't change a one-shot timer if it has fired already (odd) so delete & re-create
+    ImplSalStopTimer(pSalData);
+    CreateTimerQueueTimer(&pSalData->mnTimerId, NULL, SalTimerProc, NULL, nMS, nMS, WT_EXECUTEDEFAULT);
 
     pSalData->mnNextTimerTime = pSalData->mnLastEventTime + nMS;
 }
@@ -111,15 +109,10 @@ void CALLBACK SalTimerProc(PVOID, BOOLEAN)
     __try
     {
 #endif
+
         SalData* pSalData = GetSalData();
-        ImplSVData* pSVData = ImplGetSVData();
-
-        // don't allow recursive calls (mbInTimerProc is set when the callback
-        // is being processed)
-        if (pSVData->mpSalTimer && !pSalData->mbInTimerProc)
-        {
-            ImplPostMessage(pSalData->mpFirstInstance->mhComWnd, SAL_MSG_TIMER_CALLBACK, 0, 0);
-        }
+        ImplPostMessage(pSalData->mpFirstInstance->mhComWnd, SAL_MSG_TIMER_CALLBACK, 0, 0);
+
 #if defined ( __MINGW32__ ) && !defined ( _WIN64 )
     }
     han.Reset();
@@ -149,23 +142,18 @@ void EmitTimerCallback(bool bAllowRecursive)
 
     // Try to acquire the mutex. If we don't get the mutex then we
     // try this a short time later again.
-    if (ImplSalYieldMutexTryToAcquire())
+    if (ImplSalYieldMutexTryToAcquire() &&
+        (pSVData->mpSalTimer && (!pSalData->mbInTimerProc || bAllowRecursive)))
     {
-        if (pSVData->mpSalTimer && (!pSalData->mbInTimerProc || bAllowRecursive))
-        {
-            pSalData->mbInTimerProc = true;
-            pSVData->mpSalTimer->CallCallback();
-            pSalData->mbInTimerProc = false;
-            ImplSalYieldMutexRelease();
-
-            // Run the timer in the correct time, if we start this
-            // with a small timeout, because we don't get the mutex
-            if (pSalData->mnTimerId && (pSalData->mnTimerMS != pSalData->mnTimerOrgMS))
-                ImplSalStartTimer(pSalData->mnTimerOrgMS, false);
-        }
+        pSalData->mbInTimerProc = true;
+        pSVData->mpSalTimer->CallCallback();
+        pSalData->mbInTimerProc = false;
+        ImplSalYieldMutexRelease();
     }
     else
+    {
         ImplSalStartTimer(10, true);
+    }
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit 211b3192f05c4120fa2dd0e23988e74bdd310830
Author: Jan Holesovsky <kendy at collabora.com>
Date:   Fri Sep 19 15:48:24 2014 +0200

    fdo#84000: Reimplement the Windows WinSalTimer using Timer Queues.
    
    Timer Queues
    
    http://msdn.microsoft.com/en-us/library/windows/desktop/ms686796%28v=vs.85%29.aspx
    
    allow creating & maintaing high-precision timers.  This commit switches the
    WinSalTimer implementation from using the Timers:
    
    http://msdn.microsoft.com/en-us/library/windows/desktop/ms644900%28v=vs.85%29.aspx
    
    to Timer Queue Timers.
    
    The 'classic' Timers do not have better precision than some 15.6ms (the
    documentation mentions 10ms, but some measuring seems to confirm that it is
    more than that).
    
    With the Timer Queue Timers, we now have 1ms precision.
    
    Incorporates some cleanup from Michael Meeks <michael.meeks at collabora.com>.
    
    Change-Id: I0312a0c9fdc2779258698b24389b24c39e643473

diff --git a/tools/source/datetime/ttime.cxx b/tools/source/datetime/ttime.cxx
index 0b147b4..71836e7 100644
--- a/tools/source/datetime/ttime.cxx
+++ b/tools/source/datetime/ttime.cxx
@@ -400,7 +400,19 @@ Time Time::GetUTCOffset()
 sal_uIntPtr Time::GetSystemTicks()
 {
 #if defined WNT
-    return (sal_uIntPtr)GetTickCount();
+    static LARGE_INTEGER nTicksPerMS;
+    static bool bTicksPerMSInitialized = false;
+    if (!bTicksPerMSInitialized)
+    {
+        QueryPerformanceFrequency(&nTicksPerMS);
+        nTicksPerMS.QuadPart /= 1000;
+        bTicksPerMSInitialized = true;
+    }
+
+    LARGE_INTEGER nPerformanceCount;
+    QueryPerformanceCounter(&nPerformanceCount);
+
+    return (sal_uIntPtr)(nPerformanceCount.QuadPart/nTicksPerMS.QuadPart);
 #else
     timeval tv;
     gettimeofday (&tv, 0);
diff --git a/vcl/inc/win/saldata.hxx b/vcl/inc/win/saldata.hxx
index d047fc5..409ca3e 100644
--- a/vcl/inc/win/saldata.hxx
+++ b/vcl/inc/win/saldata.hxx
@@ -83,11 +83,11 @@ public:
     long*                   mpDitherDiff;           // Dither mapping table
     BYTE*                   mpDitherLow;            // Dither mapping table
     BYTE*                   mpDitherHigh;           // Dither mapping table
-    sal_uLong                   mnTimerMS;              // Current Time (in MS) of the Timer
-    sal_uLong                   mnTimerOrgMS;           // Current Original Time (in MS)
+    sal_uLong               mnTimerMS;              // Current Time (in MS) of the Timer
+    sal_uLong               mnTimerOrgMS;           // Current Original Time (in MS)
     DWORD                   mnNextTimerTime;
     DWORD                   mnLastEventTime;
-    UINT                    mnTimerId;              // windows timer id
+    HANDLE                  mnTimerId;              ///< Windows timer id
     bool                    mbInTimerProc;          // timer event is currently being dispatched
     HHOOK                   mhSalObjMsgHook;        // hook to get interesting msg for SalObject
     HWND                    mhWantLeaveMsg;         // window handle, that want a MOUSELEAVE message
@@ -181,8 +181,7 @@ void ImplSalAcquireYieldMutex( sal_uLong nCount );
 
 LRESULT CALLBACK SalFrameWndProcW( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam );
 
-#define SALTIMERPROC_RECURSIVE 0xffffffff
-void    CALLBACK SalTimerProc( HWND hWnd, UINT nMsg, UINT_PTR nId, DWORD nTime );
+void EmitTimerCallback(bool bAllowRecursive);
 
 void SalTestMouseLeave();
 bool ImplWriteLastError( DWORD lastError, const char *szApiCall );
@@ -286,6 +285,9 @@ int ImplSalWICompareAscii( const wchar_t* pStr1, const char* pStr2 );
 // POSTFOCUS-Message; wParam == bFocus; lParam == 0
 #define SALOBJ_MSG_POSTFOCUS        (WM_USER+161)
 
+// Call the Timer's callback from the main thread
+#define SAL_MSG_TIMER_CALLBACK      (WM_USER+162)
+
 // A/W-Wrapper
 BOOL    ImplPostMessage( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam );
 BOOL    ImplSendMessage( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam );
diff --git a/vcl/win/source/app/salinst.cxx b/vcl/win/source/app/salinst.cxx
index 7a697ae..c8eb110 100644
--- a/vcl/win/source/app/salinst.cxx
+++ b/vcl/win/source/app/salinst.cxx
@@ -736,7 +736,10 @@ LRESULT CALLBACK SalComWndProc( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lPar
             rDef = FALSE;
             break;
         case SAL_MSG_POSTTIMER:
-            SalTimerProc( 0, 0, SALTIMERPROC_RECURSIVE, lParam );
+            EmitTimerCallback(/*bAllowRecursive = */ true);
+            break;
+        case SAL_MSG_TIMER_CALLBACK:
+            EmitTimerCallback(/*bAllowRecursive = */ false);
             break;
     }
 
diff --git a/vcl/win/source/app/saltimer.cxx b/vcl/win/source/app/saltimer.cxx
index 287ec9a..779c691 100644
--- a/vcl/win/source/app/saltimer.cxx
+++ b/vcl/win/source/app/saltimer.cxx
@@ -29,25 +29,37 @@
 // maximum period
 #define MAX_SYSPERIOD     65533
 
+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.
+
+void ImplSalStopTimer(SalData* pSalData)
+{
+    HANDLE hTimer = pSalData->mnTimerId;
+    pSalData->mnTimerId = 0;
+    DeleteTimerQueueTimer(NULL, hTimer, 0);
+}
+
 void ImplSalStartTimer( sal_uLong nMS, bool bMutex )
 {
     SalData* pSalData = GetSalData();
 
     // Remember the time of the timer
     pSalData->mnTimerMS = nMS;
-    if ( !bMutex )
+    if (!bMutex)
         pSalData->mnTimerOrgMS = nMS;
 
     // duration has to fit into Window's sal_uInt16
-    if ( nMS > MAX_SYSPERIOD )
+    if (nMS > MAX_SYSPERIOD)
         nMS = MAX_SYSPERIOD;
 
-    // kill timer if it exists
-    if ( pSalData->mnTimerId )
-        KillTimer( 0, pSalData->mnTimerId );
+    // change if it exists, create if not
+    if (pSalData->mnTimerId)
+        ChangeTimerQueueTimer(NULL, pSalData->mnTimerId, nMS, nMS);
+    else
+        CreateTimerQueueTimer(&pSalData->mnTimerId, NULL, SalTimerProc, NULL, nMS, nMS, WT_EXECUTEDEFAULT);
 
-    // Make a new timer with new period
-    pSalData->mnTimerId = SetTimer( 0, 0, (UINT)nMS, SalTimerProc );
     pSalData->mnNextTimerTime = pSalData->mnLastEventTime + nMS;
 }
 
@@ -77,13 +89,17 @@ void WinSalTimer::Stop()
     // If we have a timer, than
     if ( pSalData->mnTimerId )
     {
-        KillTimer( 0, pSalData->mnTimerId );
-        pSalData->mnTimerId = 0;
+        ImplSalStopTimer(pSalData);
         pSalData->mnNextTimerTime = 0;
     }
 }
 
-void CALLBACK SalTimerProc( HWND, UINT, UINT_PTR nId, DWORD )
+/** This gets invoked from a Timer Queue thread.
+
+Don't acquire the SolarMutex to avoid deadlocks, just wake up the main thread
+at better resolution than 10ms.
+*/
+void CALLBACK SalTimerProc(PVOID, BOOLEAN)
 {
 #if defined ( __MINGW32__ ) && !defined ( _WIN64 )
     jmp_buf jmpbuf;
@@ -98,42 +114,58 @@ void CALLBACK SalTimerProc( HWND, UINT, UINT_PTR nId, DWORD )
         SalData* pSalData = GetSalData();
         ImplSVData* pSVData = ImplGetSVData();
 
-        // Test for MouseLeave
-        SalTestMouseLeave();
-
-        bool bRecursive = pSalData->mbInTimerProc && (nId != SALTIMERPROC_RECURSIVE);
-        if ( pSVData->mpSalTimer && ! bRecursive )
+        // don't allow recursive calls (mbInTimerProc is set when the callback
+        // is being processed)
+        if (pSVData->mpSalTimer && !pSalData->mbInTimerProc)
         {
-            // Try to acquire the mutex. If we don't get the mutex then we
-            // try this a short time later again.
-            if ( ImplSalYieldMutexTryToAcquire() )
-            {
-                bRecursive = pSalData->mbInTimerProc && (nId != SALTIMERPROC_RECURSIVE);
-                if ( pSVData->mpSalTimer && ! bRecursive )
-                {
-                    pSalData->mbInTimerProc = TRUE;
-                    pSVData->mpSalTimer->CallCallback();
-                    pSalData->mbInTimerProc = FALSE;
-                    ImplSalYieldMutexRelease();
-
-                    // Run the timer in the correct time, if we start this
-                    // with a small timeout, because we don't get the mutex
-                    if ( pSalData->mnTimerId &&
-                        (pSalData->mnTimerMS != pSalData->mnTimerOrgMS) )
-                        ImplSalStartTimer( pSalData->mnTimerOrgMS, FALSE );
-                }
-            }
-            else
-                ImplSalStartTimer( 10, TRUE );
+            ImplPostMessage(pSalData->mpFirstInstance->mhComWnd, SAL_MSG_TIMER_CALLBACK, 0, 0);
         }
-    }
 #if defined ( __MINGW32__ ) && !defined ( _WIN64 )
+    }
     han.Reset();
 #else
+    }
     __except(WinSalInstance::WorkaroundExceptionHandlingInUSER32Lib(GetExceptionCode(), GetExceptionInformation()))
     {
     }
 #endif
 }
 
+/** Called in the main thread.
+
+We assured that by posting the message from the SalTimeProc only, the real
+call then happens when the main thread gets SAL_MSG_TIMER_CALLBACK.
+
+ at param bAllowRecursive allows to skip the check that assures that two timeouts
+do not overlap.
+*/
+void EmitTimerCallback(bool bAllowRecursive)
+{
+    SalData* pSalData = GetSalData();
+    ImplSVData* pSVData = ImplGetSVData();
+
+    // Test for MouseLeave
+    SalTestMouseLeave();
+
+    // Try to acquire the mutex. If we don't get the mutex then we
+    // try this a short time later again.
+    if (ImplSalYieldMutexTryToAcquire())
+    {
+        if (pSVData->mpSalTimer && (!pSalData->mbInTimerProc || bAllowRecursive))
+        {
+            pSalData->mbInTimerProc = true;
+            pSVData->mpSalTimer->CallCallback();
+            pSalData->mbInTimerProc = false;
+            ImplSalYieldMutexRelease();
+
+            // Run the timer in the correct time, if we start this
+            // with a small timeout, because we don't get the mutex
+            if (pSalData->mnTimerId && (pSalData->mnTimerMS != pSalData->mnTimerOrgMS))
+                ImplSalStartTimer(pSalData->mnTimerOrgMS, false);
+        }
+    }
+    else
+        ImplSalStartTimer(10, true);
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */


More information about the Libreoffice-commits mailing list