Index: /trunk/src/VBox/Runtime/generic/timerlr-generic.cpp
===================================================================
--- /trunk/src/VBox/Runtime/generic/timerlr-generic.cpp	(revision 80664)
+++ /trunk/src/VBox/Runtime/generic/timerlr-generic.cpp	(revision 80665)
@@ -47,4 +47,11 @@
 
 /*********************************************************************************************************************************
+*   Defined Constants And Macros                                                                                                 *
+*********************************************************************************************************************************/
+/** The smallest interval for low resolution timers. */
+#define RTTIMERLR_MIN_INTERVAL  RT_NS_100MS
+
+
+/*********************************************************************************************************************************
 *   Structures and Typedefs                                                                                                      *
 *********************************************************************************************************************************/
@@ -62,4 +69,18 @@
     /** Flag indicating that the timer has been destroyed. */
     bool volatile           fDestroyed;
+    /** Set when the thread is blocked. */
+    bool volatile           fBlocked;
+    bool                    fPadding;
+    /** The timer interval. 0 if one-shot. */
+    uint64_t volatile       u64NanoInterval;
+    /** The start of the current run (ns).
+     * This is used to calculate when the timer ought to fire the next time. */
+    uint64_t volatile       u64StartTS;
+    /** The start of the current run (ns).
+     * This is used to calculate when the timer ought to fire the next time. */
+    uint64_t volatile       u64NextTS;
+    /** The current tick number (since u64StartTS). */
+    uint64_t volatile       iTick;
+
     /** Callback. */
     PFNRTTIMERLR            pfnTimer;
@@ -70,14 +91,4 @@
     /** Event semaphore on which the thread is blocked. */
     RTSEMEVENT              hEvent;
-    /** The timer interval. 0 if one-shot. */
-    uint64_t                u64NanoInterval;
-    /** The start of the current run (ns).
-     * This is used to calculate when the timer ought to fire the next time. */
-    uint64_t volatile       u64StartTS;
-    /** The start of the current run (ns).
-     * This is used to calculate when the timer ought to fire the next time. */
-    uint64_t volatile       u64NextTS;
-    /** The current tick number (since u64StartTS). */
-    uint64_t volatile       iTick;
 } RTTIMERLRINT;
 typedef RTTIMERLRINT *PRTTIMERLRINT;
@@ -98,8 +109,6 @@
      * We don't support the fancy MP features, nor intervals lower than 100 ms.
      */
-    if (fFlags & RTTIMER_FLAGS_CPU_SPECIFIC)
-        return VERR_NOT_SUPPORTED;
-    if (u64NanoInterval && u64NanoInterval < 100*1000*1000)
-        return VERR_INVALID_PARAMETER;
+    AssertReturn(!(fFlags & RTTIMER_FLAGS_CPU_SPECIFIC), VERR_NOT_SUPPORTED);
+    AssertReturn(!u64NanoInterval || u64NanoInterval >= RTTIMERLR_MIN_INTERVAL, VERR_OUT_OF_RANGE);
 
     /*
@@ -113,4 +122,6 @@
     pThis->fSuspended = true;
     pThis->fDestroyed = false;
+    pThis->fBlocked = false;
+    pThis->fPadding = false;
     pThis->pfnTimer = pfnTimer;
     pThis->pvUser = pvUser;
@@ -173,17 +184,9 @@
 
 
-RTDECL(int) RTTimerLRStart(RTTIMERLR hTimerLR, uint64_t u64First)
-{
-    /*
-     * Validate input.
-     */
-    PRTTIMERLRINT pThis = hTimerLR;
-    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
-    AssertReturn(pThis->u32Magic == RTTIMERLR_MAGIC, VERR_INVALID_HANDLE);
-    AssertReturn(!pThis->fDestroyed, VERR_INVALID_HANDLE);
-
-    if (u64First && u64First < 100*1000*1000)
-        return VERR_INVALID_PARAMETER;
-
+/**
+ * Internal worker fro RTTimerLRStart and RTTiemrLRChangeInterval.
+ */
+static int rtTimerLRStart(PRTTIMERLRINT pThis, uint64_t u64First)
+{
     if (!pThis->fSuspended)
         return VERR_TIMER_ACTIVE;
@@ -203,8 +206,7 @@
     return rc;
 }
