Index: /trunk/include/iprt/timer.h
===================================================================
--- /trunk/include/iprt/timer.h	(revision 10943)
+++ /trunk/include/iprt/timer.h	(revision 10944)
@@ -220,4 +220,94 @@
 RTDECL(int) RTTimerReleaseSystemGranularity(uint32_t u32Granted);
 
+
+
+/**
+ * Timer callback function for low res timers.
+ *
+ * This is identfical to FNRTTIMER except for the first parameter, so
+ * see FNRTTIMER for details.
+ *
+ * @param   hTimerLR    The low resolution timer handle.
+ * @param   pvUser      User argument.
+ * @param   iTick       The current timer tick. This is always 1 on the first
+ *                      callback after the timer was started. For omni timers
+ *                      this will be 1 when a cpu comes back online.
+ */
+typedef DECLCALLBACK(void) FNRTTIMERLR(RTTIMERLR hTimerLR, void *pvUser, uint64_t iTick);
+/** Pointer to FNRTTIMER() function. */
+typedef FNRTTIMERLR *PFNRTTIMERLR;
+
+
+/**
+ * Create a recurring low resolution timer.
+ *
+ * @returns iprt status code.
+ * @param   phTimerLR           Where to store the timer handle.
+ * @param   uMilliesInterval    Milliseconds between the timer ticks, at least 100 ms.
+ *                              If higher resolution is required use the other API.
+ * @param   pfnTimer            Callback function which shall be scheduled for execution
+ *                              on every timer tick.
+ * @param   pvUser              User argument for the callback.
+ * @see     RTTimerLRCreateEx, RTTimerLRDestroy, RTTimerLRStop
+ */
+RTDECL(int) RTTimerLRCreate(PRTTIMERLR phTimerLR, uint32_t uMilliesInterval, PFNRTTIMERLR pfnTimer, void *pvUser);
+
+/**
+ * Create a suspended low resolution timer.
+ *
+ * @returns iprt status code.
+ * @retval  VERR_NOT_SUPPORTED if an unsupported flag was specfied.
+ *
+ * @param   phTimerLR           Where to store the timer handle.
+ * @param   u64NanoInterval     The interval between timer ticks specified in nanoseconds if it's
+ *                              a recurring timer, the minimum for is 100000000 ns.
+ *                              For one shot timers, pass 0.
+ * @param   fFlags              Timer flags. Same as RTTimerCreateEx.
+ * @param   pfnTimer            Callback function which shall be scheduled for execution
+ *                              on every timer tick.
+ * @param   pvUser              User argument for the callback.
+ * @see     RTTimerLRStart, RTTimerLRStop, RTTimerLRDestroy
+ */
+RTDECL(int) RTTimerLRCreateEx(PRTTIMERLR phTimerLR, uint64_t u64NanoInterval, uint32_t fFlags, PFNRTTIMERLR pfnTimer, void *pvUser);
+
+/**
+ * Stops and destroys a running low resolution timer.
+ *
+ * @returns iprt status code.
+ * @param   hTimerLR            The low resolution timer to stop and destroy.
+ *                              NIL_RTTIMERLR is accepted.
+ */
+RTDECL(int) RTTimerLRDestroy(RTTIMERLR hTimerLR);
+
+/**
+ * Stops an active low resolution timer.
+ *
+ * @returns IPRT status code.
+ * @retval  VERR_INVALID_HANDLE if pTimer isn't valid.
+ * @retval  VERR_TIMER_ACTIVE if the timer isn't suspended.
+ *
+ * @param   hTimerLR            The low resolution timer to activate.
+ * @param   u64First            The RTTimeSystemNanoTS() for when the timer should start
+ *                              firing (relative), the minimum is 100000000 ns.
+ *                              If 0 is specified, the timer will fire ASAP.
+ *
+ * @see     RTTimerLRStop
+ */
+RTDECL(int) RTTimerLRStart(RTTIMERLR hTimerLR, uint64_t u64First);
+
+/**
+ * Stops an active low resolution timer.
+ *
+ * @returns IPRT status code.
+ * @retval  VERR_INVALID_HANDLE if pTimer isn't valid.
+ * @retval  VERR_TIMER_SUSPENDED if the timer isn't active.
+ * @retval  VERR_NOT_SUPPORTED if the IPRT implementation doesn't support stopping a timer.
+ *
+ * @param   hTimerLR            The low resolution timer to suspend.
+ *
+ * @see     RTTimerLRStart
+ */
+RTDECL(int) RTTimerLRStop(RTTIMERLR hTimerLR);
+
 /** @} */
 
