[NTOS]: Implement KeUpdateSystemTime and KeUpdateRunTime in C instead of ASM. Based off eVb's ARM implementation, with multiple bugs fixed (incorrect update of system counters, incorrect expiration of timers, remove non-used debug features, use locks when needed).

[NTOS]: Implement KiComputeTimerTableIndex in C instead of ASM. Based off eVb's ARM implementation, bugfixed to do correct math instead.

As a side effect, this should fix timers on ARM ;-)

svn path=/trunk/; revision=45140
This commit is contained in:
Sir Richard 2010-01-19 06:16:47 +00:00
parent d6b8e75c83
commit bf8b9467dc
7 changed files with 255 additions and 713 deletions

View file

@ -728,12 +728,6 @@ KiTimerExpiration(
IN PVOID SystemArgument2
);
ULONG
NTAPI
KiComputeTimerTableIndex(
IN LONGLONG TimeValue
);
ULONG
NTAPI
KeSetProcess(

View file

@ -972,6 +972,13 @@ KiCheckAlertability(IN PKTHREAD Thread,
return STATUS_WAIT_0;
}
ULONG
FORCEINLINE
KiComputeTimerTableIndex(IN ULONGLONG DueTime)
{
return (DueTime / KeMaximumIncrement) & (TIMER_TABLE_SIZE - 1);
}
//
// Called from KiCompleteTimer, KiInsertTreeTimer, KeSetSystemTime
// to remove timer entries

View file

@ -1,322 +0,0 @@
/*
* PROJECT: ReactOS Kernel
* LICENSE: BSD - See COPYING.ARM in the top level directory
* FILE: ntoskrnl/ke/arm/time.c
* PURPOSE: Implements timebase functionality on ARM processors
* PROGRAMMERS: ReactOS Portable Systems Group
*/
/* INCLUDES *******************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <debug.h>
/* GLOBALS ********************************************************************/
LONG KiTickOffset;
ULONG KeTimeAdjustment;
/* FUNCTIONS ******************************************************************/
ULONG
KiComputeTimerTableIndex(IN LONGLONG DueTime)
{
ULONG Hand;
//
// Compute the timer table index
//
Hand = (DueTime / KeMaximumIncrement);
Hand %= TIMER_TABLE_SIZE;
return Hand;
}
VOID
NTAPI
KeUpdateSystemTime(IN PKTRAP_FRAME TrapFrame,
IN KIRQL Irql,
IN ULONG Increment)
{
PKPRCB Prcb = KeGetPcr()->Prcb;
ULARGE_INTEGER SystemTime, InterruptTime;
ULONG Hand;
//
// Do nothing if this tick is being skipped
//
if (Prcb->SkipTick)
{
//
// Handle it next time
//
Prcb->SkipTick = FALSE;
return;
}
//
// Add the increment time to the shared data
//
InterruptTime.HighPart = SharedUserData->InterruptTime.High1Time;
InterruptTime.LowPart = SharedUserData->InterruptTime.LowPart;
InterruptTime.QuadPart += Increment;
SharedUserData->InterruptTime.High1Time = InterruptTime.HighPart;
SharedUserData->InterruptTime.LowPart = InterruptTime.LowPart;
SharedUserData->InterruptTime.High2Time = InterruptTime.HighPart;
//
// Update tick count
//
KiTickOffset -= Increment;
//
// Check for incomplete tick
//
if (KiTickOffset <= 0)
{
//
// Update the system time
//
SystemTime.HighPart = SharedUserData->SystemTime.High1Time;
SystemTime.LowPart = SharedUserData->SystemTime.LowPart;
SystemTime.QuadPart += KeTimeAdjustment;
SharedUserData->SystemTime.High1Time = SystemTime.HighPart;
SharedUserData->SystemTime.LowPart = SystemTime.LowPart;
SharedUserData->SystemTime.High2Time = SystemTime.HighPart;
//
// Update the tick count
//
SystemTime.HighPart = KeTickCount.High1Time;
SystemTime.LowPart = KeTickCount.LowPart;
SystemTime.QuadPart += 1;
KeTickCount.High1Time = SystemTime.HighPart;
KeTickCount.LowPart = SystemTime.LowPart;
KeTickCount.High2Time = SystemTime.HighPart;
//
// Update it in the shared user data
//
SharedUserData->TickCount.High1Time = SystemTime.HighPart;
SharedUserData->TickCount.LowPart = SystemTime.LowPart;
SharedUserData->TickCount.High2Time = SystemTime.HighPart;
}
//
// Check for timer expiration
//
Hand = KeTickCount.LowPart % TIMER_TABLE_SIZE;
if (KiTimerTableListHead[Hand].Time.QuadPart <= InterruptTime.QuadPart)
{
//
// Check if we are already doing expiration
//
if (!Prcb->TimerRequest)
{
//
// Request a DPC to handle this
//
Prcb->TimerRequest = TrapFrame->SvcSp;
Prcb->TimerHand = Hand;
HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
}
}
//
// Check if we should request a debugger break
//
if (KdDebuggerEnabled)
{
//
// Check if we should break
//
if (KdPollBreakIn()) DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C);
}
//
// Check if this was a full tick
//
if (KiTickOffset <= 0)
{
//
// Updare the tick offset
//
KiTickOffset += KeMaximumIncrement;
//
// Update system runtime
//
KeUpdateRunTime(TrapFrame, CLOCK2_LEVEL);
}
else
{
//
// Increase interrupt count and exit
//
Prcb->InterruptCount++;
}
}
VOID
NTAPI
KeUpdateRunTime(IN PKTRAP_FRAME TrapFrame,
IN KIRQL Irql)
{
PKTHREAD Thread = KeGetCurrentThread();
PKPROCESS Process = Thread->ApcState.Process;
PKPRCB Prcb = KeGetCurrentPrcb();
//
// Do nothing if this tick is being skipped
//
if (Prcb->SkipTick)
{
//
// Handle it next time
//
Prcb->SkipTick = FALSE;
return;
}
//
// Increase interrupt count
//
Prcb->InterruptCount++;
//
// Check if we came from user mode
//
if (TrapFrame->PreviousMode != KernelMode)
{
//
// Increase process user time
//
InterlockedIncrement((PLONG)&Process->UserTime);
Prcb->UserTime++;
Thread->UserTime++;
}
else
{
//
// See if we were in an ISR
//
if (TrapFrame->OldIrql > DISPATCH_LEVEL)
{
//
// Handle that
//
Prcb->InterruptTime++;
}
else if ((TrapFrame->OldIrql < DISPATCH_LEVEL) ||
!(Prcb->DpcRoutineActive))
{
//
// Handle being in kernel mode
//
Thread->KernelTime++;
InterlockedIncrement((PLONG)&Process->KernelTime);
}
else
{
//
// Handle being in a DPC
//
Prcb->DpcTime++;
//
// Update Debug DPC time
//
Prcb->DebugDpcTime++;
//
// Check if we've timed out
//
if (Prcb->DebugDpcTime >= KiDPCTimeout)
{
//
// Print a message
//
DbgPrint("\n*** DPC routine > 1 sec --- This is not a break in "
"KeUpdateSystemTime\n");
//
// Break if a debugger is attached
//
if (KdDebuggerEnabled) DbgBreakPoint();
//
// Restore the debug DPC time
//
Prcb->DebugDpcTime = 0;
}
}
}
//
// Update DPC rates
//
Prcb->DpcRequestRate = ((Prcb->DpcData[0].DpcCount - Prcb->DpcLastCount) +
Prcb->DpcRequestRate) >> 1;
Prcb->DpcLastCount = Prcb->DpcData[0].DpcCount;
//
// Check if the queue is large enough
//
if ((Prcb->DpcData[0].DpcQueueDepth) && !(Prcb->DpcRoutineActive))
{
//
// Request a DPC
//
Prcb->AdjustDpcThreshold = KiAdjustDpcThreshold;
HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
//
// Fix the maximum queue depth
//
if ((Prcb->DpcRequestRate < KiIdealDpcRate) &&
(Prcb->MaximumDpcQueueDepth > 1))
{
//
// Make it smaller
//
Prcb->MaximumDpcQueueDepth--;
}
}
else
{
//
// Check if we've reached the adjustment limit
//
if (!(--Prcb->AdjustDpcThreshold))
{
//
// Reset it, and check the queue maximum
//
Prcb->AdjustDpcThreshold = KiAdjustDpcThreshold;
if (KiMaximumDpcQueueDepth != Prcb->MaximumDpcQueueDepth)
{
//
// Increase it
//
Prcb->MaximumDpcQueueDepth++;
}
}
}
//
// Decrement the thread quantum
//
Thread->Quantum -= CLOCK_QUANTUM_DECREMENT;
//
// Check if the time expired
//
if ((Thread->Quantum <= 0) && (Thread != Prcb->IdleThread))
{
//
// Schedule a quantum end
//
Prcb->QuantumEnd = 1;
HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
}
}