-RT_EXPORT_SYMBOL(RTTimerLRStart);
-
-
-RTDECL(int) RTTimerLRStop(RTTIMERLR hTimerLR)
+
+
+RTDECL(int) RTTimerLRStart(RTTIMERLR hTimerLR, uint64_t u64First)
 {
     /*
@@ -215,5 +217,22 @@
     AssertReturn(pThis->u32Magic == RTTIMERLR_MAGIC, VERR_INVALID_HANDLE);
     AssertReturn(!pThis->fDestroyed, VERR_INVALID_HANDLE);
-
+    AssertReturn(!u64First || u64First >= RTTIMERLR_MIN_INTERVAL, VERR_OUT_OF_RANGE);
+
+    /*
+     * Do the job.
+     */
+    return rtTimerLRStart(pThis, u64First);
+}
+RT_EXPORT_SYMBOL(RTTimerLRStart);
+
+
+/**
+ * Internal worker for RTTimerLRStop and RTTimerLRChangeInterval
+ */
+static int rtTimerLRStop(PRTTIMERLRINT pThis, bool fSynchronous)
+{
+    /*
+     * Fail if already suspended.
+     */
     if (pThis->fSuspended)
         return VERR_TIMER_SUSPENDED;
@@ -221,16 +240,33 @@
     /*
      * Mark it as suspended and kick the thread.
-     */
+     * It's simpler to always reset the thread user semaphore, so we do that first.
+     */
+    int rc = RTThreadUserReset(pThis->hThread);
+    AssertRC(rc);
+
     ASMAtomicWriteBool(&pThis->fSuspended, true);
-    int rc = RTSemEventSignal(pThis->hEvent);
+    rc = RTSemEventSignal(pThis->hEvent);
     if (rc == VERR_ALREADY_POSTED)
         rc = VINF_SUCCESS;
     AssertRC(rc);
+
+    /*
+     * Wait for the thread to stop running if synchronous.
+     */
+    if (fSynchronous && RT_SUCCESS(rc))
+    {
+        rc = RTThreadUserWait(pThis->hThread, RT_MS_1MIN);
+        AssertRC(rc);
+    }
+
     return rc;
 }
