TMAll.cpp revision 011b3545a51dffe5c5f1cd561b634b20d375c953
/* $Id$ */
/** @file
* TM - Timeout Manager, all contexts.
*/
/*
* Copyright (C) 2006-2007 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;
* 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.
*
* 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 *
*******************************************************************************/
#define LOG_GROUP LOG_GROUP_TM
#ifdef IN_RING3
#endif
#include "TMInternal.h"
#ifdef IN_RING3
#endif
#ifndef tmLock
/**
*
* @retval VINF_SUCCESS on success (always in ring-3).
* @retval VERR_SEM_BUSY in RC and R0 if the semaphore is busy.
*
* @param pVM The VM handle.
*/
{
return rc;
}
/**
*
* @retval VINF_SUCCESS on success.
* @retval VERR_SEM_BUSY if busy.
*
* @param pVM The VM handle.
*/
{
return rc;
}
/**
*
* @param pVM The VM handle.
*/
{
}
#endif /* ! macros */
/**
* Notification that execution is about to start.
*
* This call must always be paired with a TMNotifyEndOfExecution call.
*
* The function may, depending on the configuration, resume the TSC and future
* clocks that only ticks when we're executing guest code.
*
* @param pVCpu The VMCPU to operate on.
*/
{
}
/**
* Notification that execution is about to start.
*
* This call must always be paired with a TMNotifyStartOfExecution call.
*
* The function may, depending on the configuration, suspend the TSC and future
* clocks that only ticks when we're executing guest code.
*
* @param pVCpu The VMCPU to operate on.
*/
{
}
/**
* Notification that the cpu is entering the halt state
*
* This call must always be paired with a TMNotifyEndOfExecution call.
*
* The function may, depending on the configuration, resume the TSC and future
* clocks that only ticks when we're halted.
*
* @param pVCpu The VMCPU to operate on.
*/
{
}
/**
* Notification that the cpu is leaving the halt state
*
* This call must always be paired with a TMNotifyStartOfHalt call.
*
* The function may, depending on the configuration, suspend the TSC and future
* clocks that only ticks when we're halted.
*
* @param pVCpu The VMCPU to operate on.
*/
{
}
/**
* Schedule the queue which was changed.
*/
{
{
Log3(("tmSchedule: tmTimerQueueSchedule\n"));
#ifdef VBOX_STRICT
#endif
}
{
#ifdef IN_RING3
#endif
}
}
/**
* Try change the state to enmStateNew from enmStateOld
* and link the timer into the scheduling queue.
*
* @returns Success indicator.
* @param pTimer Timer in question.
* @param enmStateNew The new timer state.
* @param enmStateOld The old timer state.
*/
{
/*
* Attempt state change.
*/
bool fRc;
return fRc;
}
/**
* Links the timer onto the scheduling queue.
*
* @param pQueue The timer queue the timer belongs to.
* @param pTimer The timer.
*/
{
do
{
if (offHead)
else
pTimer->offScheduleNext = 0;
}
/**
* Try change the state to enmStateNew from enmStateOld
* and link the timer into the scheduling queue.
*
* @returns Success indicator.
* @param pTimer Timer in question.
* @param enmStateNew The new timer state.
* @param enmStateOld The old timer state.
*/
DECLINLINE(bool) tmTimerTryWithLink(PTMTIMER pTimer, TMTIMERSTATE enmStateNew, TMTIMERSTATE enmStateOld)
{
{
return true;
}
return false;
}
#ifdef VBOX_HIGH_RES_TIMERS_HACK
/**
* Set FF if we've passed the next virtual event.
*
* This function is called before FFs are checked in the inner execution EM loops.
*
* @returns Virtual timer ticks to the next event.
* @param pVM Pointer to the shared VM structure.
* @thread The emulation thread.
*/
{
/*
* Return straight away if the timer FF is already set.
*/
{
#ifndef IN_RING3
if (RT_SUCCESS(rc))
#endif
return 0;
}
/*
* Get current time and check the expire times of the two relevant queues.
*/
/*
* TMCLOCK_VIRTUAL
*/
if (i64Delta1 <= 0)
{
#ifndef IN_RING3
if (RT_SUCCESS(rc))
#endif
#ifdef IN_RING3
#endif
return 0;
}
/*
* TMCLOCK_VIRTUAL_SYNC
* This isn't quite as stright forward if in a catch-up, not only do
* we have to adjust the 'now' but when have to adjust the delta as well.
*/
else
{
else
{
{
uint64_t u64Sub = ASMMultU64ByU32DivByU32(u64Delta, pVM->tm.s.u32VirtualSyncCatchUpPercentage, 100);
else
}
}
}
if (i64Delta2 <= 0)
{
#ifndef IN_RING3
if (RT_SUCCESS(rc))
#endif
#ifdef IN_RING3
#endif
return 0;
}
i64Delta2 = ASMMultU64ByU32DivByU32(i64Delta2, 100, pVM->tm.s.u32VirtualSyncCatchUpPercentage + 100);
/*
* Return the time left to the next event.
*/
#ifndef IN_RING3
if (RT_SUCCESS(rc))
#endif
}
/**
* Set FF if we've passed the next virtual event.
*
* This function is called before FFs are checked in the inner execution EM loops.
*
* @returns The GIP timestamp of the next event.
* 0 if the next event has already expired.
* @param pVM Pointer to the shared VM structure.
* @param pVM Pointer to the shared VM structure.
* @param pu64Delta Where to store the delta.
* @thread The emulation thread.
*/
{
/*
* Return straight away if the timer FF is already set.
*/
{
#ifndef IN_RING3
if (RT_SUCCESS(rc))
#endif
*pu64Delta = 0;
return 0;
}
/*
* Get current time and check the expire times of the two relevant queues.
*/
/*
* TMCLOCK_VIRTUAL
*/
if (i64Delta1 <= 0)
{
#ifndef IN_RING3
if (RT_SUCCESS(rc))
#endif
#ifdef IN_RING3
#endif
*pu64Delta = 0;
return 0;
}
/*
* TMCLOCK_VIRTUAL_SYNC
* This isn't quite as stright forward if in a catch-up, not only do
* we have to adjust the 'now' but when have to adjust the delta as well.
*/
else
{
else
{
{
uint64_t u64Sub = ASMMultU64ByU32DivByU32(u64Delta, pVM->tm.s.u32VirtualSyncCatchUpPercentage, 100);
else
}
}
}
if (i64Delta2 <= 0)
{
#ifndef IN_RING3
if (RT_SUCCESS(rc))
#endif
#ifdef IN_RING3
#endif
*pu64Delta = 0;
return 0;
}
i64Delta2 = ASMMultU64ByU32DivByU32(i64Delta2, 100, pVM->tm.s.u32VirtualSyncCatchUpPercentage + 100);
/*
* Return the GIP time of the next event.
* This is the reverse of what tmVirtualGetRaw is doing.
*/
*pu64Delta = u64GipTime;
{
u64GipTime *= 100;
}
#ifndef IN_RING3
if (RT_SUCCESS(rc))
#endif
return u64GipTime;
}
#endif
/**
* Gets the host context ring-3 pointer of the timer.
*
* @returns HC R3 pointer.
* @param pTimer Timer handle as returned by one of the create functions.
*/
{
}
/**
* Gets the host context ring-0 pointer of the timer.
*
* @returns HC R0 pointer.
* @param pTimer Timer handle as returned by one of the create functions.
*/
{
}
/**
* Gets the RC pointer of the timer.
*
* @returns RC pointer.
* @param pTimer Timer handle as returned by one of the create functions.
*/
{
}
#ifdef IN_RING3 /* Kept here until properly cleaned up to not use any of the local functions. */
/**
* Destroy a timer
*
* @returns VBox status.
* @param pTimer Timer handle as returned by one of the create functions.
*/
{
/*
* Be extra careful here.
*/
if (!pTimer)
return VINF_SUCCESS;
bool fActive = false;
bool fPending = false;
/*
* The rest of the game happens behind the lock, just
* like create does. All the work is done here.
*/
{
/*
* Change to the DESTROY state.
*/
Log2(("TMTimerDestroy: %p:{.enmState=%s, .pszDesc='%s'} cRetries=%d\n",
switch (enmState)
{
case TMTIMERSTATE_STOPPED:
case TMTIMERSTATE_EXPIRED:
break;
case TMTIMERSTATE_ACTIVE:
fActive = true;
break;
fActive = true;
fPending = true;
break;
fPending = true;
break;
/*
* This shouldn't happen as the caller should make sure there are no races.
*/
if (!RTThreadYield())
RTThreadSleep(1);
AssertMsgReturn(cRetries > 0, ("Failed waiting for stable state. state=%d (%s)\n", pTimer->enmState, pTimer->pszDesc),
continue;
/*
* Invalid states.
*/
case TMTIMERSTATE_FREE:
case TMTIMERSTATE_DESTROY:
AssertLogRelMsgFailedReturn(("pTimer=%p %s\n", pTimer, tmTimerState(enmState)), VERR_TM_INVALID_STATE);
default:
return VERR_TM_UNKNOWN_STATE;
}
/*
* Try switch to the destroy state.
* This should always succeed as the caller should make sure there are no race.
*/
break;
AssertMsgReturn(cRetries > 0, ("Failed waiting for stable state. state=%d (%s)\n", pTimer->enmState, pTimer->pszDesc),
}
/*
* Unlink from the active list.
*/
if (fActive)
{
if (pPrev)
else
{
}
if (pNext)
}
/*
* Unlink from the schedule list by running it.
*/
if (fPending)
{
Log3(("TMR3TimerDestroy: tmTimerQueueSchedule\n"));
}
/*
* Read to move the timer from the created list and onto the free list.
*/
/* unlink from created list */
else
/* free */
#ifdef VBOX_STRICT
#endif
return VINF_SUCCESS;
}
#endif /* IN_RING3 */
/**
* Arm a timer with a (new) expire time.
*
* @returns VBox status.
* @param pTimer Timer handle as returned by one of the create functions.
* @param u64Expire New expire time.
*/
{
/** @todo find the most frequently used paths and make them skip tmSchedule and tmTimerTryWithLink. */
int cRetries = 1000;
do
{
/*
* Change to any of the SET_EXPIRE states if valid and then to SCHEDULE or RESCHEDULE.
*/
Log2(("TMTimerSet: %p:{.enmState=%s, .pszDesc='%s'} cRetries=%d u64Expire=%llu\n",
switch (enmState)
{
case TMTIMERSTATE_EXPIRED:
case TMTIMERSTATE_STOPPED:
{
("%RU64 < %RU64 %s\n", u64Expire, pTimer->CTX_SUFF(pVM)->tm.s.u64VirtualSync, R3STRING(pTimer->pszDesc)));
return VINF_SUCCESS;
}
break;
{
return VINF_SUCCESS;
}
break;
case TMTIMERSTATE_ACTIVE:
{
return VINF_SUCCESS;
}
break;
{
return VINF_SUCCESS;
}
break;
#ifdef IN_RING3
if (!RTThreadYield())
RTThreadSleep(1);
#else
/** @todo call host context and yield after a couple of iterations */
#endif
break;
/*
* Invalid states.
*/
case TMTIMERSTATE_DESTROY:
case TMTIMERSTATE_FREE:
return VERR_TM_INVALID_STATE;
default:
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;
}
/**
* Arm a timer with a (new) expire time relative to current time.
*
* @returns VBox status.
* @param pTimer Timer handle as returned by one of the create functions.
* @param cMilliesToNext Number of millieseconds to the next tick.
*/
{
{
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));
default:
return VERR_INTERNAL_ERROR;
}
}
/**
* Arm a timer with a (new) expire time relative to current time.
*
* @returns VBox status.
* @param pTimer Timer handle as returned by one of the create functions.
* @param cMicrosToNext Number of microseconds to the next tick.
*/
{
{
case TMCLOCK_VIRTUAL:
case TMCLOCK_VIRTUAL_SYNC:
case TMCLOCK_REAL:
case TMCLOCK_TSC:
default:
return VERR_INTERNAL_ERROR;
}
}
/**
* Arm a timer with a (new) expire time relative to current time.
*
* @returns VBox status.
* @param pTimer Timer handle as returned by one of the create functions.
* @param cNanosToNext Number of nanoseconds to the next tick.
*/
{
{
case TMCLOCK_VIRTUAL:
case TMCLOCK_VIRTUAL_SYNC:
case TMCLOCK_REAL:
case TMCLOCK_TSC:
default:
return VERR_INTERNAL_ERROR;
}
}
/**
* Stop the timer.
* Use TMR3TimerArm() to "un-stop" the timer.
*
* @returns VBox status.
* @param pTimer Timer handle as returned by one of the create functions.
*/
{
/** @todo see if this function needs optimizing. */
int cRetries = 1000;
do
{
/*
* Change to any of the SET_EXPIRE states if valid and then to SCHEDULE or RESCHEDULE.
*/
Log2(("TMTimerStop: %p:{.enmState=%s, .pszDesc='%s'} cRetries=%d\n",
switch (enmState)
{
case TMTIMERSTATE_EXPIRED:
//AssertMsgFailed(("You don't stop an expired timer dude!\n"));
return VERR_INVALID_PARAMETER;
case TMTIMERSTATE_STOPPED:
return VINF_SUCCESS;
{
return VINF_SUCCESS;
}
{
return VINF_SUCCESS;
}
break;
case TMTIMERSTATE_ACTIVE:
{
return VINF_SUCCESS;
}
break;
#ifdef IN_RING3
if (!RTThreadYield())
RTThreadSleep(1);
#else
/**@todo call host and yield cpu after a while. */
#endif
break;
/*
* Invalid states.
*/
case TMTIMERSTATE_DESTROY:
case TMTIMERSTATE_FREE:
return VERR_TM_INVALID_STATE;
default:
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;
}
/**
* Get the current clock time.
* Handy for calculating the new expire time.
*
* @returns Current clock time.
* @param pTimer Timer handle as returned by one of the create functions.
*/
{
{
case TMCLOCK_VIRTUAL:
break;
case TMCLOCK_VIRTUAL_SYNC:
break;
case TMCLOCK_REAL:
break;
case TMCLOCK_TSC:
{
break;
}
default:
return ~(uint64_t)0;
}
//Log2(("TMTimerGet: returns %llu (pTimer=%p:{.enmState=%s, .pszDesc='%s'})\n",
// u64, pTimer, tmTimerState(pTimer->enmState), R3STRING(pTimer->pszDesc)));
return u64;
}
/**
* Get the freqency of the timer clock.
*
* @returns Clock frequency (as Hz of course).
* @param pTimer Timer handle as returned by one of the create functions.
*/
{
{
case TMCLOCK_VIRTUAL:
case TMCLOCK_VIRTUAL_SYNC:
return TMCLOCK_FREQ_VIRTUAL;
case TMCLOCK_REAL:
return TMCLOCK_FREQ_REAL;
case TMCLOCK_TSC:
default:
return 0;
}
}
/**
* Get the current clock time as nanoseconds.
*
* @returns The timer clock as nanoseconds.
* @param pTimer Timer handle as returned by one of the create functions.
*/
{
}
/**
* Get the current clock time as microseconds.
*
* @returns The timer clock as microseconds.
* @param pTimer Timer handle as returned by one of the create functions.
*/
{
}
/**
* Get the current clock time as milliseconds.
*
* @returns The timer clock as milliseconds.
* @param pTimer Timer handle as returned by one of the create functions.
*/
{
}
/**
* Converts the specified timer clock time to nanoseconds.
*
* @returns nanoseconds.
* @param pTimer Timer handle as returned by one of the create functions.
* @param u64Ticks The clock ticks.
* @remark There could be rounding errors here. We just do a simple integere divide
* without any adjustments.
*/
{
{
case TMCLOCK_VIRTUAL:
case TMCLOCK_VIRTUAL_SYNC:
return u64Ticks;
case TMCLOCK_REAL:
return u64Ticks * 1000000;
case TMCLOCK_TSC:
AssertReleaseMsgFailed(("TMCLOCK_TSC conversions are not implemented\n"));
return 0;
default:
return 0;
}
}
/**
* Converts the specified timer clock time to microseconds.
*
* @returns microseconds.
* @param pTimer Timer handle as returned by one of the create functions.
* @param u64Ticks The clock ticks.
* @remark There could be rounding errors here. We just do a simple integere divide
* without any adjustments.
*/
{
{
case TMCLOCK_VIRTUAL:
case TMCLOCK_VIRTUAL_SYNC:
return u64Ticks / 1000;
case TMCLOCK_REAL:
return u64Ticks * 1000;
case TMCLOCK_TSC:
AssertReleaseMsgFailed(("TMCLOCK_TSC conversions are not implemented\n"));
return 0;
default:
return 0;
}
}
/**
* Converts the specified timer clock time to milliseconds.
*
* @returns milliseconds.
* @param pTimer Timer handle as returned by one of the create functions.
* @param u64Ticks The clock ticks.
* @remark There could be rounding errors here. We just do a simple integere divide
* without any adjustments.
*/
{
{
case TMCLOCK_VIRTUAL:
case TMCLOCK_VIRTUAL_SYNC:
return u64Ticks / 1000000;
case TMCLOCK_REAL:
return u64Ticks;
case TMCLOCK_TSC:
AssertReleaseMsgFailed(("TMCLOCK_TSC conversions are not implemented\n"));
return 0;
default:
return 0;
}
}
/**
* Converts the specified nanosecond timestamp to timer clock ticks.
*
* @returns timer clock ticks.
* @param pTimer Timer handle as returned by one of the create functions.
* @param u64NanoTS The nanosecond value ticks to convert.
* @remark There could be rounding and overflow errors here.
*/
{
{
case TMCLOCK_VIRTUAL:
case TMCLOCK_VIRTUAL_SYNC:
return u64NanoTS;
case TMCLOCK_REAL:
return u64NanoTS / 1000000;
case TMCLOCK_TSC:
AssertReleaseMsgFailed(("TMCLOCK_TSC conversions are not implemented\n"));
return 0;
default:
return 0;
}
}
/**
* Converts the specified microsecond timestamp to timer clock ticks.
*
* @returns timer clock ticks.
* @param pTimer Timer handle as returned by one of the create functions.
* @param u64MicroTS The microsecond value ticks to convert.
* @remark There could be rounding and overflow errors here.
*/
{
{
case TMCLOCK_VIRTUAL:
case TMCLOCK_VIRTUAL_SYNC:
return u64MicroTS * 1000;
case TMCLOCK_REAL:
return u64MicroTS / 1000;
case TMCLOCK_TSC:
AssertReleaseMsgFailed(("TMCLOCK_TSC conversions are not implemented\n"));
return 0;
default:
return 0;
}
}
/**
* Converts the specified millisecond timestamp to timer clock ticks.
*
* @returns timer clock ticks.
* @param pTimer Timer handle as returned by one of the create functions.
* @param u64MilliTS The millisecond value ticks to convert.
* @remark There could be rounding and overflow errors here.
*/
{
{
case TMCLOCK_VIRTUAL:
case TMCLOCK_VIRTUAL_SYNC:
return u64MilliTS * 1000000;
case TMCLOCK_REAL:
return u64MilliTS;
case TMCLOCK_TSC:
AssertReleaseMsgFailed(("TMCLOCK_TSC conversions are not implemented\n"));
return 0;
default:
return 0;
}
}
/**
* Get the expire time of the timer.
* Only valid for active timers.
*
* @returns Expire time of the timer.
* @param pTimer Timer handle as returned by one of the create functions.
*/
{
int cRetries = 1000;
do
{
switch (enmState)
{
case TMTIMERSTATE_EXPIRED:
case TMTIMERSTATE_STOPPED:
Log2(("TMTimerGetExpire: returns ~0 (pTimer=%p:{.enmState=%s, .pszDesc='%s'})\n",
return ~(uint64_t)0;
case TMTIMERSTATE_ACTIVE:
Log2(("TMTimerGetExpire: returns %llu (pTimer=%p:{.enmState=%s, .pszDesc='%s'})\n",
#ifdef IN_RING3
if (!RTThreadYield())
RTThreadSleep(1);
#endif
break;
/*
* Invalid states.
*/
case TMTIMERSTATE_DESTROY:
case TMTIMERSTATE_FREE:
Log2(("TMTimerGetExpire: returns ~0 (pTimer=%p:{.enmState=%s, .pszDesc='%s'})\n",
return ~(uint64_t)0;
default:
return ~(uint64_t)0;
}
} while (cRetries-- > 0);
AssertMsgFailed(("Failed waiting for stable state. state=%d (%s)\n", pTimer->enmState, R3STRING(pTimer->pszDesc)));
Log2(("TMTimerGetExpire: returns ~0 (pTimer=%p:{.enmState=%s, .pszDesc='%s'})\n",
return ~(uint64_t)0;
}
/**
* Checks if a timer is active or not.
*
* @returns True if active.
* @returns False if not active.
* @param pTimer Timer handle as returned by one of the create functions.
*/
{
switch (enmState)
{
case TMTIMERSTATE_STOPPED:
case TMTIMERSTATE_EXPIRED:
Log2(("TMTimerIsActive: returns false (pTimer=%p:{.enmState=%s, .pszDesc='%s'})\n",
return false;
case TMTIMERSTATE_ACTIVE:
Log2(("TMTimerIsActive: returns true (pTimer=%p:{.enmState=%s, .pszDesc='%s'})\n",
return true;
/*
* Invalid states.
*/
case TMTIMERSTATE_DESTROY:
case TMTIMERSTATE_FREE:
AssertMsgFailed(("Invalid timer state %s (%s)\n", tmTimerState(enmState), R3STRING(pTimer->pszDesc)));
Log2(("TMTimerIsActive: returns false (pTimer=%p:{.enmState=%s, .pszDesc='%s'})\n",
return false;
default:
return false;
}
}
/**
* Convert state to string.
*
* @returns Readonly status name.
* @param enmState State.
*/
{
switch (enmState)
{
case TMTIMERSTATE_##state: \
default:
return "Invalid state!";
}
}
/**
* Schedules the given timer on the given queue.
*
* @param pQueue The timer queue.
* @param pTimer The timer that needs scheduling.
*
* @remarks Called while owning the lock.
*/
{
/*
* Processing.
*/
unsigned cRetries = 2;
do
{
switch (enmState)
{
/*
* Reschedule timer (in the active list).
*/
{
if (RT_UNLIKELY(!tmTimerTry(pTimer, TMTIMERSTATE_PENDING_SCHEDULE, TMTIMERSTATE_PENDING_RESCHEDULE)))
break; /* retry */
if (pPrev)
else
{
}
if (pNext)
/* fall thru */
}
/*
* Schedule timer (insert into the active list).
*/
{
break; /* retry */
if (pCur)
{
{
{
if (pPrev)
else
{
}
return;
}
{
return;
}
}
}
else
{
}
return;
}
/*
* Stop the timer in active list.
*/
{
if (RT_UNLIKELY(!tmTimerTry(pTimer, TMTIMERSTATE_PENDING_STOP_SCHEDULE, TMTIMERSTATE_PENDING_STOP)))
break; /* retry */
if (pPrev)
else
{
}
if (pNext)
/* fall thru */
}
/*
* Stop the timer (not on the active list).
*/
break;
return;
/*
* The timer is pending destruction by TMR3TimerDestroy, our caller.
* Nothing to do here.
*/
case TMTIMERSTATE_DESTROY:
break;
/*
* Postpone these until they get into the right state.
*/
return;
/*
* None of these can be in the schedule.
*/
case TMTIMERSTATE_FREE:
case TMTIMERSTATE_STOPPED:
case TMTIMERSTATE_ACTIVE:
case TMTIMERSTATE_EXPIRED:
default:
AssertMsgFailed(("Timer (%p) in the scheduling list has an invalid state %s (%d)!",
return;
}
} while (cRetries-- > 0);
}
/**
* Schedules the specified timer queue.
*
* @param pVM The VM to run the timers for.
* @param pQueue The queue to schedule.
*
* @remarks Called while owning the lock.
*/
{
/*
* Dequeue the scheduling list and iterate it.
*/
Log2(("tmTimerQueueSchedule: pQueue=%p:{.enmClock=%d, offNext=%RI32}\n", pQueue, pQueue->enmClock, offNext));
if (!offNext)
return;
while (pNext)
{
/*
* Unlink the head timer and find the next one.
*/
pTimer->offScheduleNext = 0;
/*
* Do the scheduling.
*/
Log2(("tmTimerQueueSchedule: %p:{.enmState=%s, .enmClock=%d, .enmType=%d, .pszDesc=%s}\n",
pTimer, tmTimerState(pTimer->enmState), pTimer->enmClock, pTimer->enmType, R3STRING(pTimer->pszDesc)));
} /* foreach timer in current schedule batch. */
}
#ifdef VBOX_STRICT
/**
* Checks that the timer queues are sane.
*
* @param pVM VM handle.
*
* @remarks Called while owning the lock.
*/
{
/*
* Check the linking of the active lists.
*/
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:
break;
break;
default:
AssertMsgFailed(("%s: Invalid state enmState=%d %s\n", pszWhere, enmState, tmTimerState(enmState)));
break;
}
}
}
# ifdef IN_RING3
/*
* Do the big list and check that active timers all are in the active lists.
*/
{
switch (enmState)
{
case TMTIMERSTATE_ACTIVE:
{
break;
}
case TMTIMERSTATE_STOPPED:
case TMTIMERSTATE_EXPIRED:
{
{
}
break;
}
/* ignore */
break;
/* shouldn't get here! */
case TMTIMERSTATE_DESTROY:
default:
break;
}
}
# endif /* IN_RING3 */
}
#endif /* !VBOX_STRICT */
/**
* Gets the current warp drive percent.
*
* @returns The warp drive percent.
* @param pVM The VM handle.
*/
{
}