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 __attribute__((regparm(3)))
25 KeUpdateSystemTimeHandler(IN ULONG Increment
,
27 IN PKTRAP_FRAME TrapFrame
)
31 KeUpdateSystemTime(IN PKTRAP_FRAME TrapFrame
,
36 PKPRCB Prcb
= KeGetCurrentPrcb();
37 ULARGE_INTEGER CurrentTime
, InterruptTime
;
38 ULONG Hand
, OldTickCount
;
40 /* Add the increment time to the shared data */
41 InterruptTime
.HighPart
= SharedUserData
->InterruptTime
.High1Time
;
42 InterruptTime
.LowPart
= SharedUserData
->InterruptTime
.LowPart
;
43 InterruptTime
.QuadPart
+= Increment
;
44 SharedUserData
->InterruptTime
.High1Time
= InterruptTime
.HighPart
;
45 SharedUserData
->InterruptTime
.LowPart
= InterruptTime
.LowPart
;
46 SharedUserData
->InterruptTime
.High2Time
= InterruptTime
.HighPart
;
48 /* Update tick count */
49 InterlockedExchangeAdd(&KiTickOffset
, -(LONG
)Increment
);
51 /* Check for incomplete tick */
52 OldTickCount
= KeTickCount
.LowPart
;
53 if (KiTickOffset
<= 0)
55 /* Update the system time */
56 CurrentTime
.HighPart
= SharedUserData
->SystemTime
.High1Time
;
57 CurrentTime
.LowPart
= SharedUserData
->SystemTime
.LowPart
;
58 CurrentTime
.QuadPart
+= KeTimeAdjustment
;
59 SharedUserData
->SystemTime
.High2Time
= CurrentTime
.HighPart
;
60 SharedUserData
->SystemTime
.LowPart
= CurrentTime
.LowPart
;
61 SharedUserData
->SystemTime
.High1Time
= CurrentTime
.HighPart
;
63 /* Update the tick count */
64 CurrentTime
.HighPart
= KeTickCount
.High1Time
;
65 CurrentTime
.LowPart
= OldTickCount
;
66 CurrentTime
.QuadPart
+= 1;
67 KeTickCount
.High2Time
= CurrentTime
.HighPart
;
68 KeTickCount
.LowPart
= CurrentTime
.LowPart
;
69 KeTickCount
.High1Time
= CurrentTime
.HighPart
;
71 /* Update it in the shared user data */
72 SharedUserData
->TickCount
.High2Time
= CurrentTime
.HighPart
;
73 SharedUserData
->TickCount
.LowPart
= CurrentTime
.LowPart
;
74 SharedUserData
->TickCount
.High1Time
= CurrentTime
.HighPart
;
76 /* Check for timer expiration */
77 Hand
= OldTickCount
& (TIMER_TABLE_SIZE
- 1);
78 if (KiTimerTableListHead
[Hand
].Time
.QuadPart
<= InterruptTime
.QuadPart
)
80 /* Check if we are already doing expiration */
81 if (!Prcb
->TimerRequest
)
83 /* Request a DPC to handle this */
84 Prcb
->TimerRequest
= (ULONG_PTR
)TrapFrame
;
85 Prcb
->TimerHand
= Hand
;
86 HalRequestSoftwareInterrupt(DISPATCH_LEVEL
);
90 /* Check for expiration with the new tick count as well */
94 /* Check for timer expiration */
95 Hand
= OldTickCount
& (TIMER_TABLE_SIZE
- 1);
96 if (KiTimerTableListHead
[Hand
].Time
.QuadPart
<= InterruptTime
.QuadPart
)
98 /* Check if we are already doing expiration */
99 if (!Prcb
->TimerRequest
)
101 /* Request a DPC to handle this */
102 Prcb
->TimerRequest
= (ULONG_PTR
)TrapFrame
;
103 Prcb
->TimerHand
= Hand
;
104 HalRequestSoftwareInterrupt(DISPATCH_LEVEL
);
108 /* Check if this was a full tick */
109 if (KiTickOffset
<= 0)
111 /* Update the tick offset */
112 KiTickOffset
+= KeMaximumIncrement
;
114 /* Update system runtime */
115 KeUpdateRunTime(TrapFrame
, Irql
);
119 /* Increase interrupt count and exit */
120 Prcb
->InterruptCount
++;
126 KeUpdateRunTime(IN PKTRAP_FRAME TrapFrame
,
129 PKTHREAD Thread
= KeGetCurrentThread();
130 PKPRCB Prcb
= KeGetCurrentPrcb();
132 /* Increase interrupt count */
133 Prcb
->InterruptCount
++;
135 /* Check if we came from user mode */
137 if ((TrapFrame
->SegCs
& MODE_MASK
) || (TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
139 if (TrapFrame
->PreviousMode
== UserMode
)
142 /* Increase thread user time */
148 /* See if we were in an ISR */
150 if (Irql
> DISPATCH_LEVEL
)
153 Prcb
->InterruptTime
++;
155 else if ((Irql
< DISPATCH_LEVEL
) || !(Prcb
->DpcRoutineActive
))
157 /* Handle being in kernel mode */
158 Thread
->KernelTime
++;
162 /* Handle being in a DPC */
167 /* Update DPC rates */
168 Prcb
->DpcRequestRate
= ((Prcb
->DpcData
[0].DpcCount
- Prcb
->DpcLastCount
) +
169 Prcb
->DpcRequestRate
) >> 1;
170 Prcb
->DpcLastCount
= Prcb
->DpcData
[0].DpcCount
;
172 /* Check if the queue is large enough */
173 if ((Prcb
->DpcData
[0].DpcQueueDepth
) && !(Prcb
->DpcRoutineActive
))
176 Prcb
->AdjustDpcThreshold
= KiAdjustDpcThreshold
;
177 HalRequestSoftwareInterrupt(DISPATCH_LEVEL
);
179 /* Fix the maximum queue depth */
180 if ((Prcb
->DpcRequestRate
< KiIdealDpcRate
) &&
181 (Prcb
->MaximumDpcQueueDepth
> 1))
183 /* Make it smaller */
184 Prcb
->MaximumDpcQueueDepth
--;
189 /* Check if we've reached the adjustment limit */
190 if (!(--Prcb
->AdjustDpcThreshold
))
192 /* Reset it, and check the queue maximum */
193 Prcb
->AdjustDpcThreshold
= KiAdjustDpcThreshold
;
194 if (KiMaximumDpcQueueDepth
!= Prcb
->MaximumDpcQueueDepth
)
197 Prcb
->MaximumDpcQueueDepth
++;
202 /* Decrement the thread quantum */
203 Thread
->Quantum
-= CLOCK_QUANTUM_DECREMENT
;
205 /* Check if the time expired */
206 if ((Thread
->Quantum
<= 0) && (Thread
!= Prcb
->IdleThread
))
208 /* Schedule a quantum end */
209 Prcb
->QuantumEnd
= 1;
210 HalRequestSoftwareInterrupt(DISPATCH_LEVEL
);