-RT_EXPORT_SYMBOL(RTTimerLRStop);
-
-RTDECL(int) RTTimerLRChangeInterval(RTTIMERLR hTimerLR, uint64_t u64NanoInterval)
-{
+
+
+RTDECL(int) RTTimerLRStop(RTTIMERLR hTimerLR)
+{
+    /*
+     * Validate input.
+     */
     PRTTIMERLRINT pThis = hTimerLR;
     AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
@@ -238,34 +274,58 @@
     AssertReturn(!pThis->fDestroyed, VERR_INVALID_HANDLE);
 
-    if (u64NanoInterval && u64NanoInterval < 100*1000*1000)
-        return VERR_INVALID_PARAMETER;
-
-#if 0
-    if (!pThis->fSuspended)
-    {
-        int rc = RTTimerLRStop(hTimerLR);
-        if (RT_FAILURE(rc))
-            return rc;
-
+    /*
+     * Do the job.
+     */
+    return rtTimerLRStop(pThis, false);
+}
+RT_EXPORT_SYMBOL(RTTimerLRStop);
+
+
+RTDECL(int) RTTimerLRChangeInterval(RTTIMERLR hTimerLR, uint64_t u64NanoInterval)
+{
+    /*
+     * Validate input.
+     */
+    PRTTIMERLRINT pThis = hTimerLR;
+    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+    AssertReturn(pThis->u32Magic == RTTIMERLR_MAGIC, VERR_INVALID_HANDLE);
+    AssertReturn(!pThis->fDestroyed, VERR_INVALID_HANDLE);
+    AssertReturn(!u64NanoInterval || u64NanoInterval >= RTTIMERLR_MIN_INTERVAL, VERR_OUT_OF_RANGE);
+
+    /*
+     * Do the job accoring to state and caller.
+     */
+    int rc;
+    if (pThis->fSuspended)
+    {
+        /* Stopped: Just update the interval. */
         ASMAtomicWriteU64(&pThis->u64NanoInterval, u64NanoInterval);
-
-        rc = RTTimerLRStart(hTimerLR, 0);
-        if (RT_FAILURE(rc))
-            return rc;
+        rc = VINF_SUCCESS;
+    }
+    else if (RTThreadSelf() == pThis->hThread)
+    {
+        /* Running: Updating interval from the callback. */
+        uint64_t u64Now = RTTimeNanoTS();
+        pThis->iTick           = 0;
+        pThis->u64StartTS      = u64Now;
+        pThis->u64NextTS       = u64Now;
+        ASMAtomicWriteU64(&pThis->u64NanoInterval, u64NanoInterval);
+        rc = VINF_SUCCESS;
     }
     else
-#endif
-    {
-        uint64_t u64Now = RTTimeNanoTS();
-        ASMAtomicWriteU64(&pThis->iTick, 0);
-        ASMAtomicWriteU64(&pThis->u64StartTS, u64Now);
-        ASMAtomicWriteU64(&pThis->u64NextTS, u64Now);
-        ASMAtomicWriteU64(&pThis->u64NanoInterval, u64NanoInterval);
-        RTSemEventSignal(pThis->hEvent);
-    }
-
-    return VINF_SUCCESS;
+    {
+        /* Running: Stopping  */
+        rc = rtTimerLRStop(pThis, true);
+        if (RT_SUCCESS(rc))
+        {
+            ASMAtomicWriteU64(&pThis->u64NanoInterval, u64NanoInterval);
+            rc = rtTimerLRStart(pThis, 0);
+        }
+    }
+
+    return rc;
 }
 RT_EXPORT_SYMBOL(RTTimerLRChangeInterval);
+
 
 static DECLCALLBACK(int) rtTimerLRThread(RTTHREAD hThreadSelf, void *pvUser)
@@ -281,5 +341,10 @@
         if (ASMAtomicUoReadBool(&pThis->fSuspended))
         {
-            int rc = RTSemEventWait(pThis->hEvent, RT_INDEFINITE_WAIT);
+            /* Signal rtTimerLRStop thread. */
+            int rc = RTThreadUserSignal(hThreadSelf);
+            AssertRC(rc);
+
+            ASMAtomicWriteBool(&pThis->fBlocked, true);
+            rc = RTSemEventWait(pThis->hEvent, RT_INDEFINITE_WAIT);
             if (RT_FAILURE(rc) && rc != VERR_INTERRUPTED)
             {
@@ -287,4 +352,5 @@
                 RTThreadSleep(1000); /* Don't cause trouble! */
             }
+            ASMAtomicWriteBool(&pThis->fBlocked, false);
         }
         else
@@ -292,16 +358,27 @@
             uint64_t        cNanoSeconds;
             const uint64_t  u64NanoTS = RTTimeNanoTS();
-            if (u64NanoTS >= pThis->u64NextTS)
+            uint64_t        u64NextTS = pThis->u64NextTS;
+            if (u64NanoTS >= u64NextTS)
             {
-                pThis->iTick++;
-                pThis->pfnTimer(pThis, pThis->pvUser, pThis->iTick);
+                uint64_t iTick = ++pThis->iTick;
+                pThis->pfnTimer(pThis, pThis->pvUser, iTick);
 
                 /* status changed? */
-                if (    ASMAtomicUoReadBool(&pThis->fSuspended)
-                    ||  ASMAtomicUoReadBool(&pThis->fDestroyed))
+                if (   ASMAtomicUoReadBool(&pThis->fSuspended)
+                    || ASMAtomicUoReadBool(&pThis->fDestroyed))
                     continue;
 
-                /* one shot? */
-                if (!pThis->u64NanoInterval)
+                /*
+                 * Read timer data (it's all volatile and better if we read it all at once):
+                 */
+                iTick = pThis->iTick;
+                uint64_t const u64StartTS       = pThis->u64StartTS;
+                uint64_t const u64NanoInterval  = pThis->u64NanoInterval;
+                ASMCompilerBarrier();
+
+                /*
+                 * Suspend if one shot.
+                 */
+                if (!u64NanoInterval)
                 {
                     ASMAtomicWriteBool(&pThis->fSuspended, true);
@@ -318,24 +395,27 @@
                  * if we're using a non-monotonic clock as time source.
                  */
-                pThis->u64NextTS = pThis->u64StartTS + pThis->iTick * pThis->u64NanoInterval;
-                if (RT_LIKELY(pThis->u64NextTS > u64NanoTS))
-                    cNanoSeconds = pThis->u64NextTS - u64NanoTS;
+                u64NextTS = u64StartTS + iTick * u64NanoInterval;
+                if (RT_LIKELY(u64NextTS > u64NanoTS))
+                    cNanoSeconds = u64NextTS - u64NanoTS;
                 else
                 {
-                    uint64_t iActualTick = (u64NanoTS - pThis->u64StartTS) / pThis->u64NanoInterval;
-                    if (iActualTick - pThis->iTick > 60)
+                    uint64_t iActualTick = (u64NanoTS - u64StartTS) / u64NanoInterval;
+                    if (iActualTick - iTick > 60)
                         pThis->iTick = iActualTick - 1;
 #ifdef IN_RING0
                     cNanoSeconds = RTTimerGetSystemGranularity() / 2;
 #else
-                    cNanoSeconds = 1000000; /* 1ms */
+                    cNanoSeconds = RT_NS_1MS;
 #endif
-                    pThis->u64NextTS = u64NanoTS + cNanoSeconds;
+                    u64NextTS = u64NanoTS + cNanoSeconds;
                 }
+
+                pThis->u64NextTS = u64NextTS;
             }
             else
-                cNanoSeconds = pThis->u64NextTS - u64NanoTS;
+                cNanoSeconds = u64NextTS - u64NanoTS;
 
             /* block. */
+            ASMAtomicWriteBool(&pThis->fBlocked, true);
             int rc = RTSemEventWait(pThis->hEvent,
                                     (RTMSINTERVAL)(cNanoSeconds < 1000000 ? 1 : cNanoSeconds / 1000000));
@@ -345,4 +425,5 @@
                 RTThreadSleep(1000); /* Don't cause trouble! */
             }
+            ASMAtomicWriteBool(&pThis->fBlocked, false);
         }
     }