View file

@ -1,383 +0,0 @@
/*
* FILE: ntoskrnl/ke/i386/clock.S
* COPYRIGHT: See COPYING in the top level directory
* PURPOSE: System Clock Management
* PROGRAMMER: Alex Ionescu (alex@relsoft.net)
*/
/* INCLUDES ******************************************************************/
#include <asm.h>
#include <internal/i386/asmmacro.S>
.intel_syntax noprefix
/* GLOBALS *******************************************************************/
_DpcTimeoutMsg:
.asciz "\n*** DPC routine > 1 sec --- This is not a break in KeUpdateSystemTime\n"
/* FUNCTIONS ******************************************************************/
.globl _KiComputeTimerTableIndex@8
.func KiComputeTimerTableIndex@8
_KiComputeTimerTableIndex@8:
/* Save registers */
push ebx
/* Make the first multiplication */
mov eax, [esp+8]
mul dword ptr [_KiTimeIncrementReciprocal+4]
mov ebx, eax
mov ecx, edx
/* Make the second multiplication */
mov eax, [esp+12]
mul dword ptr [_KiTimeIncrementReciprocal]
add ebx, eax
adc ecx, edx
/* Multiply by the reciprocal */
mov eax, [esp+8]
mul dword ptr [_KiTimeIncrementReciprocal]
mov eax, [esp+12]
push edx
mul dword ptr [_KiTimeIncrementReciprocal+4]
pop edx
add edx, ebx
adc eax, ecx
/* Shift the result and generate the index */
mov cl, [_KiTimeIncrementShiftCount]
shr eax, cl
and eax, TIMER_TABLE_SIZE - 1
/* Return */
pop ebx
ret 8
.endfunc
.globl _KeUpdateRunTime@8
.func KeUpdateRunTime@8
_KeUpdateRunTime@8:
/* Get KPCR */
mov eax, [fs:KPCR_SELF]
/* Check if this tick is getting skipped */
cmp byte ptr [eax+KPCR_PRCB_SKIP_TICK], 0
jnz SkipTick
/* Save EBX */
push ebx
/* Increase interrupt count */
inc dword ptr [eax+KPCR_PRCB_INTERRUPT_COUNT]
/* Get the current thread and process */
mov ebx, [eax+KPCR_CURRENT_THREAD]
mov ecx, [ebx+KTHREAD_APCSTATE_PROCESS]
/* Check if this was V86 or user mode */
test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
jnz NotKern
test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
jnz NotKern
/* Increase kernel time */
inc dword ptr [eax+KPCR_PRCB_KERNEL_TIME]
/* Check if IRQL was DISPATCH_LEVEL */
cmp byte ptr [esp+8], DISPATCH_LEVEL
jb BelowDispatch
ja AboveDispatch
/* Check if the DPC routine is active */
cmp byte ptr fs:[KPCR_PRCB_DPC_ROUTINE_ACTIVE], 0
jz BelowDispatch
/* At dispatch, increase DPC time */
inc dword ptr [eax+KPCR_PRCB_DPC_TIME]
#if DBG
/* Update the DPC time */
inc dword ptr [eax+KPCR_PRCB_DEBUG_DPC_TIME]
/* Check if we've timed out */
mov edx, _KiDPCTimeout
cmp dword ptr [eax+KPCR_PRCB_DEBUG_DPC_TIME], edx
jc AfterSet
/* We did, print out a message */
push offset _DpcTimeoutMsg
call _DbgPrint
add esp, 4
/* Check if the debugger is enabled */
cmp byte ptr __KdDebuggerEnabled, 0
jz ResetDpcTime
/* Breakpoint */
call _DbgBreakPoint@0
ResetDpcTime:
/* Restore state */
mov eax, PCR[KPCR_SELF]
mov dword ptr [eax+KPCR_PRCB_DEBUG_DPC_TIME], 0
#endif
jmp AfterSet
AboveDispatch:
/* Update interrupt time */
inc dword ptr [eax+KPCR_PRCB_INTERRUPT_TIME]
jmp AfterSet
BelowDispatch:
/* Update kernel time */
inc dword ptr [ebx+KTHREAD_KERNEL_TIME]
jmp AfterSet
NotKern:
/* Update user time */
inc dword ptr [eax+KPCR_PRCB_USER_TIME]
inc dword ptr [ebx+KTHREAD_USER_TIME]
AfterSet:
/* Get the DPC Count and last count, and set the ne wone */
mov ecx, [eax+KPCR_PRCB_DPC_COUNT]
mov edx, [eax+KPCR_PRCB_DPC_LAST_COUNT]
mov [eax+KPCR_PRCB_DPC_LAST_COUNT], ecx
/* Substract counts and add request rate, divide by two to get average */
sub ecx, edx
add ecx, [eax+KPCR_PRCB_DPC_REQUEST_RATE]
shr ecx, 1
/* Set this as the new request rate */
mov [eax+KPCR_PRCB_DPC_REQUEST_RATE], ecx
/* Check for depth > 0, DPCs to be inactive, and no other pending request */
cmp dword ptr [eax+KPCR_PRCB_DPC_QUEUE_DEPTH], 0
je DontRequest
cmp byte ptr [eax+KPCR_PRCB_DPC_ROUTINE_ACTIVE], 0
jnz DontRequest
cmp byte ptr [eax+KPCR_PRCB_DPC_INTERRUPT_REQUESTED], 0
jnz DontRequest
/* Request a DPC */
mov ecx, DISPATCH_LEVEL
call @HalRequestSoftwareInterrupt@4
/* Restore PCR address */
mov eax, [fs:KPCR_SELF]
/* Get the DPC request rate and threshold adjust, and set it */
mov ecx, [eax+KPCR_PRCB_DPC_REQUEST_RATE]
mov edx, _KiAdjustDpcThreshold
mov [eax+KPCR_PRCB_ADJUST_DPC_THRESHOLD], edx
/* Check if the rate now is not ideal */
cmp ecx, _KiIdealDpcRate
jge RateOk
cmp dword ptr [eax+KPCR_PRCB_MAXIMUM_DPC_QUEUE_DEPTH], 1
je RateOk
/* Fix the depth */
dec dword ptr [eax+KPCR_PRCB_MAXIMUM_DPC_QUEUE_DEPTH]
jmp RateOk
DontRequest:
/* We didn't request a DPC, decrease the threshold */
dec dword ptr [eax+KPCR_PRCB_ADJUST_DPC_THRESHOLD]
jnz RateOk
/* We're at 0 now, reset it */
mov ecx, _KiAdjustDpcThreshold
mov [eax+KPCR_PRCB_ADJUST_DPC_THRESHOLD], ecx
/* Get maximum depth and check it */
mov ecx, _KiMaximumDpcQueueDepth
cmp ecx, [eax+KPCR_PRCB_MAXIMUM_DPC_QUEUE_DEPTH]
je RateOk
/* Increase it, it's below maximum */
inc dword ptr [eax+KPCR_PRCB_MAXIMUM_DPC_QUEUE_DEPTH]
RateOk:
/* Decrement quantum and verify it */
sub byte ptr [ebx+KTHREAD_QUANTUM], CLOCK_QUANTUM_DECREMENT
jg QuantumNotEmpty
/* Make sure this isn't the idle thread */
cmp ebx, [eax+KPCR_PRCB_IDLE_THREAD]
jz QuantumNotEmpty
/* Set quantum end */
mov byte ptr [eax+KPCR_PRCB_QUANTUM_END], 1
mov ecx, DISPATCH_LEVEL
call @HalRequestSoftwareInterrupt@4
QuantumNotEmpty:
/* Restore ebx and return */
pop ebx
ret 4
SkipTick:
/* Disable skipping the next tick and return */
mov byte ptr [eax+KPCR_PRCB_SKIP_TICK], 0
ret 4
.endfunc
.globl _KeUpdateSystemTime@0
.func KeUpdateSystemTime@0
_KeUpdateSystemTime@0:
/* Check if this tick is getting skipped */
cmp byte ptr fs:[KPCR_PRCB_SKIP_TICK], 0
jnz SkipTickSys
/* Get shared data in ECX */
mov ecx, USER_SHARED_DATA
/* Get interrupt time */
mov edi, [ecx+USER_SHARED_DATA_INTERRUPT_TIME]
mov esi, [ecx+USER_SHARED_DATA_INTERRUPT_TIME+4]
/* Add the increment and get the carry */
add edi, eax
adc esi, 0
/* Now store the updated times */
mov [ecx+USER_SHARED_DATA_INTERRUPT_TIME+8], esi
mov [ecx+USER_SHARED_DATA_INTERRUPT_TIME], edi
mov [ecx+USER_SHARED_DATA_INTERRUPT_TIME+4], esi
/* Substract tick count and get the low count */
LOCK sub _KiTickOffset, eax
mov eax, _KeTickCount
mov ebx, eax
jg IncompleteTick
/* Get shared data in ECX */
mov ebx, USER_SHARED_DATA
/* Get system time */
mov ecx, [ebx+USER_SHARED_DATA_SYSTEM_TIME]
mov edx, [ebx+USER_SHARED_DATA_SYSTEM_TIME+4]
/* Add the increment and get the carry */
add ecx, _KeTimeAdjustment
adc edx, 0
/* Now store the updated times */
mov [ebx+USER_SHARED_DATA_SYSTEM_TIME+8], edx
mov [ebx+USER_SHARED_DATA_SYSTEM_TIME], ecx
mov [ebx+USER_SHARED_DATA_SYSTEM_TIME+4], edx
/* Put tick count back in EBX */
mov ebx, eax
/* Copy it in ECX and get high count */
mov ecx, eax
mov edx, _KeTickCount + 4
/* Add the increment and get the carry */
add ecx, 1
adc edx, 0
/* Now store the updated tick */
mov [_KeTickCount+8], edx
mov [_KeTickCount], ecx
mov [_KeTickCount+4], edx
/* Store in in shared data too */
mov ds:[USER_SHARED_DATA+USER_SHARED_DATA_TICK_COUNT+8], edx
mov ds:[USER_SHARED_DATA+USER_SHARED_DATA_TICK_COUNT], ecx
mov ds:[USER_SHARED_DATA+USER_SHARED_DATA_TICK_COUNT+4], edx
/* Get hand index and entry into the table */
and eax, TIMER_TABLE_SIZE - 1
shl eax, 4
/* Compare the due time */
cmp esi, [eax+_KiTimerTableListHead+KTIMER_TABLE_TIME+4]
jb NextHand
ja TimerExpired
cmp edi, [eax+_KiTimerTableListHead+KTIMER_TABLE_TIME]
jnb TimerExpired
NextHand:
/* Move to the next hand */
inc ebx
mov eax, ebx
IncompleteTick:
/* Get hand index and entry into the table */
and eax, TIMER_TABLE_SIZE - 1
shl eax, 4
/* Compare the due time */
cmp esi, [eax+_KiTimerTableListHead+KTIMER_TABLE_TIME+4]
jb DebugCheck
ja TimerExpired
cmp edi, [eax+_KiTimerTableListHead+KTIMER_TABLE_TIME]
jb DebugCheck
TimerExpired:
/* Check if expiration is active */
mov ecx, [fs:KPCR_PRCB]
cmp dword ptr [ecx+KPRCB_TIMER_REQUEST], 0
jne DebugCheck
/* It's not, register it */
mov [ecx+KPRCB_TIMER_REQUEST], esp
mov [ecx+KPRCB_TIMER_HAND], ebx
mov ecx, DISPATCH_LEVEL
call @HalRequestSoftwareInterrupt@4
DebugCheck:
/* Check if the debugger is enabled */
cmp byte ptr __KdDebuggerEnabled, 0
jnz DebuggerEnabled
/* Check if this was a full tick */
NoDebug:
cmp dword ptr _KiTickOffset, 0
jg IncompleteTick2
/* Increase tick offset */
mov eax, _KeMaximumIncrement
add _KiTickOffset, eax
/* Update system run time */
push [esp]
call _KeUpdateRunTime@8
jmp Done
IncompleteTick2:
/* Increase interrupt count */
inc dword ptr [fs:KPCR_PRCB_INTERRUPT_COUNT]
Done:
/* Exit the interrupt */
cli
call _HalEndSystemInterrupt@8
jmp _Kei386EoiHelper@0
DebuggerEnabled:
/* Check for break-in request */
call _KdPollBreakIn@0
or al, al
jz NoDebug
/* Break-in requested! */
push DBG_STATUS_CONTROL_C
call _DbgBreakPointWithStatus@4
jmp NoDebug
SkipTickSys:
/* Disable skipping the next tick and return */
mov byte ptr fs:[KPCR_PRCB_SKIP_TICK], 0
jmp IncompleteTick2
.endfunc