Index: /trunk/include/iprt/types.h
===================================================================
--- /trunk/include/iprt/types.h	(revision 10943)
+++ /trunk/include/iprt/types.h	(revision 10944)
@@ -1139,4 +1139,12 @@
 #define NIL_RTHANDLETABLE                           ((RTHANDLETABLE)0)
 
+/** A handle to a low resolution timer. */
+typedef struct RTTIMERLRINT                        *RTTIMERLR;
+/** A pointer to a low resolution timer handle. */
+typedef RTTIMERLR                                  *PRTTIMERLR;
+/** @def NIL_RTTIMERLR
+ * NIL low resolution timer handle value. */
+#define NIL_RTTIMERLR                               ((RTTIMERLR)0)
+
 
 /**
Index: /trunk/src/VBox/Runtime/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Runtime/Makefile.kmk	(revision 10943)
+++ /trunk/src/VBox/Runtime/Makefile.kmk	(revision 10944)
@@ -240,6 +240,8 @@
 	generic/RTLogWriteStdOut-generic.cpp \
 	generic/RTLogWriteUser-generic.cpp \
+	generic/RTTimerLRCreate-generic.cpp \
 	generic/semfastmutex-generic.cpp \
 	generic/spinlock-generic.cpp \
+	generic/timerlr-generic.cpp \
 	r3/alloc-ef.cpp \
 	r3/alloc.cpp \
Index: /trunk/src/VBox/Runtime/generic/RTTimerLRCreate-generic.cpp
===================================================================
--- /trunk/src/VBox/Runtime/generic/RTTimerLRCreate-generic.cpp	(revision 10944)
+++ /trunk/src/VBox/Runtime/generic/RTTimerLRCreate-generic.cpp	(revision 10944)
@@ -0,0 +1,53 @@
+/** $Id$ */
+/** @file
+ * IPRT - Low Resolution Timers, Generic RTTimerLRCreate() Implementation.
+ */
+
+/*
+ * Copyright (C) 2006-2008 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <iprt/timer.h>
+#include <iprt/err.h>
+#include <iprt/assert.h>
+
+
+RTDECL(int) RTTimerLRCreate(PRTTIMERLR phTimerLR, uint32_t uMilliesInterval, PFNRTTIMERLR pfnTimer, void *pvUser)
+{
+    int rc = RTTimerLRCreateEx(phTimerLR, uMilliesInterval * UINT64_C(1000000), 0, pfnTimer, pvUser);
+    if (RT_SUCCESS(rc))
+    {
+        rc = RTTimerLRStart(*phTimerLR, 0);
+        if (RT_SUCCESS(rc))
+            return rc;
+        int rc2 = RTTimerLRDestroy(*phTimerLR); AssertRC(rc2);
+        *phTimerLR = NIL_RTTIMERLR;
+    }
+    return rc;
+}
+
Index: /trunk/src/VBox/Runtime/generic/timerlr-generic.cpp
===================================================================
--- /trunk/src/VBox/Runtime/generic/timerlr-generic.cpp	(revision 10944)
+++ /trunk/src/VBox/Runtime/generic/timerlr-generic.cpp	(revision 10944)
@@ -0,0 +1,312 @@
+/** $Id$ */
+/** @file
+ * IPRT - Low Resolution Timers, Generic.
+ *
+ * This code is more or less identicial to timer-generic.cpp, so
+ * bugfixes goes into both files.
+ */
+
+/*
+ * Copyright (C) 2006-2008 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <iprt/timer.h>
+#include <iprt/thread.h>
+#include <iprt/err.h>
+#include <iprt/assert.h>
+#include <iprt/alloc.h>
+#include <iprt/asm.h>
+#include <iprt/semaphore.h>
+#include <iprt/time.h>
+#include <iprt/log.h>
+#include "internal/magics.h"
+
+
+/*******************************************************************************
+*   Structures and Typedefs                                                    *
+*******************************************************************************/
+/**
+ * The internal representation of a timer handle.
+ */
+typedef struct RTTIMERLRINT
+{
+    /** Magic.
+     * This is RTTIMERRT_MAGIC, but changes to something else before the timer
+     * is destroyed to indicate clearly that thread should exit. */
+    uint32_t volatile       u32Magic;
+    /** Flag indicating the the timer is suspended. */
+    bool volatile           fSuspended;
+    /** Flag indicating that the timer has been destroyed. */
+    bool volatile           fDestroyed;
+    /** Callback. */
+    PFNRTTIMERLR            pfnTimer;
+    /** User argument. */
+    void                   *pvUser;
+    /** The timer thread. */
+    RTTHREAD                hThread;
+    /** 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;
+
+
+/*******************************************************************************
+*   Internal Functions                                                         *
+*******************************************************************************/
+static DECLCALLBACK(int) rtTimerLRThread(RTTHREAD hThread, void *pvUser);
+
+
+RTDECL(int) RTTimerLRCreateEx(RTTIMERLR *phTimerLR, uint64_t u64NanoInterval, uint32_t fFlags, PFNRTTIMERLR pfnTimer, void *pvUser)
+{
+    AssertPtr(phTimerLR);
+    *phTimerLR = NIL_RTTIMERLR;
+
+    /*
+     * 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 < 100*1000*1000)
+        return VERR_INVALID_PARAMETER;
+
+    /*
+     * Allocate and initialize the timer handle.
+     */
+    PRTTIMERLRINT pThis = (PRTTIMERLRINT)RTMemAlloc(sizeof(*pThis));
+    if (!pThis)
+        return VERR_NO_MEMORY;
+
+    pThis->u32Magic = RTTIMERLR_MAGIC;
+    pThis->fSuspended = true;
+    pThis->fDestroyed = false;
+    pThis->pfnTimer = pfnTimer;
+    pThis->pvUser = pvUser;
+    pThis->hThread = NIL_RTTHREAD;
+    pThis->hEvent = NIL_RTSEMEVENT;
+    pThis->u64NanoInterval = u64NanoInterval;
+    pThis->u64StartTS = 0;
+
+    int rc = RTSemEventCreate(&pThis->hEvent);
+    if (RT_SUCCESS(rc))
+    {
+        rc = RTThreadCreate(&pThis->hThread, rtTimerLRThread, pThis, 0, RTTHREADTYPE_TIMER, RTTHREADFLAGS_WAITABLE, "TIMER");
+        if (RT_SUCCESS(rc))
+        {
+            *phTimerLR = pThis;
+            return VINF_SUCCESS;
+        }
+
+        pThis->u32Magic = 0;
+        RTSemEventDestroy(pThis->hEvent);
+        pThis->hEvent = NIL_RTSEMEVENT;
+    }
+    RTMemFree(pThis);
+
+    return rc;
+}
+
+
+RTDECL(int) RTTimerLRDestroy(RTTIMERLR hTimerLR)
+{
+    /*
+     * Validate input, NIL is fine though.
+     */
+    if (hTimerLR == NIL_RTTIMERLR)
+        return VINF_SUCCESS;
+    PRTTIMERLRINT pThis = hTimerLR;
+    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+    AssertReturn(pThis->u32Magic == RTTIMERLR_MAGIC, VERR_INVALID_HANDLE);
+    AssertReturn(!pThis->fDestroyed, VERR_INVALID_HANDLE);
+
+    /*
+     * If the timer is active, we just flag it to self destruct on the next tick.
+     * If it's suspended we can safely set the destroy flag and signal it.
+     */
+    RTTHREAD hThread = pThis->hThread;
+    if (!pThis->fSuspended)
+    {
+        ASMAtomicWriteBool(&pThis->fSuspended, true);
+        ASMAtomicWriteBool(&pThis->fDestroyed, true);
+    }
+    else
+    {
+        ASMAtomicWriteBool(&pThis->fDestroyed, true);
+        int rc = RTSemEventSignal(pThis->hEvent);
+        if (rc == VERR_ALREADY_POSTED)
+            rc = VINF_SUCCESS;
+        AssertRC(rc);
+    }
+
+    RTThreadWait(hThread, 250, NULL);
+    return VINF_SUCCESS;
+}
+
+
+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;
+
+    if (!pThis->fSuspended)
+        return VERR_TIMER_ACTIVE;
+
+    /*
+     * Calc when it should start fireing and give the thread a kick so it get going.
+     */
+    u64First += RTTimeNanoTS();
+    ASMAtomicWriteU64(&pThis->iTick, 0);
+    ASMAtomicWriteU64(&pThis->u64StartTS, u64First);
+    ASMAtomicWriteU64(&pThis->u64NextTS, u64First);
+    ASMAtomicWriteBool(&pThis->fSuspended, false);
+    int rc = RTSemEventSignal(pThis->hEvent);
+    if (rc == VERR_ALREADY_POSTED)
+        rc = VINF_SUCCESS;
+    AssertRC(rc);
+    return rc;
+}
+
+
+RTDECL(int) RTTimerLRStop(RTTIMERLR hTimerLR)
+{
+    /*
+     * 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 (pThis->fSuspended)
+        return VERR_TIMER_SUSPENDED;
+
+    /*
+     * Mark it as suspended and kick the thread.
+     */
+    ASMAtomicWriteBool(&pThis->fSuspended, true);
+    int rc = RTSemEventSignal(pThis->hEvent);
+    if (rc == VERR_ALREADY_POSTED)
+        rc = VINF_SUCCESS;
+    AssertRC(rc);
+    return rc;
+}
+
+
+static DECLCALLBACK(int) rtTimerLRThread(RTTHREAD hThread, void *pvUser)
+{
+    PRTTIMERLRINT pThis = (PRTTIMERLRINT)pvUser;
+
+    /*
+     * The loop.
+     */
+    while (!ASMAtomicUoReadBool(&pThis->fDestroyed))
+    {
+        if (ASMAtomicUoReadBool(&pThis->fSuspended))
+        {
+            int rc = RTSemEventWait(pThis->hEvent, RT_INDEFINITE_WAIT);
+            if (RT_FAILURE(rc) && rc != VERR_INTERRUPTED)
+            {
+                AssertRC(rc);
+                RTThreadSleep(1000); /* Don't cause trouble! */
+            }
+        }
+        else
+        {
+            const uint64_t u64NanoTS = RTTimeNanoTS();
+            if (u64NanoTS >= pThis->u64NextTS)
+            {
+                pThis->iTick++;
+                pThis->pfnTimer(pThis, pThis->pvUser, pThis->iTick);
+
+                /* status changed? */
+                if (    ASMAtomicUoReadBool(&pThis->fSuspended)
+                    ||  ASMAtomicUoReadBool(&pThis->fDestroyed))
+                    continue;
+
+                /* one shot? */
+                if (!pThis->u64NanoInterval)
+                {
+                    ASMAtomicWriteBool(&pThis->fSuspended, true);
+                    continue;
+                }
+
+                /* calc the next time we should fire. */
+                pThis->u64NextTS = pThis->u64StartTS + pThis->iTick * pThis->u64NanoInterval;
+                if (pThis->u64NextTS < u64NanoTS)
+#ifdef IN_RING3 /* In ring-3 we'll catch up lost ticks immediately. */
+                    pThis->u64NextTS = u64NanoTS + 1;
+#else
+                    pThis->u64NextTS = u64NanoTS + RTTimerGetSystemGranularity() / 2;
+#endif
+            }
+
+            /* block. */
+            uint64_t cNanoSeconds = pThis->u64NextTS - u64NanoTS;
+#ifdef IN_RING3 /* In ring-3 we'll catch up lost ticks immediately. */
+            if (cNanoSeconds > 10)
+#endif
+            {
+                int rc = RTSemEventWait(pThis->hEvent, cNanoSeconds < 1000000 ? 1 : cNanoSeconds / 1000000);
+                if (RT_FAILURE(rc) && rc != VERR_INTERRUPTED && rc != VERR_TIMEOUT)
+                {
+                    AssertRC(rc);
+                    RTThreadSleep(1000); /* Don't cause trouble! */
+                }
+            }
+        }
+    }
+
+    /*
+     * Release the timer resources.
+     */
+    ASMAtomicWriteU32(&pThis->u32Magic, ~RTTIMERLR_MAGIC); /* make the handle invalid. */
+    int rc = RTSemEventDestroy(pThis->hEvent); AssertRC(rc);
+    pThis->hEvent = NIL_RTSEMEVENT;
+    pThis->hThread = NIL_RTTHREAD;
+    RTMemFree(pThis);
+
+    return VINF_SUCCESS;
+}
+
Index: /trunk/src/VBox/Runtime/include/internal/magics.h
===================================================================
--- /trunk/src/VBox/Runtime/include/internal/magics.h	(revision 10943)
+++ /trunk/src/VBox/Runtime/include/internal/magics.h	(revision 10944)
@@ -79,4 +79,6 @@
 /** Magic number for timer handles. (Jared Mason Diamond) */
 #define RTTIMER_MAGIC               0x19370910
