Index: trunk/src/VBox/VMM/TM.cpp
===================================================================
--- trunk/src/VBox/VMM/TM.cpp	(revision 20730)
+++ trunk/src/VBox/VMM/TM.cpp	(revision 20733)
@@ -578,4 +578,7 @@
     STAM_REG(pVM, &pVM->tm.s.StatTimerSetRZ,                          STAMTYPE_PROFILE, "/TM/TimerSetRZ",                  STAMUNIT_TICKS_PER_CALL, "Profiling TMTimerSet calls made in ring-0 / RC.");
 
+    STAM_REG(pVM, &pVM->tm.s.StatTimerSetRelativeR3,                  STAMTYPE_PROFILE, "/TM/TimerSetRelativeR3",          STAMUNIT_TICKS_PER_CALL, "Profiling TMTimerSetRelative calls made in ring-3.");
+    STAM_REG(pVM, &pVM->tm.s.StatTimerSetRelativeRZ,                  STAMTYPE_PROFILE, "/TM/TimerSetRelativeRZ",          STAMUNIT_TICKS_PER_CALL, "Profiling TMTimerSetReltaive calls made in ring-0 / RC.");
+
     STAM_REG(pVM, &pVM->tm.s.StatTimerStopR3,                         STAMTYPE_PROFILE, "/TM/TimerStopR3",                 STAMUNIT_TICKS_PER_CALL, "Profiling TMTimerStop calls made in ring-3.");
     STAM_REG(pVM, &pVM->tm.s.StatTimerStopRZ,                         STAMTYPE_PROFILE, "/TM/TimerStopRZ",                 STAMUNIT_TICKS_PER_CALL, "Profiling TMTimerStop calls made in ring-0 / RC.");
