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 /* Disable interrupts and end the interrupt */
117 HalEndSystemInterrupt(Irql
, TrapFrame
);
119 /* Exit the interrupt */
120 KiEoiHelper(TrapFrame
);
125 KeUpdateRunTime(IN PKTRAP_FRAME TrapFrame
,
128 PKTHREAD Thread
= KeGetCurrentThread();
129 PKPRCB Prcb
= KeGetCurrentPrcb();
131 /* Increase interrupt count */
132 Prcb
->InterruptCount
++;
134 /* Check if we came from user mode */
136 if ((TrapFrame
->SegCs
& MODE_MASK
) || (TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
138 if (TrapFrame
->PreviousMode
== UserMode
)
141 /* Increase thread user time */
147 /* See if we were in an ISR */
149 if (Irql
> DISPATCH_LEVEL
)
152 Prcb
->InterruptTime
++;
154 else if ((Irql
< DISPATCH_LEVEL
) || !(Prcb
->DpcRoutineActive
))
156 /* Handle being in kernel mode */
157 Thread
->KernelTime
++;
161 /* Handle being in a DPC */
166 /* Update DPC rates */
167 Prcb
->DpcRequestRate
= ((Prcb
->DpcData
[0].DpcCount
- Prcb
->DpcLastCount
) +
168 Prcb
->DpcRequestRate
) >> 1;
169 Prcb
->DpcLastCount
= Prcb
->DpcData
[0].DpcCount
;
171 /* Check if the queue is large enough */
172 if ((Prcb
->DpcData
[0].DpcQueueDepth
) && !(Prcb
->DpcRoutineActive
))
175 Prcb
->AdjustDpcThreshold
= KiAdjustDpcThreshold
;
176 HalRequestSoftwareInterrupt(DISPATCH_LEVEL
);
178 /* Fix the maximum queue depth */
179 if ((Prcb
->DpcRequestRate
< KiIdealDpcRate
) &&
180 (Prcb
->MaximumDpcQueueDepth
> 1))
182 /* Make it smaller */
183 Prcb
->MaximumDpcQueueDepth
--;
188 /* Check if we've reached the adjustment limit */
189 if (!(--Prcb
->AdjustDpcThreshold
))
191 /* Reset it, and check the queue maximum */
192 Prcb
->AdjustDpcThreshold
= KiAdjustDpcThreshold
;
193 if (KiMaximumDpcQueueDepth
!= Prcb
->MaximumDpcQueueDepth
)
196 Prcb
->MaximumDpcQueueDepth
++;
201 /* Decrement the thread quantum */
202 Thread
->Quantum
-= CLOCK_QUANTUM_DECREMENT
;
204 /* Check if the time expired */
205 if ((Thread
->Quantum
<= 0) && (Thread
!= Prcb
->IdleThread
))
207 /* Schedule a quantum end */
208 Prcb
->QuantumEnd
= 1;
209 HalRequestSoftwareInterrupt(DISPATCH_LEVEL
);