View file

@ -656,6 +656,41 @@ _KiUnexpectedInterrupt:
/* INTERRUPT HANDLERS ********************************************************/
.globl _KeUpdateSystemTime@0
.func KeUpdateSystemTime@0
_KeUpdateSystemTime@0:
/*
* When we enter here, the ASM HAL has:
* - Entered here with a JMP, not a CALL
* - Put increment in EAX
* - Pushed OldIRQL on the stack earlier [ESP]
* - Pushed Vector on the stack earlier [ESP + 4]
* - The trap frame at ESP + 8
*
* When the HAL moves to C, this shit needs to die!!!
*
*/
/* Call the regparm with Increment, OldIrql, TrapFrame */
mov edx, [esp]
mov ecx, ebp
call _KeUpdateSystemTimeHandler
/*
* The code below cannot be done in C because HalEndSystemInterrupt will
* fuck with your stack sideways when it decides to handle a pending APC or
* DPC!
*/
/* Stack is back where it was, HalEndSystemInterrupt will clean it up */
cli
call _HalEndSystemInterrupt@8
/* Now the stack has become the trap frame */
jmp _Kei386EoiHelper@0
.endfunc
.func KiDispatchInterrupt@0
_KiDispatchInterrupt@0:

212
reactos/ntoskrnl/ke/time.c Normal file
View file