@@ -1498,5 +1501,5 @@
     {
         Log3(("TMR3TimerDestroy: tmTimerQueueSchedule\n"));
-        STAM_PROFILE_START(&pVM->tm.s.CTXALLSUFF(StatScheduleOne), a);
+        STAM_PROFILE_START(&pVM->tm.s.CTX_SUFF_Z(StatScheduleOne), a);
         Assert(pQueue->offSchedule);
         tmTimerQueueSchedule(pVM, pQueue);
Index: trunk/src/VBox/VMM/TMInternal.h
===================================================================
--- trunk/src/VBox/VMM/TMInternal.h	(revision 20730)
+++ trunk/src/VBox/VMM/TMInternal.h	(revision 20733)
@@ -485,4 +485,9 @@
     STAMPROFILE                 StatTimerSetR3;
     /** @} */
+    /** TMTimerSetRelative
+     * @{ */
+    STAMPROFILE                 StatTimerSetRelativeRZ;
+    STAMPROFILE                 StatTimerSetRelativeR3;
+    /** @} */
     /** TMTimerStop
      * @{ */
Index: trunk/src/VBox/VMM/VMMAll/TMAll.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMAll/TMAll.cpp	(revision 20730)
+++ trunk/src/VBox/VMM/VMMAll/TMAll.cpp	(revision 20733)
@@ -751,5 +751,5 @@
 VMMDECL(int) TMTimerSet(PTMTIMER pTimer, uint64_t u64Expire)
 {
-    STAM_PROFILE_START(&pTimer->CTX_SUFF(pVM)->tm.s.CTXALLSUFF(StatTimerSet), a);
+    STAM_PROFILE_START(&pTimer->CTX_SUFF(pVM)->tm.s.CTX_SUFF_Z(StatTimerSet), a);
     TMTIMER_ASSERT_CRITSECT(pTimer);
 
@@ -852,4 +852,200 @@
 
 /**
+ * Return the current time for the specified clock, setting pu64Now if not NULL.
+ *
+ * @returns Current time.
+ * @param   pVM             The VM handle.
+ * @param   enmClock        The clock to query.
+ * @param   pu64Now         Optional pointer where to store the return time
+ */
+DECL_FORCE_INLINE(uint64_t) tmTimerSetRelativeNowWorker(PVM pVM, TMCLOCK enmClock, uint64_t *pu64Now)
+{
+    uint64_t u64Now;
+    switch (enmClock)
+    {
+        case TMCLOCK_VIRTUAL_SYNC:
+            u64Now = TMVirtualSyncGet(pVM);
+            break;
+        case TMCLOCK_VIRTUAL:
+            u64Now = TMVirtualGet(pVM);
+            break;
+        case TMCLOCK_REAL:
+            u64Now = TMRealGet(pVM);
+            break;
+        default:
+            AssertFatalMsgFailed(("%d\n", enmClock));
+    }
+
+    if (pu64Now)
+        *pu64Now = u64Now;
+    return u64Now;
+}
+
+
+/**
+ * Arm a timer with a expire time relative to the current time.
+ *
+ * @returns VBox status.
+ * @param   pTimer          Timer handle as returned by one of the create functions.
+ * @param   cTicksToNext    Clock ticks until the next time expiration.
+ * @param   pu64Now         Where to return the current time stamp used.
+ *                          Optional.
+ */
+VMMDECL(int) TMTimerSetRelative(PTMTIMER pTimer, uint64_t cTicksToNext, uint64_t *pu64Now)
+{
+    STAM_PROFILE_START(&pTimer->CTX_SUFF(pVM)->tm.s.CTX_SUFF_Z(StatTimerSetRelative), a);
+    TMTIMER_ASSERT_CRITSECT(pTimer);
+    PVM         pVM      = pTimer->CTX_SUFF(pVM);
+    TMCLOCK     enmClock = pTimer->enmClock;
+    bool        fOwnLock = false;
+    int         rc;
+
+    /** @todo find the most frequently used paths and make them skip tmSchedule and tmTimerTryWithLink. */
+    for (int cRetries = 1000; ; cRetries--)
+    {
+        /*
+         * Try to take the appropriate lock to increase the likelyhood
+         * that we don't race timer queue running and to some extend
+         * clock queries.
+         */
+        if (!fOwnLock)
+        {
+            if (enmClock == TMCLOCK_VIRTUAL_SYNC)
+                fOwnLock = RT_SUCCESS(tmVirtualSyncTryLock(pVM));
+            else
+                fOwnLock = RT_SUCCESS(tmTryLock(pVM));
+        }
+
+        /*
+         * Change to any of the SET_EXPIRE states if valid and then to SCHEDULE or RESCHEDULE.
+         */
+        TMTIMERSTATE    enmState = pTimer->enmState;
+        switch (enmState)
+        {
+            case TMTIMERSTATE_EXPIRED_DELIVER:
+            case TMTIMERSTATE_STOPPED:
+                if (tmTimerTryWithLink(pTimer, TMTIMERSTATE_PENDING_SCHEDULE_SET_EXPIRE, enmState))
+                {
+                    Assert(!pTimer->offPrev);
+                    Assert(!pTimer->offNext);
+                    pTimer->u64Expire = cTicksToNext + tmTimerSetRelativeNowWorker(pVM, enmClock, pu64Now);
+                    Log2(("TMTimerSetRelative: %p:{.enmState=%s, .pszDesc='%s', .u64Expire=%'RU64} cRetries=%d [EXP/STOP]\n",
+                          pTimer, tmTimerState(enmState), R3STRING(pTimer->pszDesc), pTimer->u64Expire, cRetries));
+                    TM_SET_STATE(pTimer, TMTIMERSTATE_PENDING_SCHEDULE);
+                    tmSchedule(pTimer);
+                    rc = VINF_SUCCESS;
+                    break;
+                }
+                rc = VERR_TRY_AGAIN;
+                break;
+
+            case TMTIMERSTATE_PENDING_SCHEDULE:
+            case TMTIMERSTATE_PENDING_STOP_SCHEDULE:
+                if (tmTimerTry(pTimer, TMTIMERSTATE_PENDING_SCHEDULE_SET_EXPIRE, enmState))
+                {
+                    pTimer->u64Expire = cTicksToNext + tmTimerSetRelativeNowWorker(pVM, enmClock, pu64Now);
+                    Log2(("TMTimerSetRelative: %p:{.enmState=%s, .pszDesc='%s', .u64Expire=%'RU64} cRetries=%d [PEND_SCHED]\n",
+                          pTimer, tmTimerState(enmState), R3STRING(pTimer->pszDesc), pTimer->u64Expire, cRetries));
+                    TM_SET_STATE(pTimer, TMTIMERSTATE_PENDING_SCHEDULE);
+                    tmSchedule(pTimer);
+                    rc = VINF_SUCCESS;
+                    break;
+                }
+                rc = VERR_TRY_AGAIN;
+                break;
+
+
+            case TMTIMERSTATE_ACTIVE:
+                if (tmTimerTryWithLink(pTimer, TMTIMERSTATE_PENDING_RESCHEDULE_SET_EXPIRE, enmState))
+                {
+                    pTimer->u64Expire = cTicksToNext + tmTimerSetRelativeNowWorker(pVM, enmClock, pu64Now);
+                    Log2(("TMTimerSetRelative: %p:{.enmState=%s, .pszDesc='%s', .u64Expire=%'RU64} cRetries=%d [ACTIVE]\n",
+                          pTimer, tmTimerState(enmState), R3STRING(pTimer->pszDesc), pTimer->u64Expire, cRetries));
+                    TM_SET_STATE(pTimer, TMTIMERSTATE_PENDING_RESCHEDULE);
+                    tmSchedule(pTimer);
+                    rc = VINF_SUCCESS;
+                    break;
+                }
+                rc = VERR_TRY_AGAIN;
+                break;
+
+            case TMTIMERSTATE_PENDING_RESCHEDULE:
+            case TMTIMERSTATE_PENDING_STOP:
+                if (tmTimerTry(pTimer, TMTIMERSTATE_PENDING_RESCHEDULE_SET_EXPIRE, enmState))
+                {
+                    pTimer->u64Expire = cTicksToNext + tmTimerSetRelativeNowWorker(pVM, enmClock, pu64Now);
+                    Log2(("TMTimerSetRelative: %p:{.enmState=%s, .pszDesc='%s', .u64Expire=%'RU64} cRetries=%d [PEND_RESCH/STOP]\n",
+                          pTimer, tmTimerState(enmState), R3STRING(pTimer->pszDesc), pTimer->u64Expire, cRetries));
+                    TM_SET_STATE(pTimer, TMTIMERSTATE_PENDING_RESCHEDULE);
+                    tmSchedule(pTimer);
+                    rc = VINF_SUCCESS;
+                    break;
+                }
+                rc = VERR_TRY_AGAIN;
+                break;
+
+
+            case TMTIMERSTATE_EXPIRED_GET_UNLINK:
+            case TMTIMERSTATE_PENDING_SCHEDULE_SET_EXPIRE:
+            case TMTIMERSTATE_PENDING_RESCHEDULE_SET_EXPIRE:
+#ifdef IN_RING3
+                if (!RTThreadYield())
+                    RTThreadSleep(1);
+#else
+/** @todo call host context and yield after a couple of iterations */
+#endif
+                rc = VERR_TRY_AGAIN;
+                break;
+
+            /*
+             * Invalid states.
+             */
+            case TMTIMERSTATE_DESTROY:
+            case TMTIMERSTATE_FREE:
+                AssertMsgFailed(("Invalid timer state %d (%s)\n", enmState, R3STRING(pTimer->pszDesc)));
+                rc = VERR_TM_INVALID_STATE;
+                break;
+
+            default:
+                AssertMsgFailed(("Unknown timer state %d (%s)\n", enmState, R3STRING(pTimer->pszDesc)));
+                rc = VERR_TM_UNKNOWN_STATE;
+                break;
+        }
+
+        /* switch + loop is tedious to break out of. */
+        if (rc == VINF_SUCCESS)
+            break;
+
+        if (rc != VERR_TRY_AGAIN)
+        {
+            tmTimerSetRelativeNowWorker(pVM, enmClock, pu64Now);
+            break;
+        }
+        if (cRetries > 0)
+        {
+            AssertMsgFailed(("Failed waiting for stable state. state=%d (%s)\n", pTimer->enmState, R3STRING(pTimer->pszDesc)));
+            rc = VERR_INTERNAL_ERROR;
+            tmTimerSetRelativeNowWorker(pVM, enmClock, pu64Now);
+            break;
+        }
+    } /* for (;;) */
+
+    /*
+     * Clean up and return.
+     */
+    if (fOwnLock)
+    {
+        if (enmClock == TMCLOCK_VIRTUAL_SYNC)
+            tmVirtualSyncUnlock(pVM);
+        else
+            tmUnlock(pVM);
+    }
+
+    STAM_PROFILE_STOP(&pTimer->CTX_SUFF(pVM)->tm.s.CTX_SUFF_Z(StatTimerSetRelative), a);
+    return rc;
+}
+
+
+/**
  * Arm a timer with a (new) expire time relative to current time.
  *
@@ -866,12 +1062,14 @@
     {
         case TMCLOCK_VIRTUAL:
-            return TMTimerSet(pTimer, cMilliesToNext * (uint64_t)TMCLOCK_FREQ_VIRTUAL / 1000 + TMVirtualGet(pVM));
+            AssertCompile(TMCLOCK_FREQ_VIRTUAL == 1000000000);
+            return TMTimerSetRelative(pTimer, cMilliesToNext * UINT64_C(1000000), NULL);
+
         case TMCLOCK_VIRTUAL_SYNC:
-            return TMTimerSet(pTimer, cMilliesToNext * (uint64_t)TMCLOCK_FREQ_VIRTUAL / 1000 + TMVirtualSyncGet(pVM));
+            AssertCompile(TMCLOCK_FREQ_VIRTUAL == 1000000000);
+            return TMTimerSetRelative(pTimer, cMilliesToNext * UINT64_C(1000000), NULL);
+
         case TMCLOCK_REAL:
             AssertCompile(TMCLOCK_FREQ_REAL == 1000);
-            return TMTimerSet(pTimer, cMilliesToNext + TMRealGet(pVM));
-        case TMCLOCK_TSC:
-            return TMTimerSet(pTimer, cMilliesToNext * pVM->tm.s.cTSCTicksPerSecond / 1000 + TMCpuTickGet(pVCpu));
+            return TMTimerSetRelative(pTimer, cMilliesToNext, NULL);
 
         default:
@@ -898,16 +1096,13 @@
         case TMCLOCK_VIRTUAL:
             AssertCompile(TMCLOCK_FREQ_VIRTUAL == 1000000000);
-            return TMTimerSet(pTimer, cMicrosToNext * 1000 + TMVirtualGet(pVM));
+            return TMTimerSetRelative(pTimer, cMicrosToNext * 1000, NULL);
 
         case TMCLOCK_VIRTUAL_SYNC:
             AssertCompile(TMCLOCK_FREQ_VIRTUAL == 1000000000);
-            return TMTimerSet(pTimer, cMicrosToNext * 1000 + TMVirtualSyncGet(pVM));
+            return TMTimerSetRelative(pTimer, cMicrosToNext * 1000, NULL);
 
         case TMCLOCK_REAL:
             AssertCompile(TMCLOCK_FREQ_REAL == 1000);
-            return TMTimerSet(pTimer, cMicrosToNext / 1000 + TMRealGet(pVM));
-
-        case TMCLOCK_TSC:
-            return TMTimerSet(pTimer, TMTimerFromMicro(pTimer, cMicrosToNext) + TMCpuTickGet(pVCpu));
+            return TMTimerSetRelative(pTimer, cMicrosToNext / 1000, NULL);
 
         default:
@@ -934,16 +1129,13 @@
         case TMCLOCK_VIRTUAL:
             AssertCompile(TMCLOCK_FREQ_VIRTUAL == 1000000000);
-            return TMTimerSet(pTimer, cNanosToNext + TMVirtualGet(pVM));
+            return TMTimerSetRelative(pTimer, cNanosToNext, NULL);
 
         case TMCLOCK_VIRTUAL_SYNC:
             AssertCompile(TMCLOCK_FREQ_VIRTUAL == 1000000000);
-            return TMTimerSet(pTimer, cNanosToNext + TMVirtualSyncGet(pVM));
+            return TMTimerSetRelative(pTimer, cNanosToNext, NULL);
 
         case TMCLOCK_REAL:
             AssertCompile(TMCLOCK_FREQ_REAL == 1000);
-            return TMTimerSet(pTimer, cNanosToNext / 1000000 + TMRealGet(pVM));
-
-        case TMCLOCK_TSC:
-            return TMTimerSet(pTimer, TMTimerFromNano(pTimer, cNanosToNext) + TMCpuTickGet(pVCpu));
+            return TMTimerSetRelative(pTimer, cNanosToNext / 1000000, NULL);
 
         default:
@@ -963,5 +1155,5 @@
 VMMDECL(int) TMTimerStop(PTMTIMER pTimer)
 {
-    STAM_PROFILE_START(&pTimer->CTX_SUFF(pVM)->tm.s.CTXALLSUFF(StatTimerStop), a);
+    STAM_PROFILE_START(&pTimer->CTX_SUFF(pVM)->tm.s.CTX_SUFF_Z(StatTimerStop), a);
     TMTIMER_ASSERT_CRITSECT(pTimer);
 
@@ -1067,10 +1259,4 @@
             u64 = TMRealGet(pVM);
             break;
-        case TMCLOCK_TSC:
-        {
-            PVMCPU pVCpu = &pVM->aCpus[0];  /* just take the first VCPU */
-            u64 = TMCpuTickGet(pVCpu);
-            break;
-        }
         default:
             AssertMsgFailed(("Invalid enmClock=%d\n", pTimer->enmClock));
@@ -1099,7 +1285,4 @@
         case TMCLOCK_REAL:
             return TMCLOCK_FREQ_REAL;
-
-        case TMCLOCK_TSC:
-            return TMCpuTicksPerSecond(pTimer->CTX_SUFF(pVM));
 
         default:
@@ -1168,8 +1351,4 @@
             return u64Ticks * 1000000;
 
-        case TMCLOCK_TSC:
-            AssertReleaseMsgFailed(("TMCLOCK_TSC conversions are not implemented\n"));
-            return 0;
-
         default:
             AssertMsgFailed(("Invalid enmClock=%d\n", pTimer->enmClock));
@@ -1201,8 +1380,4 @@
             return u64Ticks * 1000;
 
-        case TMCLOCK_TSC:
-            AssertReleaseMsgFailed(("TMCLOCK_TSC conversions are not implemented\n"));
-            return 0;
-
         default:
             AssertMsgFailed(("Invalid enmClock=%d\n", pTimer->enmClock));
@@ -1234,8 +1409,4 @@
             return u64Ticks;
 
-        case TMCLOCK_TSC:
-            AssertReleaseMsgFailed(("TMCLOCK_TSC conversions are not implemented\n"));
-            return 0;
-
         default:
             AssertMsgFailed(("Invalid enmClock=%d\n", pTimer->enmClock));
@@ -1266,8 +1437,4 @@
             return u64NanoTS / 1000000;
 
-        case TMCLOCK_TSC:
-            AssertReleaseMsgFailed(("TMCLOCK_TSC conversions are not implemented\n"));
-            return 0;
-
         default:
             AssertMsgFailed(("Invalid enmClock=%d\n", pTimer->enmClock));
@@ -1298,8 +1465,4 @@
             return u64MicroTS / 1000;
 
-        case TMCLOCK_TSC:
-            AssertReleaseMsgFailed(("TMCLOCK_TSC conversions are not implemented\n"));
-            return 0;
-
         default:
             AssertMsgFailed(("Invalid enmClock=%d\n", pTimer->enmClock));
@@ -1329,8 +1492,4 @@
             AssertCompile(TMCLOCK_FREQ_REAL == 1000);
             return u64MilliTS;
-
-        case TMCLOCK_TSC:
-            AssertReleaseMsgFailed(("TMCLOCK_TSC conversions are not implemented\n"));
-            return 0;
 
         default:
