Author: fireball Date: Sun Jan 3 19:29:30 2010 New Revision: 44918
URL: http://svn.reactos.org/svn/reactos?rev=44918&view=rev Log: Samuel Serapion - Implement ExSetTimerResolution, tested with a VirtualBox driver. - Rewrite comments in TimeRefresh lock/unlock functions.
Modified: trunk/reactos/ntoskrnl/ex/time.c
Modified: trunk/reactos/ntoskrnl/ex/time.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ex/time.c?rev=4491... ============================================================================== --- trunk/reactos/ntoskrnl/ex/time.c [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/ex/time.c [iso-8859-1] Sun Jan 3 19:29:30 2010 @@ -25,33 +25,195 @@ 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) -{ - /* Simply acquire the Resource */ +ExAcquireTimeRefreshLock( + IN BOOLEAN Wait + ) +{ + /* 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) -{ - /* Simply release the Resource */ +ExReleaseTimeRefreshLock( + VOID + ) +{ + /* 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 @@ -306,18 +468,6 @@ }
/* - * @unimplemented - */ -ULONG -NTAPI -ExSetTimerResolution(IN ULONG DesiredTime, - IN BOOLEAN SetResolution) -{ - UNIMPLEMENTED; - return 0; -} - -/* * @implemented */ VOID