@ -0,0 +1,212 @@
/*
* PROJECT: ReactOS Kernel
* LICENSE: BSD - See COPYING.ARM in the top level directory
* FILE: ntoskrnl/ke/time.c
* PURPOSE: Implements timebase functionality
* PROGRAMMERS: ReactOS Portable Systems Group
*/
/* INCLUDES *******************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <debug.h>
/* GLOBALS ********************************************************************/
LONG KiTickOffset;
ULONG KeTimeAdjustment;
/* FUNCTIONS ******************************************************************/
#ifndef _M_ARM
VOID
__attribute__((regparm(3)))
KeUpdateSystemTimeHandler(IN ULONG Increment,
IN KIRQL Irql,
IN PKTRAP_FRAME TrapFrame)
#else
VOID
NTAPI
KeUpdateSystemTime(IN PKTRAP_FRAME TrapFrame,
IN ULONG Increment,
IN KIRQL Irql)
#endif
{
PKPRCB Prcb = KeGetCurrentPrcb();
ULARGE_INTEGER CurrentTime, InterruptTime;
ULONG Hand, OldTickCount;
/* Add the increment time to the shared data */
InterruptTime.HighPart = SharedUserData->InterruptTime.High1Time;
InterruptTime.LowPart = SharedUserData->InterruptTime.LowPart;
InterruptTime.QuadPart += Increment;
SharedUserData->InterruptTime.High1Time = InterruptTime.HighPart;
SharedUserData->InterruptTime.LowPart = InterruptTime.LowPart;
SharedUserData->InterruptTime.High2Time = InterruptTime.HighPart;
/* Update tick count */
InterlockedExchangeAdd(&KiTickOffset, -(LONG)Increment);
/* Check for incomplete tick */
OldTickCount = KeTickCount.LowPart;
if (KiTickOffset <= 0)
{
/* Update the system time */
CurrentTime.HighPart = SharedUserData->SystemTime.High1Time;
CurrentTime.LowPart = SharedUserData->SystemTime.LowPart;
CurrentTime.QuadPart += KeTimeAdjustment;
SharedUserData->SystemTime.High2Time = CurrentTime.HighPart;
SharedUserData->SystemTime.LowPart = CurrentTime.LowPart;
SharedUserData->SystemTime.High1Time = CurrentTime.HighPart;
/* Update the tick count */
CurrentTime.HighPart = KeTickCount.High1Time;
CurrentTime.LowPart = OldTickCount;
CurrentTime.QuadPart += 1;
KeTickCount.High2Time = CurrentTime.HighPart;
KeTickCount.LowPart = CurrentTime.LowPart;
KeTickCount.High1Time = CurrentTime.HighPart;
/* Update it in the shared user data */
SharedUserData->TickCount.High2Time = CurrentTime.HighPart;
SharedUserData->TickCount.LowPart = CurrentTime.LowPart;
SharedUserData->TickCount.High1Time = CurrentTime.HighPart;
/* Check for timer expiration */
Hand = OldTickCount & (TIMER_TABLE_SIZE - 1);
if (KiTimerTableListHead[Hand].Time.QuadPart <= InterruptTime.QuadPart)
{
/* Check if we are already doing expiration */
if (!Prcb->TimerRequest)
{
/* Request a DPC to handle this */
Prcb->TimerRequest = (ULONG_PTR)TrapFrame;
Prcb->TimerHand = Hand;
HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
}
}
/* Check for expiration with the new tick count as well */
OldTickCount++;
}
/* Check for timer expiration */
Hand = OldTickCount & (TIMER_TABLE_SIZE - 1);
if (KiTimerTableListHead[Hand].Time.QuadPart <= InterruptTime.QuadPart)
{
/* Check if we are already doing expiration */
if (!Prcb->TimerRequest)
{
/* Request a DPC to handle this */
Prcb->TimerRequest = (ULONG_PTR)TrapFrame;
Prcb->TimerHand = Hand;
HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
}
}
/* Check if this was a full tick */
if (KiTickOffset <= 0)
{
/* Update the tick offset */
KiTickOffset += KeMaximumIncrement;
/* Update system runtime */
KeUpdateRunTime(TrapFrame, Irql);
}
else
{
/* Increase interrupt count and exit */
Prcb->InterruptCount++;
}
}
VOID
NTAPI
KeUpdateRunTime(IN PKTRAP_FRAME TrapFrame,
IN KIRQL Irql)
{
PKTHREAD Thread = KeGetCurrentThread();
PKPRCB Prcb = KeGetCurrentPrcb();
/* Increase interrupt count */
Prcb->InterruptCount++;
/* Check if we came from user mode */
#ifndef _M_ARM
if ((TrapFrame->SegCs & MODE_MASK) || (TrapFrame->EFlags & EFLAGS_V86_MASK))
#else
if (TrapFrame->PreviousMode == UserMode)
#endif
{
/* Increase thread user time */
Prcb->UserTime++;
Thread->UserTime++;
}
else
{
/* See if we were in an ISR */
Prcb->KernelTime++;
if (Irql > DISPATCH_LEVEL)
{
/* Handle that */
Prcb->InterruptTime++;
}
else if ((Irql < DISPATCH_LEVEL) || !(Prcb->DpcRoutineActive))
{
/* Handle being in kernel mode */
Thread->KernelTime++;
}
else
{
/* Handle being in a DPC */
Prcb->DpcTime++;
}
}
/* Update DPC rates */
Prcb->DpcRequestRate = ((Prcb->DpcData[0].DpcCount - Prcb->DpcLastCount) +
Prcb->DpcRequestRate) >> 1;
Prcb->DpcLastCount = Prcb->DpcData[0].DpcCount;
/* Check if the queue is large enough */
if ((Prcb->DpcData[0].DpcQueueDepth) && !(Prcb->DpcRoutineActive))
{
/* Request a DPC */
Prcb->AdjustDpcThreshold = KiAdjustDpcThreshold;
HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
/* Fix the maximum queue depth */
if ((Prcb->DpcRequestRate < KiIdealDpcRate) &&
(Prcb->MaximumDpcQueueDepth > 1))
{
/* Make it smaller */
Prcb->MaximumDpcQueueDepth--;
}
}
else
{
/* Check if we've reached the adjustment limit */
if (!(--Prcb->AdjustDpcThreshold))
{
/* Reset it, and check the queue maximum */
Prcb->AdjustDpcThreshold = KiAdjustDpcThreshold;
if (KiMaximumDpcQueueDepth != Prcb->MaximumDpcQueueDepth)
{
/* Increase it */
Prcb->MaximumDpcQueueDepth++;
}
}
}
/* Decrement the thread quantum */
Thread->Quantum -= CLOCK_QUANTUM_DECREMENT;
/* Check if the time expired */
if ((Thread->Quantum <= 0) && (Thread != Prcb->IdleThread))
{
/* Schedule a quantum end */
Prcb->QuantumEnd = 1;
HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
}
}

View file

@ -48,7 +48,6 @@
<file>ldt.c</file>
<file>mtrr.c</file>
<file>patpge.c</file>
<file>systimer.S</file>
<file>thrdini.c</file>
<file>trap.s</file>
<file>traphdlr.c</file>
@ -66,7 +65,6 @@
<file>kiinit.c</file>
<file>stubs_asm.s</file>
<file>thrdini.c</file>
<file>time.c</file>
<file>trap.s</file>
<file>trapc.c</file>
<file>usercall.c</file>
@ -107,6 +105,7 @@
<file>queue.c</file>
<file>semphobj.c</file>
<file>spinlock.c</file>
<file>time.c</file>
<file>thrdschd.c</file>
<file>thrdobj.c</file>
<file>timerobj.c</file>