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.me...@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 <ke...@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.me...@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.
+
+@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: */
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to