2 * PROJECT: ReactOS Kernel
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: ntoskrnl/ke/time.c
5 * PURPOSE: Implements timebase functionality
6 * PROGRAMMERS: ReactOS Portable Systems Group
9 /* INCLUDES *******************************************************************/
15 /* GLOBALS ********************************************************************/
18 ULONG KeTimeAdjustment
;
20 /* FUNCTIONS ******************************************************************/
24 KeUpdateSystemTime(IN PKTRAP_FRAME TrapFrame
,
28 PKPRCB Prcb
= KeGetCurrentPrcb();
29 ULARGE_INTEGER CurrentTime
, InterruptTime
;
30 ULONG Hand
, OldTickCount
;
32 /* Add the increment time to the shared data */
33 InterruptTime
.HighPart
= SharedUserData
->InterruptTime
.High1Time
;
34 InterruptTime
.LowPart
= SharedUserData
->InterruptTime
.LowPart
;
35 InterruptTime
.QuadPart
+= Increment
;
36 SharedUserData
->InterruptTime
.High1Time
= InterruptTime
.HighPart
;
37 SharedUserData
->InterruptTime
.LowPart
= InterruptTime
.LowPart
;
38 SharedUserData
->InterruptTime
.High2Time
= InterruptTime
.HighPart
;
40 /* Update tick count */
41 InterlockedExchangeAdd(&KiTickOffset
, -(LONG
)Increment
);
43 /* Check for incomplete tick */
44 OldTickCount
= KeTickCount
.LowPart
;
45 if (KiTickOffset
<= 0)
47 /* Update the system time */
48 CurrentTime
.HighPart
= SharedUserData
->SystemTime
.High1Time
;
49 CurrentTime
.LowPart
= SharedUserData
->SystemTime
.LowPart
;
50 CurrentTime
.QuadPart
+= KeTimeAdjustment
;
51 SharedUserData
->SystemTime
.High2Time
= CurrentTime
.HighPart
;
52 SharedUserData
->SystemTime
.LowPart
= CurrentTime
.LowPart
;
53 SharedUserData
->SystemTime
.High1Time
= CurrentTime
.HighPart
;
55 /* Update the tick count */
56 CurrentTime
.HighPart
= KeTickCount
.High1Time
;
57 CurrentTime
.LowPart
= OldTickCount
;
58 CurrentTime
.QuadPart
+= 1;
59 KeTickCount
.High2Time
= CurrentTime
.HighPart
;
60 KeTickCount
.LowPart
= CurrentTime
.LowPart
;
61 KeTickCount
.High1Time
= CurrentTime
.HighPart
;
63 /* Update it in the shared user data */
64 SharedUserData
->TickCount
.High2Time
= CurrentTime
.HighPart
;
65 SharedUserData
->TickCount
.LowPart
= CurrentTime
.LowPart
;
66 SharedUserData
->TickCount
.High1Time
= CurrentTime
.HighPart
;
68 /* Check for timer expiration */
69 Hand
= OldTickCount
& (TIMER_TABLE_SIZE
- 1);
70 if (KiTimerTableListHead
[Hand
].Time
.QuadPart
<= InterruptTime
.QuadPart
)
72 /* Check if we are already doing expiration */
73 if (!Prcb
->TimerRequest
)
75 /* Request a DPC to handle this */
76 Prcb
->TimerRequest
= (ULONG_PTR
)TrapFrame
;
77 Prcb
->TimerHand
= Hand
;
78 HalRequestSoftwareInterrupt(DISPATCH_LEVEL
);
82 /* Check for expiration with the new tick count as well */
86 /* Check for timer expiration */
87 Hand
= OldTickCount
& (TIMER_TABLE_SIZE
- 1);
88 if (KiTimerTableListHead
[Hand
].Time
.QuadPart
<= InterruptTime
.QuadPart
)
90 /* Check if we are already doing expiration */
91 if (!Prcb
->TimerRequest
)
93 /* Request a DPC to handle this */
94 Prcb
->TimerRequest
= (ULONG_PTR
)TrapFrame
;
95 Prcb
->TimerHand
= Hand
;
96 HalRequestSoftwareInterrupt(DISPATCH_LEVEL
);
100 /* Check if this was a full tick */
101 if (KiTickOffset
<= 0)
103 /* Update the tick offset */
104 KiTickOffset
+= KeMaximumIncrement
;
106 /* Update system runtime */
107 KeUpdateRunTime(TrapFrame
, Irql
);
111 /* Increase interrupt count and exit */
112 Prcb
->InterruptCount
++;
115 /* Save the nested trap frame address */
116 KeGetPcr()->VdmAlert
= (ULONG_PTR
)TrapFrame
;
118 /* Disable interrupts and end the interrupt */
120 HalEndSystemInterrupt(Irql
, PRIMARY_VECTOR_BASE
+ 0);
122 /* Exit the interrupt */
123 KiEoiHelper(TrapFrame
);
128 KeUpdateRunTime(IN PKTRAP_FRAME TrapFrame
,
131 PKTHREAD Thread
= KeGetCurrentThread();
132 PKPRCB Prcb
= KeGetCurrentPrcb();
134 /* Increase interrupt count */
135 Prcb
->InterruptCount
++;
137 /* Check if we came from user mode */
139 if ((TrapFrame
->SegCs
& MODE_MASK
) || (TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
141 if (TrapFrame
->PreviousMode
== UserMode
)
144 /* Increase thread user time */
150 /* See if we were in an ISR */
152 if (Irql
> DISPATCH_LEVEL
)
155 Prcb
->InterruptTime
++;
157 else if ((Irql
< DISPATCH_LEVEL
) || !(Prcb
->DpcRoutineActive
))
159 /* Handle being in kernel mode */
160 Thread
->KernelTime
++;
164 /* Handle being in a DPC */
169 /* Update DPC rates */
170 Prcb
->DpcRequestRate
= ((Prcb
->DpcData
[0].DpcCount
- Prcb
->DpcLastCount
) +
171 Prcb
->DpcRequestRate
) >> 1;
172 Prcb
->DpcLastCount
= Prcb
->DpcData
[0].DpcCount
;
174 /* Check if the queue is large enough */
175 if ((Prcb
->DpcData
[0].DpcQueueDepth
) && !(Prcb
->DpcRoutineActive
))
178 Prcb
->AdjustDpcThreshold
= KiAdjustDpcThreshold
;
179 HalRequestSoftwareInterrupt(DISPATCH_LEVEL
);
181 /* Fix the maximum queue depth */
182 if ((Prcb
->DpcRequestRate
< KiIdealDpcRate
) &&
183 (Prcb
->MaximumDpcQueueDepth
> 1))
185 /* Make it smaller */
186 Prcb
->MaximumDpcQueueDepth
--;
191 /* Check if we've reached the adjustment limit */
192 if (!(--Prcb
->AdjustDpcThreshold
))
194 /* Reset it, and check the queue maximum */
195 Prcb
->AdjustDpcThreshold
= KiAdjustDpcThreshold
;
196 if (KiMaximumDpcQueueDepth
!= Prcb
->MaximumDpcQueueDepth
)
199 Prcb
->MaximumDpcQueueDepth
++;
204 /* Decrement the thread quantum */
205 Thread
->Quantum
-= CLOCK_QUANTUM_DECREMENT
;
207 /* Check if the time expired */
208 if ((Thread
->Quantum
<= 0) && (Thread
!= Prcb
->IdleThread
))
210 /* Schedule a quantum end */
211 Prcb
->QuantumEnd
= 1;
212 HalRequestSoftwareInterrupt(DISPATCH_LEVEL
);