mirror of
https://github.com/ApfelTeeSaft/reactos.git
synced 2026-08-29 19:26:33 +00:00
Samuel Serapion
- Implement ExSetTimerResolution, tested with a VirtualBox driver. - Rewrite comments in TimeRefresh lock/unlock functions. svn path=/trunk/; revision=44918
This commit is contained in:
+168
-18
@@ -25,35 +25,197 @@ ULONG ExpAltTimeZoneBias;
|
||||
ULONG ExpTimeZoneId;
|
||||
ULONG ExpTickCountMultiplier;
|
||||
ERESOURCE ExpTimeRefreshLock;
|
||||
ULONG ExpKernelResolutionCount = 0;
|
||||
ULONG ExpTimerResolutionCount = 0;
|
||||
|
||||
/* FUNCTIONS ****************************************************************/
|
||||
|
||||
/*++
|
||||
* @name ExAcquireTimeRefreshLock
|
||||
*
|
||||
* The ExReleaseTimeRefreshLock routine acquires the system-wide lock used
|
||||
* to synchronize clock interrupt frequency changes.
|
||||
*
|
||||
* @param Wait
|
||||
* If TRUE, the system will block the caller thread waiting for the lock
|
||||
* to become available. If FALSE, the routine will fail if the lock has
|
||||
* already been acquired.
|
||||
*
|
||||
* @return Boolean value indicating success or failure of the lock acquisition.
|
||||
*
|
||||
* @remarks None.
|
||||
*
|
||||
*--*/
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
ExAcquireTimeRefreshLock(BOOLEAN Wait)
|
||||
ExAcquireTimeRefreshLock(
|
||||
IN BOOLEAN Wait
|
||||
)
|
||||
{
|
||||
/* Simply acquire the Resource */
|
||||
/* Block APCs */
|
||||
KeEnterCriticalRegion();
|
||||
|
||||
/* Attempt lock acquisition */
|
||||
if (!(ExAcquireResourceExclusiveLite(&ExpTimeRefreshLock, Wait)))
|
||||
{
|
||||
/* We failed! */
|
||||
/* Lock was not acquired, enable APCs and fail */
|
||||
KeLeaveCriticalRegion();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Success */
|
||||
/* Lock has been acquired */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*++
|
||||
* @name ExReleaseTimeRefreshLock
|
||||
*
|
||||
* The ExReleaseTimeRefreshLock routine releases the system-wide lock used
|
||||
* to synchronize clock interrupt frequency changes.
|
||||
*
|
||||
* @param None.
|
||||
*
|
||||
* @return None.
|
||||
*
|
||||
* @remarks None.
|
||||
*
|
||||
*--*/
|
||||
VOID
|
||||
NTAPI
|
||||
ExReleaseTimeRefreshLock(VOID)
|
||||
ExReleaseTimeRefreshLock(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
/* Simply release the Resource */
|
||||
/* Release the lock and re-enable APCs */
|
||||
ExReleaseResourceLite(&ExpTimeRefreshLock);
|
||||
KeLeaveCriticalRegion();
|
||||
}
|
||||
|
||||
/*++
|
||||
* @name ExSetTimerResolution
|
||||
* @exported
|
||||
*
|
||||
* The KiInsertQueueApc routine modifies the frequency at which the system
|
||||
* clock interrupts.
|
||||
*
|
||||
* @param DesiredTime
|
||||
* Specifies the amount of time that should elapse between each timer
|
||||
* interrupt, in 100-nanosecond units.
|
||||
*
|
||||
* This parameter is ignored if SetResolution is FALSE.
|
||||
*
|
||||
* @param SetResolution
|
||||
* If TRUE, the call is a request to set the clock interrupt frequency to
|
||||
* the value specified by DesiredTime. If FALSE, the call is a request to
|
||||
* restore the clock interrupt frequency to the system's default value.
|
||||
*
|
||||
* @return New timer resolution, in 100-nanosecond ticks.
|
||||
*
|
||||
* @remarks (1) The clock frequency is changed only if the DesiredTime value is
|
||||
* less than the current setting.
|
||||
*
|
||||
* (2) The routine just returns the current setting if the DesiredTime
|
||||
* value is greater than what is currently set.
|
||||
*
|
||||
* (3) If the DesiredTime value is less than the system clock can
|
||||
* support, the routine uses the smallest resolution the system can
|
||||
* support, and returns that value.
|
||||
*
|
||||
* (4) If multiple drivers have attempted to change the clock interrupt
|
||||
* frequency, the system will only restore the default frequency
|
||||
* once ALL drivers have called the routine with SetResolution set
|
||||
* to FALSE.
|
||||
*
|
||||
* NB. This routine synchronizes with IRP_MJ_POWER requests through the
|
||||
* TimeRefreshLock.
|
||||
*
|
||||
*--*/
|
||||
ULONG
|
||||
NTAPI
|
||||
ExSetTimerResolution(IN ULONG DesiredTime,
|
||||
IN BOOLEAN SetResolution)
|
||||
{
|
||||
ULONG CurrentIncrement;
|
||||
|
||||
/* Wait for clock interrupt frequency and power requests to synchronize */
|
||||
ExAcquireTimeRefreshLock(TRUE);
|
||||
|
||||
/* Obey remark 2*/
|
||||
CurrentIncrement = KeTimeIncrement;
|
||||
|
||||
/* Check the type of operation this is */
|
||||
if (SetResolution)
|
||||
{
|
||||
/*
|
||||
* If this is the first kernel change, bump the timer resolution change
|
||||
* count, then bump the kernel change count as well.
|
||||
*
|
||||
* These two variables are tracked differently since user-mode processes
|
||||
* can also change the timer resolution through the NtSetTimerResolution
|
||||
* system call. A per-process flag in the EPROCESS then stores the per-
|
||||
* process change state.
|
||||
*
|
||||
*/
|
||||
if (!ExpKernelResolutionCount++) ExpTimerResolutionCount++;
|
||||
|
||||
/* Obey remark 3 */
|
||||
if (DesiredTime < KeMinimumIncrement) DesiredTime = KeMinimumIncrement;
|
||||
|
||||
/* Obey remark 1 */
|
||||
if (DesiredTime < KeTimeIncrement)
|
||||
{
|
||||
/* Force this thread on CPU zero, since we don't want it to drift */
|
||||
KeSetSystemAffinityThread(1);
|
||||
|
||||
/* Now call the platform driver (HAL) to make the change */
|
||||
CurrentIncrement = HalSetTimeIncrement(DesiredTime);
|
||||
|
||||
/* Put the thread back to its original affinity */
|
||||
KeRevertToUserAffinityThread();
|
||||
|
||||
/* Finally, keep track of the new value in the kernel */
|
||||
KeTimeIncrement = CurrentIncrement;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* First, make sure that a driver has actually changed the resolution */
|
||||
if (ExpKernelResolutionCount)
|
||||
{
|
||||
/* Obey remark 4 */
|
||||
if (--ExpKernelResolutionCount)
|
||||
{
|
||||
/*
|
||||
* All kernel drivers have requested the original frequency to
|
||||
* be restored, but there might still be user processes with an
|
||||
* ongoing clock interrupt frequency change, so make sure that
|
||||
* this isn't the case.
|
||||
*/
|
||||
if (--ExpTimerResolutionCount)
|
||||
{
|
||||
/* Force this thread on one CPU so that it doesn't drift */
|
||||
KeSetSystemAffinityThread(1);
|
||||
|
||||
/* Call the HAL to restore the frequency to its default */
|
||||
CurrentIncrement = HalSetTimeIncrement(KeMaximumIncrement);
|
||||
|
||||
/* Put the thread back to its original affinity */
|
||||
KeRevertToUserAffinityThread();
|
||||
|
||||
/* Finally, keep track of the new value in the kernel */
|
||||
KeTimeIncrement = CurrentIncrement;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Release the clock interrupt frequency lock since changes are done */
|
||||
ExReleaseTimeRefreshLock();
|
||||
|
||||
/* And return the current value -- which could reflect the new frequency */
|
||||
return CurrentIncrement;
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
ExUpdateSystemTimeFromCmos(IN BOOLEAN UpdateInterruptTime,
|
||||
@@ -305,18 +467,6 @@ ExLocalTimeToSystemTime(PLARGE_INTEGER LocalTime,
|
||||
SystemTime->QuadPart = LocalTime->QuadPart + ExpTimeZoneBias.QuadPart;
|
||||
}
|
||||
|
||||
/*
|
||||
* @unimplemented
|
||||
*/
|
||||
ULONG
|
||||
NTAPI
|
||||
ExSetTimerResolution(IN ULONG DesiredTime,
|
||||
IN BOOLEAN SetResolution)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user