Index: /trunk/src/VBox/Runtime/testcase/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Runtime/testcase/Makefile.kmk	(revision 80664)
+++ /trunk/src/VBox/Runtime/testcase/Makefile.kmk	(revision 80665)
@@ -141,5 +141,5 @@
 	tstTime-4 \
 	tstTimer \
-	tstTimerLR \
+	tstRTTimerLR \
 	tstRTTimeSpec \
 	tstRTUdp-1 \
@@ -698,6 +698,6 @@
 tstTimer_SOURCES = tstTimer.cpp
 
-tstTimerLR_TEMPLATE = VBOXR3TSTEXE
-tstTimerLR_SOURCES = tstTimerLR.cpp
+tstRTTimerLR_TEMPLATE = VBOXR3TSTEXE
+tstRTTimerLR_SOURCES = tstRTTimerLR.cpp
 
 tstRTTimeSpec_TEMPLATE = VBOXR3TSTEXE
Index: /trunk/src/VBox/Runtime/testcase/tstRTTimerLR.cpp
===================================================================
--- /trunk/src/VBox/Runtime/testcase/tstRTTimerLR.cpp	(revision 80665)
+++ /trunk/src/VBox/Runtime/testcase/tstRTTimerLR.cpp	(revision 80665)
@@ -0,0 +1,262 @@
+/* $Id$ */
+/** @file
+ * IPRT Testcase - Low Resolution Timers.
+ */
+
+/*
+ * Copyright (C) 2006-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+*   Header Files                                                                                                                 *
+*********************************************************************************************************************************/
+#include <iprt/timer.h>
+
+#include <iprt/errcore.h>
+#include <iprt/message.h>
+#include <iprt/stream.h>
+#include <iprt/test.h>
+#include <iprt/thread.h>
+#include <iprt/time.h>
+
+
+/*********************************************************************************************************************************
+*   Global Variables                                                                                                             *
+*********************************************************************************************************************************/
+static volatile unsigned gcTicks;
+static volatile uint64_t gu64Min;
+static volatile uint64_t gu64Max;
+static volatile uint64_t gu64Prev;
+
+
+static DECLCALLBACK(void) TimerLRCallback(RTTIMERLR hTimerLR, void *pvUser, uint64_t iTick)
+{
+    RT_NOREF_PV(hTimerLR); RT_NOREF_PV(pvUser); RT_NOREF_PV(iTick);
+
+    gcTicks++;
+
+    const uint64_t u64Now = RTTimeNanoTS();
+    if (gu64Prev)
+    {
+        const uint64_t u64Delta = u64Now - gu64Prev;
+        if (u64Delta < gu64Min)
+            gu64Min = u64Delta;
+        if (u64Delta > gu64Max)
+            gu64Max = u64Delta;
+    }
+    gu64Prev = u64Now;
+}
+
+
+int main()
+{
+    /*
+     * Init runtime
+     */
+    RTTEST hTest;
+    RTEXITCODE rcExit = RTTestInitAndCreate("tstRTTimerLR", &hTest);
+    if (rcExit != RTEXITCODE_SUCCESS)
+        return rcExit;
+
+    /*
+     * Check that the clock is reliable.
+     */
+    RTTestSub(hTest, "RTTimeNanoTS() for 2sec");
+    uint64_t uTSMillies = RTTimeMilliTS();
+    uint64_t uTSBegin = RTTimeNanoTS();
+    uint64_t uTSLast = uTSBegin;
+    uint64_t uTSDiff;
+    uint64_t cIterations = 0;
+
+    do
+    {
+        uint64_t uTS = RTTimeNanoTS();
+        if (uTS < uTSLast)
+            RTTestFailed(hTest, "RTTimeNanoTS() is unreliable. uTS=%RU64 uTSLast=%RU64", uTS, uTSLast);
+        if (++cIterations > 2*1000*1000*1000)
+        {
+            RTTestFailed(hTest, "RTTimeNanoTS() is unreliable. cIterations=%RU64 uTS=%RU64 uTSBegin=%RU64",
+                         cIterations, uTS, uTSBegin);
+            return RTTestSummaryAndDestroy(hTest);
+        }
+        uTSLast = uTS;
+        uTSDiff = uTSLast - uTSBegin;
+    } while (uTSDiff < (2*1000*1000*1000));
+    uTSMillies = RTTimeMilliTS() - uTSMillies;
+    if (uTSMillies >= 2500 || uTSMillies <= 1500)
+        RTTestFailed(hTest, "uTSMillies=%RI64 uTSBegin=%RU64 uTSLast=%RU64 uTSDiff=%RU64",
+                     uTSMillies, uTSBegin, uTSLast, uTSDiff);
+
+    /*
+     * Tests.
+     */
+    static struct
+    {
+        unsigned uMilliesInterval;
+        unsigned uMilliesWait;
+        unsigned cLower;
+        unsigned cUpper;
+    } aTests[] =
+    {
+        { 1000, 2500, 3,   3 }, /* (keep in mind the immediate first tick) */
+        {  250, 2000, 6,  10 },
+        {  100, 2000, 17, 23 },
+    };
+
+    int rc;
+    unsigned i = 0;
+    for (i = 0; i < RT_ELEMENTS(aTests); i++)
+    {
+        //aTests[i].cLower = (aTests[i].uMilliesWait - aTests[i].uMilliesWait / 10) / aTests[i].uMilliesInterval;
+        //aTests[i].cUpper = (aTests[i].uMilliesWait + aTests[i].uMilliesWait / 10) / aTests[i].uMilliesInterval;
+
+        RTTestSubF(hTest, "%d ms interval, %d ms wait, expects %d-%d ticks",
+                   aTests[i].uMilliesInterval, aTests[i].uMilliesWait, aTests[i].cLower, aTests[i].cUpper);
+
+        /*
+         * Start timer which ticks every 10ms.
+         */
+        gcTicks = 0;
+        RTTIMERLR hTimerLR;
+        gu64Max = 0;
+        gu64Min = UINT64_MAX;
+        gu64Prev = 0;
+        rc = RTTimerLRCreateEx(&hTimerLR, aTests[i].uMilliesInterval * (uint64_t)1000000, 0, TimerLRCallback, NULL);
+        if (RT_FAILURE(rc))
+        {
+            RTTestFailed(hTest, "RTTimerLRCreateEX(,%u*1M,,,) -> %Rrc", aTests[i].uMilliesInterval, rc);
+            continue;
+        }
+
+        /*
+         * Start the timer an actively wait for it for the period requested.
+         */
+        uTSBegin = RTTimeNanoTS();
+        rc = RTTimerLRStart(hTimerLR, 0);
+        if (RT_FAILURE(rc))
+            RTTestFailed(hTest, "RTTimerLRStart() -> %Rrc", rc);
+
+        while (RTTimeNanoTS() - uTSBegin < (uint64_t)aTests[i].uMilliesWait * 1000000)
+            RTThreadSleep(1);
+
+        /* don't stop it, destroy it because there are potential races in destroying an active timer. */
+        rc = RTTimerLRDestroy(hTimerLR);
+        if (RT_FAILURE(rc))
+            RTTestFailed(hTest, "RTTimerLRDestroy() -> %Rrc gcTicks=%d", rc, gcTicks);
+
+        uint64_t uTSEnd = RTTimeNanoTS();
+        uTSDiff = uTSEnd - uTSBegin;
+        RTTestPrintf(hTest, RTTESTLVL_ALWAYS, "uTS=%'RI64 (%'RU64 - %'RU64) gcTicks=%u min=%'RU64 max=%'RU64\n",
+                     uTSDiff, uTSBegin, uTSEnd, gcTicks, gu64Min, gu64Max);
+
+        /* Check that it really stopped. */
+        unsigned cTicks = gcTicks;
+        RTThreadSleep(aTests[i].uMilliesInterval * 2);
+        if (gcTicks != cTicks)
+        {
+            RTTestFailed(hTest, "RTTimerLRDestroy() didn't really stop the timer! gcTicks=%d cTicks=%d", gcTicks, cTicks);
+            continue;
+        }
+
+        /*
+         * Check the number of ticks.
+         */
+        if (gcTicks < aTests[i].cLower)
+            RTTestFailed(hTest, "Too few ticks gcTicks=%d (expected %d-%d)", gcTicks, aTests[i].cUpper, aTests[i].cLower);
+        else if (gcTicks > aTests[i].cUpper)
+            RTTestFailed(hTest, "Too many ticks gcTicks=%d (expected %d-%d)", gcTicks, aTests[i].cUpper, aTests[i].cLower);
+    }
+
+    /*
+     * Test changing the interval dynamically
+     */
+    RTTestSub(hTest, "RTTimerLRChangeInterval");
+    do
+    {
+        RTTIMERLR hTimerLR;
+        rc = RTTimerLRCreateEx(&hTimerLR, aTests[0].uMilliesInterval * (uint64_t)1000000, 0, TimerLRCallback, NULL);
+        if (RT_FAILURE(rc))
+        {
+            RTTestFailed(hTest, "RTTimerLRCreateEX(,%u*1M,,,) -> %Rrc", aTests[0].uMilliesInterval, rc);
+            break;
+        }
+
+        for (i = 0; i < RT_ELEMENTS(aTests); i++)
+        {
+            RTTestPrintf(hTest, RTTESTLVL_ALWAYS, "%d ms interval, %d ms wait, expects %d-%d ticks.\n",
+                         aTests[i].uMilliesInterval, aTests[i].uMilliesWait, aTests[i].cLower, aTests[i].cUpper);
+
+            gcTicks = 0;
+            gu64Max = 0;
+            gu64Min = UINT64_MAX;
+            gu64Prev = 0;
+
+            /*
+             * Start the timer an actively wait for it for the period requested.
+             */
+            uTSBegin = RTTimeNanoTS();
+            if (i == 0)
+            {
+                rc = RTTimerLRStart(hTimerLR, 0);
+                if (RT_FAILURE(rc))
+                    RTTestFailed(hTest, "RTTimerLRStart() -> %Rrc", rc);
+            }
+            else
+            {
+                rc = RTTimerLRChangeInterval(hTimerLR, aTests[i].uMilliesInterval * RT_NS_1MS_64);
+                if (RT_FAILURE(rc))
+                    RTTestFailed(hTest, "RTTimerLRChangeInterval() -> %d gcTicks=%d", rc, gcTicks);
+            }
+
+            while (RTTimeNanoTS() - uTSBegin < (uint64_t)aTests[i].uMilliesWait * RT_NS_1MS_64)
+                RTThreadSleep(1);
+
+            uint64_t uTSEnd = RTTimeNanoTS();
+            uTSDiff = uTSEnd - uTSBegin;
+            RTTestPrintf(hTest, RTTESTLVL_ALWAYS, "uTS=%'RI64 (%'RU64 - %'RU64) gcTicks=%u min=%'RU64 max=%'RU64\n",
+                         uTSDiff, uTSBegin, uTSEnd, gcTicks, gu64Min, gu64Max);
+
+            /*
+             * Check the number of ticks.
+             */
+            if (gcTicks < aTests[i].cLower)
+                RTTestFailed(hTest, "Too few ticks gcTicks=%d (expected %d-%d)", gcTicks, aTests[i].cUpper, aTests[i].cLower);
+            else if (gcTicks > aTests[i].cUpper)
+                RTTestFailed(hTest, "Too many ticks gcTicks=%d (expected %d-%d)", gcTicks, aTests[i].cUpper, aTests[i].cLower);
+        }
+
+        /* don't stop it, destroy it because there are potential races in destroying an active timer. */
+        rc = RTTimerLRDestroy(hTimerLR);
+        if (RT_FAILURE(rc))
+            RTTestFailed(hTest, "RTTimerLRDestroy() -> %d gcTicks=%d", rc, gcTicks);
+    } while (0);
+
+    /*
+     * Test multiple timers running at once.
+     */
+    /** @todo multiple LR timer testcase. */
+
+    /*
+     * Summary.
+     */
+    return RTTestSummaryAndDestroy(hTest);
+}
+
Index: unk/src/VBox/Runtime/testcase/tstTimerLR.cpp
===================================================================
--- /trunk/src/VBox/Runtime/testcase/tstTimerLR.cpp	(revision 80664)
+++ 	(revision )
@@ -1,306 +1,0 @@
-/* $Id$ */
-/** @file
- * IPRT Testcase - Low Resolution Timers.
- */
-
-/*
- * Copyright (C) 2006-2019 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- *
- * The contents of this file may alternatively be used under the terms
- * of the Common Development and Distribution License Version 1.0
- * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
- * VirtualBox OSE distribution, in which case the provisions of the
- * CDDL are applicable instead of those of the GPL.
- *
- * You may elect to license modified versions of this file under the
- * terms and conditions of either the GPL or the CDDL or both.
- */
-
-
-/*********************************************************************************************************************************
-*   Header Files                                                                                                                 *
-*********************************************************************************************************************************/
-#include <iprt/timer.h>
-#include <iprt/time.h>
-#include <iprt/thread.h>
-#include <iprt/initterm.h>
-#include <iprt/message.h>
-#include <iprt/stream.h>
-#include <iprt/errcore.h>
-
-
-
-/*********************************************************************************************************************************
-*   Global Variables                                                                                                             *
-*********************************************************************************************************************************/
-static volatile unsigned gcTicks;
-static volatile uint64_t gu64Min;
-static volatile uint64_t gu64Max;
-static volatile uint64_t gu64Prev;
-
-static DECLCALLBACK(void) TimerLRCallback(RTTIMERLR hTimerLR, void *pvUser, uint64_t iTick)
-{
-    RT_NOREF_PV(hTimerLR); RT_NOREF_PV(pvUser); RT_NOREF_PV(iTick);
-
-    gcTicks++;
-
-    const uint64_t u64Now = RTTimeNanoTS();
-    if (gu64Prev)
-    {
-        const uint64_t u64Delta = u64Now - gu64Prev;
-        if (u64Delta < gu64Min)
-            gu64Min = u64Delta;
-        if (u64Delta > gu64Max)
-            gu64Max = u64Delta;
-    }
-    gu64Prev = u64Now;
-}
-
-
-int main()
-{
-    /*
-     * Init runtime
-     */
-    unsigned cErrors = 0;
-    int rc = RTR3InitExeNoArguments(0);
-    if (RT_FAILURE(rc))
-        return RTMsgInitFailure(rc);
-
-    /*
-     * Check that the clock is reliable.
-     */
-    RTPrintf("tstTimer: TESTING - RTTimeNanoTS() for 2sec\n");
-    uint64_t uTSMillies = RTTimeMilliTS();
-    uint64_t uTSBegin = RTTimeNanoTS();
-    uint64_t uTSLast = uTSBegin;
-    uint64_t uTSDiff;
-    uint64_t cIterations = 0;
-
-    do
-    {
-        uint64_t uTS = RTTimeNanoTS();
-        if (uTS < uTSLast)
-        {
-            RTPrintf("tstTimer: FAILURE - RTTimeNanoTS() is unreliable. uTS=%RU64 uTSLast=%RU64\n", uTS, uTSLast);
-            cErrors++;
-        }
-        if (++cIterations > (2*1000*1000*1000))
-        {
-            RTPrintf("tstTimer: FAILURE - RTTimeNanoTS() is unreliable. cIterations=%RU64 uTS=%RU64 uTSBegin=%RU64\n", cIterations, uTS, uTSBegin);
-            return 1;
-        }
-        uTSLast = uTS;
-        uTSDiff = uTSLast - uTSBegin;
-    } while (uTSDiff < (2*1000*1000*1000));
-    uTSMillies = RTTimeMilliTS() - uTSMillies;
-    if (uTSMillies >= 2500 || uTSMillies <= 1500)
-    {
-        RTPrintf("tstTimer: FAILURE - uTSMillies=%RI64 uTSBegin=%RU64 uTSLast=%RU64 uTSDiff=%RU64\n",
-                 uTSMillies, uTSBegin, uTSLast, uTSDiff);
-        cErrors++;
-    }
-    if (!cErrors)
-        RTPrintf("tstTimer: OK      - RTTimeNanoTS()\n");
-
-    /*
-     * Tests.
-     */
-    static struct
-    {
-        unsigned uMilliesInterval;
-        unsigned uMilliesWait;
-        unsigned cLower;
-        unsigned cUpper;
-    } aTests[] =
-    {
-        { 1000, 2500, 3,   3 }, /* (keep in mind the immediate first tick) */
-        {  250, 2000, 6,  10 },
-        {  100, 2000, 17, 23 },
-    };
-
-    unsigned i = 0;
-    for (i = 0; i < RT_ELEMENTS(aTests); i++)
-    {
-        //aTests[i].cLower = (aTests[i].uMilliesWait - aTests[i].uMilliesWait / 10) / aTests[i].uMilliesInterval;
-        //aTests[i].cUpper = (aTests[i].uMilliesWait + aTests[i].uMilliesWait / 10) / aTests[i].uMilliesInterval;
-
-        RTPrintf("\n"
-                 "tstTimer: TESTING - %d ms interval, %d ms wait, expects %d-%d ticks.\n",
-                 aTests[i].uMilliesInterval, aTests[i].uMilliesWait, aTests[i].cLower, aTests[i].cUpper);
-
-        /*
-         * Start timer which ticks every 10ms.
-         */
-        gcTicks = 0;
-        RTTIMERLR hTimerLR;
-        gu64Max = 0;
-        gu64Min = UINT64_MAX;
-        gu64Prev = 0;
-        rc = RTTimerLRCreateEx(&hTimerLR, aTests[i].uMilliesInterval * (uint64_t)1000000, 0, TimerLRCallback, NULL);
-        if (RT_FAILURE(rc))
-        {
-            RTPrintf("RTTimerLRCreateEX(,%u*1M,,,) -> %d\n", aTests[i].uMilliesInterval, rc);
-            cErrors++;
-            continue;
-        }
-
-        /*
-         * Start the timer an actively wait for it for the period requested.
-         */
-        uTSBegin = RTTimeNanoTS();
-        rc = RTTimerLRStart(hTimerLR, 0);
-        if (RT_FAILURE(rc))
-        {
-            RTPrintf("tstTimer: FAILURE - RTTimerLRStart() -> %Rrc\n", rc);
-            cErrors++;
-        }
-
-        while (RTTimeNanoTS() - uTSBegin < (uint64_t)aTests[i].uMilliesWait * 1000000)
-            /* nothing */;
-
-        /* don't stop it, destroy it because there are potential races in destroying an active timer. */
-        rc = RTTimerLRDestroy(hTimerLR);
-        if (RT_FAILURE(rc))
-        {
-            RTPrintf("tstTimer: FAILURE - RTTimerLRDestroy() -> %d gcTicks=%d\n", rc, gcTicks);
-            cErrors++;
-        }
-
-        uint64_t uTSEnd = RTTimeNanoTS();
-        uTSDiff = uTSEnd - uTSBegin;
-        RTPrintf("uTS=%RI64 (%RU64 - %RU64)\n", uTSDiff, uTSBegin, uTSEnd);
-
-        /* Check that it really stopped. */
-        unsigned cTicks = gcTicks;
-        RTThreadSleep(aTests[i].uMilliesInterval * 2);
-        if (gcTicks != cTicks)
-        {
-            RTPrintf("tstTimer: FAILURE - RTTimerLRDestroy() didn't really stop the timer! gcTicks=%d cTicks=%d\n", gcTicks, cTicks);
-            cErrors++;
-            continue;
-        }
-
-        /*
-         * Check the number of ticks.
-         */
-        if (gcTicks < aTests[i].cLower)
-        {
-            RTPrintf("tstTimer: FAILURE - Too few ticks gcTicks=%d (expected %d-%d)", gcTicks, aTests[i].cUpper, aTests[i].cLower);
-            cErrors++;
-        }
-        else if (gcTicks > aTests[i].cUpper)
-        {
-            RTPrintf("tstTimer: FAILURE - Too many ticks gcTicks=%d (expected %d-%d)", gcTicks, aTests[i].cUpper, aTests[i].cLower);
-            cErrors++;
-        }
-        else
-            RTPrintf("tstTimer: OK      - gcTicks=%d",  gcTicks);
-        RTPrintf(" min=%RU64 max=%RU64\n", gu64Min, gu64Max);
-    }
-
-    /*
-     * Test changing the interval dynamically
-     */
-    RTPrintf("\n"
-             "tstTimer: Testing dynamic changes of timer interval...\n");
-    do
-    {
-        RTTIMERLR hTimerLR;
-        rc = RTTimerLRCreateEx(&hTimerLR, aTests[0].uMilliesInterval * (uint64_t)1000000, 0, TimerLRCallback, NULL);
-        if (RT_FAILURE(rc))
-        {
-            RTPrintf("RTTimerLRCreateEX(,%u*1M,,,) -> %d\n", aTests[0].uMilliesInterval, rc);
-            cErrors++;
-            continue;
-        }
-
-        for (i = 0; i < RT_ELEMENTS(aTests); i++)
-        {
-            RTPrintf("\n"
-                     "tstTimer: TESTING - %d ms interval, %d ms wait, expects %d-%d ticks.\n",
-                     aTests[i].uMilliesInterval, aTests[i].uMilliesWait, aTests[i].cLower, aTests[i].cUpper);
-
-            gcTicks = 0;
-            gu64Max = 0;
-            gu64Min = UINT64_MAX;
-            gu64Prev = 0;
-            /*
-             * Start the timer an actively wait for it for the period requested.
-             */
-            uTSBegin = RTTimeNanoTS();
-            if (i == 0)
-            {
-                rc = RTTimerLRStart(hTimerLR, 0);
-                if (RT_FAILURE(rc))
-                {
-                    RTPrintf("tstTimer: FAILURE - RTTimerLRStart() -> %Rrc\n", rc);
-                    cErrors++;
-                }
-            }
-            else
-            {
-                rc = RTTimerLRChangeInterval(hTimerLR, aTests[i].uMilliesInterval * (uint64_t)1000000);
-                if (RT_FAILURE(rc))
-                {
-                    RTPrintf("tstTimer: FAILURE - RTTimerLRChangeInterval() -> %d gcTicks=%d\n", rc, gcTicks);
-                    cErrors++;
-                }
-            }
-
-            while (RTTimeNanoTS() - uTSBegin < (uint64_t)aTests[i].uMilliesWait * 1000000)
-                /* nothing */;
-
-            uint64_t uTSEnd = RTTimeNanoTS();
-            uTSDiff = uTSEnd - uTSBegin;
-            RTPrintf("uTS=%RI64 (%RU64 - %RU64)\n", uTSDiff, uTSBegin, uTSEnd);
-
-            /*
-             * Check the number of ticks.
-             */
-            if (gcTicks < aTests[i].cLower)
-            {
-                RTPrintf("tstTimer: FAILURE - Too few ticks gcTicks=%d (expected %d-%d)\n", gcTicks, aTests[i].cUpper, aTests[i].cLower);
-                cErrors++;
-            }
-            else if (gcTicks > aTests[i].cUpper)
-            {
-                RTPrintf("tstTimer: FAILURE - Too many ticks gcTicks=%d (expected %d-%d)\n", gcTicks, aTests[i].cUpper, aTests[i].cLower);
-                cErrors++;
-            }
-            else
-                RTPrintf("tstTimer: OK      - gcTicks=%d\n",  gcTicks);
-            // RTPrintf(" min=%RU64 max=%RU64\n", gu64Min, gu64Max);
-        }
-        /* don't stop it, destroy it because there are potential races in destroying an active timer. */
-        rc = RTTimerLRDestroy(hTimerLR);
-        if (RT_FAILURE(rc))
-        {
-            RTPrintf("tstTimer: FAILURE - RTTimerLRDestroy() -> %d gcTicks=%d\n", rc, gcTicks);
-            cErrors++;
-        }
-    } while (0);
-
-    /*
-     * Test multiple timers running at once.
-     */
-    /** @todo multiple LR timer testcase. */
-
-    /*
-     * Summary.
-     */
-    if (!cErrors)
-        RTPrintf("tstTimer: SUCCESS\n");
-    else
-        RTPrintf("tstTimer: FAILURE %d errors\n", cErrors);
-    return !!cErrors;
-}
-