+/** Magic number for timer low resolution handles. (Saki Hiwatari) */
+#define RTTIMERLR_MAGIC             0x19610715
 
 /** @} */
Index: /trunk/src/VBox/Runtime/testcase/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Runtime/testcase/Makefile.kmk	(revision 10943)
+++ /trunk/src/VBox/Runtime/testcase/Makefile.kmk	(revision 10944)
@@ -87,4 +87,5 @@
 	tstTime-4 \
 	tstTimer \
+	tstTimerLR \
 	tstTimeSpec \
 	tstTSC \
@@ -297,4 +298,6 @@
 tstTimer_SOURCES = tstTimer.cpp
 
+tstTimerLR_SOURCES = tstTimerLR.cpp
+
 tstTimeSpec_SOURCES = tstTimeSpec.cpp
 
Index: /trunk/src/VBox/Runtime/testcase/tstTimerLR.cpp
===================================================================
--- /trunk/src/VBox/Runtime/testcase/tstTimerLR.cpp	(revision 10944)
+++ /trunk/src/VBox/Runtime/testcase/tstTimerLR.cpp	(revision 10944)
@@ -0,0 +1,229 @@
+/* $Id$ */
+/** @file
+ * IPRT Testcase - Low Resolution Timers.
+ */
+
+/*
+ * Copyright (C) 2006-2008 Sun Microsystems, Inc.
+ *
+ * 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.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <iprt/timer.h>
+#include <iprt/time.h>
+#include <iprt/thread.h>
+#include <iprt/runtime.h>
+#include <iprt/stream.h>
+#include <iprt/err.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)
+{
+    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 = RTR3Init();
+    if (RT_FAILURE(rc))
+    {
+        RTPrintf("tstTimer: RTR3Init() -> %d\n", rc);
+        return 1;
+    }
+
+    /*
+     * 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 < 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.
+         */
+        uint64_t 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();
+        uint64_t 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 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;
+}
+
+
+
