TMAll.cpp revision e7ddda521ef8ec576db936e3f77c8fdc3aad09bf
85c594c1140f082dd862abde9dc7825137a3d51avboxsync * TM - Timeout Manager, all contexts.
85c594c1140f082dd862abde9dc7825137a3d51avboxsync * Copyright (C) 2006-2007 Sun Microsystems, Inc.
bd8e360cd1db83dcb2694ea9122ce3bc5bae678avboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
bd8e360cd1db83dcb2694ea9122ce3bc5bae678avboxsync * available from http://www.virtualbox.org. This file is free software;
bd8e360cd1db83dcb2694ea9122ce3bc5bae678avboxsync * you can redistribute it and/or modify it under the terms of the GNU
bd8e360cd1db83dcb2694ea9122ce3bc5bae678avboxsync * General Public License (GPL) as published by the Free Software
bd8e360cd1db83dcb2694ea9122ce3bc5bae678avboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
bd8e360cd1db83dcb2694ea9122ce3bc5bae678avboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
bd8e360cd1db83dcb2694ea9122ce3bc5bae678avboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
85c594c1140f082dd862abde9dc7825137a3d51avboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
85c594c1140f082dd862abde9dc7825137a3d51avboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
85c594c1140f082dd862abde9dc7825137a3d51avboxsync * additional information or have any questions.
d00232b1c9c58409fd4b276f12e0d340e7bcc3c5vboxsync/*******************************************************************************
85c594c1140f082dd862abde9dc7825137a3d51avboxsync* Header Files *
85c594c1140f082dd862abde9dc7825137a3d51avboxsync*******************************************************************************/
d00232b1c9c58409fd4b276f12e0d340e7bcc3c5vboxsync * Try take the EMT/TM lock, wait in ring-3 return VERR_SEM_BUSY in R0/RC.
d00232b1c9c58409fd4b276f12e0d340e7bcc3c5vboxsync * @retval VINF_SUCCESS on success (always in ring-3).
ddf5411fb7193f28ec0f1e1354c5d8dcc424526avboxsync * @retval VERR_SEM_BUSY in RC and R0 if the semaphore is busy.
ddf5411fb7193f28ec0f1e1354c5d8dcc424526avboxsync * @param pVM The VM handle.
e2d696a2f8e2b120c87f63fc2ca2470e138c4dbavboxsync int rc = PDMCritSectEnter(&pVM->tm.s.EmtLock, VERR_SEM_BUSY);
85c594c1140f082dd862abde9dc7825137a3d51avboxsync * Try take the EMT/TM lock, no waiting.
85c594c1140f082dd862abde9dc7825137a3d51avboxsync * @retval VINF_SUCCESS on success.
85c594c1140f082dd862abde9dc7825137a3d51avboxsync * @retval VERR_SEM_BUSY if busy.
85c594c1140f082dd862abde9dc7825137a3d51avboxsync * @param pVM The VM handle.
85c594c1140f082dd862abde9dc7825137a3d51avboxsync * Release the EMT/TM lock.
85c594c1140f082dd862abde9dc7825137a3d51avboxsync * @param pVM The VM handle.
85c594c1140f082dd862abde9dc7825137a3d51avboxsync * Try take the VirtualSync lock, wait in ring-3 return VERR_SEM_BUSY in R0/RC.
85c594c1140f082dd862abde9dc7825137a3d51avboxsync * @retval VINF_SUCCESS on success (always in ring-3).
85c594c1140f082dd862abde9dc7825137a3d51avboxsync * @retval VERR_SEM_BUSY in RC and R0 if the semaphore is busy.
85c594c1140f082dd862abde9dc7825137a3d51avboxsync * @param pVM The VM handle.
85c594c1140f082dd862abde9dc7825137a3d51avboxsync int rc = PDMCritSectEnter(&pVM->tm.s.VirtualSyncLock, VERR_SEM_BUSY);
85c594c1140f082dd862abde9dc7825137a3d51avboxsync * Try take the VirtualSync lock, no waiting.
85c594c1140f082dd862abde9dc7825137a3d51avboxsync * @retval VINF_SUCCESS on success.
85c594c1140f082dd862abde9dc7825137a3d51avboxsync * @retval VERR_SEM_BUSY if busy.
85c594c1140f082dd862abde9dc7825137a3d51avboxsync * @param pVM The VM handle.
d00232b1c9c58409fd4b276f12e0d340e7bcc3c5vboxsync int rc = PDMCritSectTryEnter(&pVM->tm.s.VirtualSyncLock);
d00232b1c9c58409fd4b276f12e0d340e7bcc3c5vboxsync * Release the VirtualSync lock.
85c594c1140f082dd862abde9dc7825137a3d51avboxsync * @param pVM The VM handle.
85c594c1140f082dd862abde9dc7825137a3d51avboxsync#endif /* ! macros */
#ifdef IN_RING3
#ifdef VBOX_STRICT
bool fRc;
return fRc;
if (offHead)
DECLINLINE(bool) tmTimerTryWithLink(PTMTIMER pTimer, TMTIMERSTATE enmStateNew, TMTIMERSTATE enmStateOld)
#ifdef VBOX_HIGH_RES_TIMERS_HACK
DECLINLINE(uint64_t) tmTimerPollReturnMiss(PVM pVM, uint64_t u64Now, uint64_t u64Delta, uint64_t *pu64Delta)
return u64GipTime;
DECL_FORCE_INLINE(uint64_t) tmTimerPollReturnOtherCpu(PVM pVM, uint64_t u64Now, uint64_t *pu64Delta)
DECL_FORCE_INLINE(uint64_t) tmTimerPollReturnHit(PVM pVM, PVMCPU pVCpu, PVMCPU pVCpuDst, uint64_t u64Now,
*pu64Delta = 0;
return tmTimerPollReturnHit(pVM, pVCpu, pVCpuDst, u64Now, pu64Delta, &pVM->tm.s.StatPollAlreadySet);
const uint64_t u64Expire1 = ASMAtomicReadU64(&pVM->tm.s.CTX_SUFF(paTimerQueues)[TMCLOCK_VIRTUAL].u64Expire);
if (i64Delta1 <= 0)
#ifdef IN_RING3
uint64_t u64Expire2 = ASMAtomicUoReadU64(&pVM->tm.s.CTX_SUFF(paTimerQueues)[TMCLOCK_VIRTUAL_SYNC].u64Expire);
&& u64Expire2 == ASMAtomicUoReadU64(&pVM->tm.s.CTX_SUFF(paTimerQueues)[TMCLOCK_VIRTUAL_SYNC].u64Expire)))
if (i64Delta2 > 0)
#ifdef IN_RING3
return tmTimerPollReturnHit(pVM, pVCpu, pVCpuDst, u64Now, pu64Delta, &pVM->tm.s.StatPollVirtualSync);
return tmTimerPollReturnHit(pVM, pVCpu, pVCpuDst, u64Now, pu64Delta, &pVM->tm.s.StatPollVirtualSync);
bool fCatchUp;
for (;; cOuterTries--)
if (fCatchUp)
&& u64Expire2 == ASMAtomicReadU64(&pVM->tm.s.CTX_SUFF(paTimerQueues)[TMCLOCK_VIRTUAL_SYNC].u64Expire)
|| cOuterTries <= 0)
&& u64Expire2 == ASMAtomicReadU64(&pVM->tm.s.CTX_SUFF(paTimerQueues)[TMCLOCK_VIRTUAL_SYNC].u64Expire)
return tmTimerPollReturnHit(pVM, pVCpu, pVCpuDst, u64Now, pu64Delta, &pVM->tm.s.StatPollAlreadySet);
return tmTimerPollReturnHit(pVM, pVCpu, pVCpuDst, u64Now, pu64Delta, &pVM->tm.s.StatPollVirtualSync);
if (cOuterTries <= 0)
if (cOuterTries <= 0)
if (i64Delta2 <= 0)
#ifdef IN_RING3
return tmTimerPollReturnHit(pVM, pVCpu, pVCpuDst, u64Now, pu64Delta, &pVM->tm.s.StatPollVirtualSync);
if (fCatchUp)
return off == 0;
/** @todo find the most frequently used paths and make them skip tmSchedule and tmTimerTryWithLink. */
switch (enmState)
case TMTIMERSTATE_STOPPED:
("%'RU64 < %'RU64 %s\n", u64Expire, pTimer->CTX_SUFF(pVM)->tm.s.u64VirtualSync, R3STRING(pTimer->pszDesc)));
return VINF_SUCCESS;
return VINF_SUCCESS;
case TMTIMERSTATE_ACTIVE:
return VINF_SUCCESS;
return VINF_SUCCESS;
#ifdef IN_RING3
if (!RTThreadYield())
case TMTIMERSTATE_DESTROY:
case TMTIMERSTATE_FREE:
return VERR_TM_INVALID_STATE;
return VERR_TM_UNKNOWN_STATE;
} while (cRetries-- > 0);
AssertMsgFailed(("Failed waiting for stable state. state=%d (%s)\n", pTimer->enmState, R3STRING(pTimer->pszDesc)));
return VERR_INTERNAL_ERROR;
case TMCLOCK_VIRTUAL:
return TMTimerSet(pTimer, cMilliesToNext * (uint64_t)TMCLOCK_FREQ_VIRTUAL / 1000 + TMVirtualGet(pVM));
case TMCLOCK_VIRTUAL_SYNC:
return TMTimerSet(pTimer, cMilliesToNext * (uint64_t)TMCLOCK_FREQ_VIRTUAL / 1000 + TMVirtualSyncGet(pVM));
case TMCLOCK_REAL:
case TMCLOCK_TSC:
return TMTimerSet(pTimer, cMilliesToNext * pVM->tm.s.cTSCTicksPerSecond / 1000 + TMCpuTickGet(pVCpu));
return VERR_INTERNAL_ERROR;
case TMCLOCK_VIRTUAL:
case TMCLOCK_VIRTUAL_SYNC:
case TMCLOCK_REAL:
case TMCLOCK_TSC:
return VERR_INTERNAL_ERROR;
case TMCLOCK_VIRTUAL:
case TMCLOCK_VIRTUAL_SYNC:
case TMCLOCK_REAL:
case TMCLOCK_TSC:
return VERR_INTERNAL_ERROR;
switch (enmState)
return VERR_INVALID_PARAMETER;
case TMTIMERSTATE_STOPPED:
return VINF_SUCCESS;
return VINF_SUCCESS;
return VINF_SUCCESS;
case TMTIMERSTATE_ACTIVE:
return VINF_SUCCESS;
#ifdef IN_RING3
if (!RTThreadYield())
case TMTIMERSTATE_DESTROY:
case TMTIMERSTATE_FREE:
return VERR_TM_INVALID_STATE;
return VERR_TM_UNKNOWN_STATE;
} while (cRetries-- > 0);
AssertMsgFailed(("Failed waiting for stable state. state=%d (%s)\n", pTimer->enmState, R3STRING(pTimer->pszDesc)));
return VERR_INTERNAL_ERROR;
case TMCLOCK_VIRTUAL:
case TMCLOCK_VIRTUAL_SYNC:
case TMCLOCK_REAL:
case TMCLOCK_TSC:
return ~(uint64_t)0;
return u64;
case TMCLOCK_VIRTUAL:
case TMCLOCK_VIRTUAL_SYNC:
return TMCLOCK_FREQ_VIRTUAL;
case TMCLOCK_REAL:
return TMCLOCK_FREQ_REAL;
case TMCLOCK_TSC:
case TMCLOCK_VIRTUAL:
case TMCLOCK_VIRTUAL_SYNC:
return u64Ticks;
case TMCLOCK_REAL:
case TMCLOCK_TSC:
case TMCLOCK_VIRTUAL:
case TMCLOCK_VIRTUAL_SYNC:
case TMCLOCK_REAL:
case TMCLOCK_TSC:
case TMCLOCK_VIRTUAL:
case TMCLOCK_VIRTUAL_SYNC:
case TMCLOCK_REAL:
return u64Ticks;
case TMCLOCK_TSC:
case TMCLOCK_VIRTUAL:
case TMCLOCK_VIRTUAL_SYNC:
return u64NanoTS;
case TMCLOCK_REAL:
case TMCLOCK_TSC:
case TMCLOCK_VIRTUAL:
case TMCLOCK_VIRTUAL_SYNC:
case TMCLOCK_REAL:
case TMCLOCK_TSC:
case TMCLOCK_VIRTUAL:
case TMCLOCK_VIRTUAL_SYNC:
case TMCLOCK_REAL:
return u64MilliTS;
case TMCLOCK_TSC:
switch (enmState)
case TMTIMERSTATE_STOPPED:
return ~(uint64_t)0;
case TMTIMERSTATE_ACTIVE:
#ifdef IN_RING3
if (!RTThreadYield())
case TMTIMERSTATE_DESTROY:
case TMTIMERSTATE_FREE:
return ~(uint64_t)0;
return ~(uint64_t)0;
} while (cRetries-- > 0);
AssertMsgFailed(("Failed waiting for stable state. state=%d (%s)\n", pTimer->enmState, R3STRING(pTimer->pszDesc)));
return ~(uint64_t)0;
switch (enmState)
case TMTIMERSTATE_STOPPED:
case TMTIMERSTATE_ACTIVE:
case TMTIMERSTATE_DESTROY:
case TMTIMERSTATE_FREE:
AssertMsgFailed(("Invalid timer state %s (%s)\n", tmTimerState(enmState), R3STRING(pTimer->pszDesc)));
switch (enmState)
switch (enmState)
if (RT_UNLIKELY(!tmTimerTry(pTimer, TMTIMERSTATE_PENDING_SCHEDULE, TMTIMERSTATE_PENDING_RESCHEDULE)))
if (pPrev)
if (pNext)
if (pCur)
if (pPrev)
if (RT_UNLIKELY(!tmTimerTry(pTimer, TMTIMERSTATE_PENDING_STOP_SCHEDULE, TMTIMERSTATE_PENDING_STOP)))
if (pPrev)
if (pNext)
case TMTIMERSTATE_DESTROY:
case TMTIMERSTATE_FREE:
case TMTIMERSTATE_STOPPED:
case TMTIMERSTATE_ACTIVE:
} while (cRetries-- > 0);
Log2(("tmTimerQueueSchedule: pQueue=%p:{.enmClock=%d, offNext=%RI32, .u64Expired=%'RU64}\n", pQueue, pQueue->enmClock, offNext, pQueue->u64Expire));
if (!offNext)
while (pNext)
pTimer, tmTimerState(pTimer->enmState), pTimer->enmClock, pTimer->enmType, R3STRING(pTimer->pszDesc)));
#ifdef VBOX_STRICT
for (int i = 0; i < TMCLOCK_MAX; i++)
AssertMsg(TMTIMER_GET_PREV(pCur) == pPrev, ("%s: %p != %p\n", pszWhere, TMTIMER_GET_PREV(pCur), pPrev));
switch (enmState)
case TMTIMERSTATE_ACTIVE:
AssertMsgFailed(("%s: Invalid state enmState=%d %s\n", pszWhere, enmState, tmTimerState(enmState)));
# ifdef IN_RING3
switch (enmState)
case TMTIMERSTATE_ACTIVE:
case TMTIMERSTATE_STOPPED:
case TMTIMERSTATE_DESTROY: