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
;
19 BOOLEAN KiTimeAdjustmentEnabled
= FALSE
;
21 /* FUNCTIONS ******************************************************************/
25 KeUpdateSystemTime(IN PKTRAP_FRAME TrapFrame
,
29 PKPRCB Prcb
= KeGetCurrentPrcb();
30 ULARGE_INTEGER CurrentTime
, InterruptTime
;
31 ULONG Hand
, OldTickCount
;
33 /* Add the increment time to the shared data */
34 InterruptTime
.HighPart
= SharedUserData
->InterruptTime
.High1Time
;
35 InterruptTime
.LowPart
= SharedUserData
->InterruptTime
.LowPart
;
36 InterruptTime
.QuadPart
+= Increment
;
37 SharedUserData
->InterruptTime
.High1Time
= InterruptTime
.HighPart
;
38 SharedUserData
->InterruptTime
.LowPart
= InterruptTime
.LowPart
;
39 SharedUserData
->InterruptTime
.High2Time
= InterruptTime
.HighPart
;
41 /* Update tick count */
42 InterlockedExchangeAdd(&KiTickOffset
, -(LONG
)Increment
);
44 /* Check for incomplete tick */
45 OldTickCount
= KeTickCount
.LowPart
;
46 if (KiTickOffset
<= 0)
48 /* Update the system time */
49 CurrentTime
.HighPart
= SharedUserData
->SystemTime
.High1Time
;
50 CurrentTime
.LowPart
= SharedUserData
->SystemTime
.LowPart
;
51 CurrentTime
.QuadPart
+= KeTimeAdjustment
;
52 SharedUserData
->SystemTime
.High2Time
= CurrentTime
.HighPart
;
53 SharedUserData
->SystemTime
.LowPart
= CurrentTime
.LowPart
;
54 SharedUserData
->SystemTime
.High1Time
= CurrentTime
.HighPart
;
56 /* Update the tick count */
57 CurrentTime
.HighPart
= KeTickCount
.High1Time
;
58 CurrentTime
.LowPart
= OldTickCount
;
59 CurrentTime
.QuadPart
+= 1;
60 KeTickCount
.High2Time
= CurrentTime
.HighPart
;
61 KeTickCount
.LowPart
= CurrentTime
.LowPart
;
62 KeTickCount
.High1Time
= CurrentTime
.HighPart
;
64 /* Update it in the shared user data */
65 SharedUserData
->TickCount
.High2Time
= CurrentTime
.HighPart
;
66 SharedUserData
->TickCount
.LowPart
= CurrentTime
.LowPart
;
67 SharedUserData
->TickCount
.High1Time
= CurrentTime
.HighPart
;
69 /* Check for timer expiration */
70 Hand
= OldTickCount
& (TIMER_TABLE_SIZE
- 1);
71 if (KiTimerTableListHead
[Hand
].Time
.QuadPart
<= InterruptTime
.QuadPart
)
73 /* Check if we are already doing expiration */
74 if (!Prcb
->TimerRequest
)
76 /* Request a DPC to handle this */
77 Prcb
->TimerRequest
= (ULONG_PTR
)TrapFrame
;
78 Prcb
->TimerHand
= Hand
;
79 HalRequestSoftwareInterrupt(DISPATCH_LEVEL
);
83 /* Check for expiration with the new tick count as well */
87 /* Check for timer expiration */
88 Hand
= OldTickCount
& (TIMER_TABLE_SIZE
- 1);
89 if (KiTimerTableListHead
[Hand
].Time
.QuadPart
<= InterruptTime
.QuadPart
)
91 /* Check if we are already doing expiration */
92 if (!Prcb
->TimerRequest
)
94 /* Request a DPC to handle this */
95 Prcb
->TimerRequest
= (ULONG_PTR
)TrapFrame
;
96 Prcb
->TimerHand
= Hand
;
97 HalRequestSoftwareInterrupt(DISPATCH_LEVEL
);
101 /* Check if this was a full tick */
102 if (KiTickOffset
<= 0)
104 /* Update the tick offset */
105 KiTickOffset
+= KeMaximumIncrement
;
107 /* Update system runtime */
108 KeUpdateRunTime(TrapFrame
, Irql
);
112 /* Increase interrupt count and exit */
113 Prcb
->InterruptCount
++;
116 /* Disable interrupts and end the interrupt */
117 KiEndInterrupt(Irql
, TrapFrame
);
122 KeUpdateRunTime(IN PKTRAP_FRAME TrapFrame
,
125 PKTHREAD Thread
= KeGetCurrentThread();
126 PKPRCB Prcb
= KeGetCurrentPrcb();
128 /* Increase interrupt count */
129 Prcb
->InterruptCount
++;
131 /* Check if we came from user mode */
133 if ((TrapFrame
->SegCs
& MODE_MASK
) || (TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
135 if (TrapFrame
->PreviousMode
== UserMode
)
138 /* Increase thread user time */
144 /* See if we were in an ISR */
146 if (Irql
> DISPATCH_LEVEL
)
149 Prcb
->InterruptTime
++;
151 else if ((Irql
< DISPATCH_LEVEL
) || !(Prcb
->DpcRoutineActive
))
153 /* Handle being in kernel mode */
154 Thread
->KernelTime
++;
158 /* Handle being in a DPC */
163 /* Update DPC rates */
164 Prcb
->DpcRequestRate
= ((Prcb
->DpcData
[0].DpcCount
- Prcb
->DpcLastCount
) +
165 Prcb
->DpcRequestRate
) >> 1;
166 Prcb
->DpcLastCount
= Prcb
->DpcData
[0].DpcCount
;
168 /* Check if the queue is large enough */
169 if ((Prcb
->DpcData
[0].DpcQueueDepth
) && !(Prcb
->DpcRoutineActive
))
172 Prcb
->AdjustDpcThreshold
= KiAdjustDpcThreshold
;
173 HalRequestSoftwareInterrupt(DISPATCH_LEVEL
);
175 /* Fix the maximum queue depth */
176 if ((Prcb
->DpcRequestRate
< KiIdealDpcRate
) &&
177 (Prcb
->MaximumDpcQueueDepth
> 1))
179 /* Make it smaller */
180 Prcb
->MaximumDpcQueueDepth
--;
185 /* Check if we've reached the adjustment limit */
186 if (!(--Prcb
->AdjustDpcThreshold
))
188 /* Reset it, and check the queue maximum */
189 Prcb
->AdjustDpcThreshold
= KiAdjustDpcThreshold
;
190 if (KiMaximumDpcQueueDepth
!= Prcb
->MaximumDpcQueueDepth
)
193 Prcb
->MaximumDpcQueueDepth
++;
198 /* Decrement the thread quantum */
199 Thread
->Quantum
-= CLOCK_QUANTUM_DECREMENT
;
201 /* Check if the time expired */
202 if ((Thread
->Quantum
<= 0) && (Thread
!= Prcb
->IdleThread
))
204 /* Schedule a quantum end */
205 Prcb
->QuantumEnd
= 1;
206 HalRequestSoftwareInterrupt(DISPATCH_LEVEL
);