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 KiWriteSystemTime(volatile KSYSTEM_TIME
*SystemTime
, ULARGE_INTEGER NewTime
)
28 /* Do a single atomic write */
29 *(ULONGLONG
*)SystemTime
= NewTime
.QuadPart
;
31 /* Update in 3 steps, so that a reader can recognize partial updates */
32 SystemTime
->High1Time
= NewTime
.HighPart
;
33 SystemTime
->LowPart
= NewTime
.LowPart
;
34 SystemTime
->High2Time
= NewTime
.HighPart
;
40 KiCheckForTimerExpiration(
42 PKTRAP_FRAME TrapFrame
,
43 ULARGE_INTEGER InterruptTime
)
47 /* Check for timer expiration */
48 Hand
= KeTickCount
.LowPart
& (TIMER_TABLE_SIZE
- 1);
49 if (KiTimerTableListHead
[Hand
].Time
.QuadPart
<= InterruptTime
.QuadPart
)
51 /* Check if we are already doing expiration */
52 if (!Prcb
->TimerRequest
)
54 /* Request a DPC to handle this */
55 Prcb
->TimerRequest
= (ULONG_PTR
)TrapFrame
;
56 Prcb
->TimerHand
= Hand
;
57 HalRequestSoftwareInterrupt(DISPATCH_LEVEL
);
64 KeUpdateSystemTime(IN PKTRAP_FRAME TrapFrame
,
68 PKPRCB Prcb
= KeGetCurrentPrcb();
69 ULARGE_INTEGER CurrentTime
, InterruptTime
;
72 /* Check if this tick is being skipped */
75 /* Handle it next time */
76 Prcb
->SkipTick
= FALSE
;
78 /* Increase interrupt count and end the interrupt */
79 Prcb
->InterruptCount
++;
80 KiEndInterrupt(Irql
, TrapFrame
);
83 /* Add the increment time to the shared data */
84 InterruptTime
.QuadPart
= *(ULONGLONG
*)&SharedUserData
->InterruptTime
;
85 InterruptTime
.QuadPart
+= Increment
;
86 KiWriteSystemTime(&SharedUserData
->InterruptTime
, InterruptTime
);
88 /* Check for timer expiration */
89 KiCheckForTimerExpiration(Prcb
, TrapFrame
, InterruptTime
);
91 /* Update the tick offset */
92 OldTickOffset
= InterlockedExchangeAdd(&KiTickOffset
, -(LONG
)Increment
);
94 /* If the debugger is enabled, check for break-in request */
95 if (KdDebuggerEnabled
&& KdPollBreakIn())
97 /* Break-in requested! */
98 DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C
);
101 /* Check for full tick */
102 if (OldTickOffset
<= (LONG
)Increment
)
104 /* Update the system time */
105 CurrentTime
.QuadPart
= *(ULONGLONG
*)&SharedUserData
->SystemTime
;
106 CurrentTime
.QuadPart
+= KeTimeAdjustment
;
107 KiWriteSystemTime(&SharedUserData
->SystemTime
, CurrentTime
);
109 /* Update the tick count */
110 CurrentTime
.QuadPart
= (*(ULONGLONG
*)&KeTickCount
) + 1;
111 KiWriteSystemTime(&KeTickCount
, CurrentTime
);
113 /* Update it in the shared user data */
114 KiWriteSystemTime(&SharedUserData
->TickCount
, CurrentTime
);
116 /* Check for expiration with the new tick count as well */
117 KiCheckForTimerExpiration(Prcb
, TrapFrame
, InterruptTime
);
119 /* Reset the tick offset */
120 KiTickOffset
+= KeMaximumIncrement
;
122 /* Update processor/thread runtime */
123 KeUpdateRunTime(TrapFrame
, Irql
);
127 /* Increase interrupt count only */
128 Prcb
->InterruptCount
++;
131 /* Disable interrupts and end the interrupt */
132 KiEndInterrupt(Irql
, TrapFrame
);
137 KeUpdateRunTime(IN PKTRAP_FRAME TrapFrame
,
140 PKTHREAD Thread
= KeGetCurrentThread();
141 PKPRCB Prcb
= KeGetCurrentPrcb();
143 /* Check if this tick is being skipped */
146 /* Handle it next time */
147 Prcb
->SkipTick
= FALSE
;
151 /* Increase interrupt count */
152 Prcb
->InterruptCount
++;
154 /* Check if we came from user mode */
156 if ((TrapFrame
->SegCs
& MODE_MASK
) || (TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
158 if (TrapFrame
->PreviousMode
== UserMode
)
161 /* Increase thread user time */
167 /* See if we were in an ISR */
169 if (Irql
> DISPATCH_LEVEL
)
172 Prcb
->InterruptTime
++;
174 else if ((Irql
< DISPATCH_LEVEL
) || !(Prcb
->DpcRoutineActive
))
176 /* Handle being in kernel mode */
177 Thread
->KernelTime
++;
181 /* Handle being in a DPC */
185 /* Update the DPC time */
186 Prcb
->DebugDpcTime
++;
188 /* Check if we have timed out */
189 if (Prcb
->DebugDpcTime
== KiDPCTimeout
);
192 DbgPrint("*** DPC routine > 1 sec --- This is not a break in KeUpdateSystemTime\n");
194 /* Break if debugger is enabled */
195 if (KdDebuggerEnabled
) DbgBreakPoint();
198 Prcb
->DebugDpcTime
= 0;
204 /* Update DPC rates */
205 Prcb
->DpcRequestRate
= ((Prcb
->DpcData
[0].DpcCount
- Prcb
->DpcLastCount
) +
206 Prcb
->DpcRequestRate
) >> 1;
207 Prcb
->DpcLastCount
= Prcb
->DpcData
[0].DpcCount
;
209 /* Check if the queue is large enough */
210 if ((Prcb
->DpcData
[0].DpcQueueDepth
) && !(Prcb
->DpcRoutineActive
))
213 Prcb
->AdjustDpcThreshold
= KiAdjustDpcThreshold
;
214 HalRequestSoftwareInterrupt(DISPATCH_LEVEL
);
216 /* Fix the maximum queue depth */
217 if ((Prcb
->DpcRequestRate
< KiIdealDpcRate
) &&
218 (Prcb
->MaximumDpcQueueDepth
> 1))
220 /* Make it smaller */
221 Prcb
->MaximumDpcQueueDepth
--;
226 /* Check if we've reached the adjustment limit */
227 if (!(--Prcb
->AdjustDpcThreshold
))
229 /* Reset it, and check the queue maximum */
230 Prcb
->AdjustDpcThreshold
= KiAdjustDpcThreshold
;
231 if (KiMaximumDpcQueueDepth
!= Prcb
->MaximumDpcQueueDepth
)
234 Prcb
->MaximumDpcQueueDepth
++;
239 /* Decrement the thread quantum */
240 Thread
->Quantum
-= CLOCK_QUANTUM_DECREMENT
;
242 /* Check if the time expired */
243 if ((Thread
->Quantum
<= 0) && (Thread
!= Prcb
->IdleThread
))
245 /* Schedule a quantum end */
246 Prcb
->QuantumEnd
= 1;
247 HalRequestSoftwareInterrupt(DISPATCH_LEVEL
);