1677ae4ae1819959f0cae5337ee63f1996adc790
[reactos.git] / reactos / ntoskrnl / ke / time.c
1 /*
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
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* GLOBALS ********************************************************************/
16
17 LONG KiTickOffset;
18 ULONG KeTimeAdjustment;
19
20 /* FUNCTIONS ******************************************************************/
21
22 VOID
23 FASTCALL
24 KeUpdateSystemTime(IN PKTRAP_FRAME TrapFrame,
25 IN ULONG Increment,
26 IN KIRQL Irql)
27 {
28 PKPRCB Prcb = KeGetCurrentPrcb();
29 ULARGE_INTEGER CurrentTime, InterruptTime;
30 ULONG Hand, OldTickCount;
31
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;
39
40 /* Update tick count */
41 InterlockedExchangeAdd(&KiTickOffset, -(LONG)Increment);
42
43 /* Check for incomplete tick */
44 OldTickCount = KeTickCount.LowPart;
45 if (KiTickOffset <= 0)
46 {
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;
54
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;
62
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;
67
68 /* Check for timer expiration */
69 Hand = OldTickCount & (TIMER_TABLE_SIZE - 1);
70 if (KiTimerTableListHead[Hand].Time.QuadPart <= InterruptTime.QuadPart)
71 {
72 /* Check if we are already doing expiration */
73 if (!Prcb->TimerRequest)
74 {
75 /* Request a DPC to handle this */
76 Prcb->TimerRequest = (ULONG_PTR)TrapFrame;
77 Prcb->TimerHand = Hand;
78 HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
79 }
80 }
81
82 /* Check for expiration with the new tick count as well */
83 OldTickCount++;
84 }
85
86 /* Check for timer expiration */
87 Hand = OldTickCount & (TIMER_TABLE_SIZE - 1);
88 if (KiTimerTableListHead[Hand].Time.QuadPart <= InterruptTime.QuadPart)
89 {
90 /* Check if we are already doing expiration */
91 if (!Prcb->TimerRequest)
92 {
93 /* Request a DPC to handle this */
94 Prcb->TimerRequest = (ULONG_PTR)TrapFrame;
95 Prcb->TimerHand = Hand;
96 HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
97 }
98 }
99
100 /* Check if this was a full tick */
101 if (KiTickOffset <= 0)
102 {
103 /* Update the tick offset */
104 KiTickOffset += KeMaximumIncrement;
105
106 /* Update system runtime */
107 KeUpdateRunTime(TrapFrame, Irql);
108 }
109 else
110 {
111 /* Increase interrupt count and exit */
112 Prcb->InterruptCount++;
113 }
114
115 /* Save the nested trap frame address */
116 KeGetPcr()->VdmAlert = (ULONG_PTR)TrapFrame;
117
118 /* Disable interrupts and end the interrupt */
119 _disable();
120 HalEndSystemInterrupt(Irql, PRIMARY_VECTOR_BASE + 0);
121
122 /* Exit the interrupt */
123 KiEoiHelper(TrapFrame);
124 }
125
126 VOID
127 NTAPI
128 KeUpdateRunTime(IN PKTRAP_FRAME TrapFrame,
129 IN KIRQL Irql)
130 {
131 PKTHREAD Thread = KeGetCurrentThread();
132 PKPRCB Prcb = KeGetCurrentPrcb();
133
134 /* Increase interrupt count */
135 Prcb->InterruptCount++;
136
137 /* Check if we came from user mode */
138 #ifndef _M_ARM
139 if ((TrapFrame->SegCs & MODE_MASK) || (TrapFrame->EFlags & EFLAGS_V86_MASK))
140 #else
141 if (TrapFrame->PreviousMode == UserMode)
142 #endif
143 {
144 /* Increase thread user time */
145 Prcb->UserTime++;
146 Thread->UserTime++;
147 }
148 else
149 {
150 /* See if we were in an ISR */
151 Prcb->KernelTime++;
152 if (Irql > DISPATCH_LEVEL)
153 {
154 /* Handle that */
155 Prcb->InterruptTime++;
156 }
157 else if ((Irql < DISPATCH_LEVEL) || !(Prcb->DpcRoutineActive))
158 {
159 /* Handle being in kernel mode */
160 Thread->KernelTime++;
161 }
162 else
163 {
164 /* Handle being in a DPC */
165 Prcb->DpcTime++;
166 }
167 }
168
169 /* Update DPC rates */
170 Prcb->DpcRequestRate = ((Prcb->DpcData[0].DpcCount - Prcb->DpcLastCount) +
171 Prcb->DpcRequestRate) >> 1;
172 Prcb->DpcLastCount = Prcb->DpcData[0].DpcCount;
173
174 /* Check if the queue is large enough */
175 if ((Prcb->DpcData[0].DpcQueueDepth) && !(Prcb->DpcRoutineActive))
176 {
177 /* Request a DPC */
178 Prcb->AdjustDpcThreshold = KiAdjustDpcThreshold;
179 HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
180
181 /* Fix the maximum queue depth */
182 if ((Prcb->DpcRequestRate < KiIdealDpcRate) &&
183 (Prcb->MaximumDpcQueueDepth > 1))
184 {
185 /* Make it smaller */
186 Prcb->MaximumDpcQueueDepth--;
187 }
188 }
189 else
190 {
191 /* Check if we've reached the adjustment limit */
192 if (!(--Prcb->AdjustDpcThreshold))
193 {
194 /* Reset it, and check the queue maximum */
195 Prcb->AdjustDpcThreshold = KiAdjustDpcThreshold;
196 if (KiMaximumDpcQueueDepth != Prcb->MaximumDpcQueueDepth)
197 {
198 /* Increase it */
199 Prcb->MaximumDpcQueueDepth++;
200 }
201 }
202 }
203
204 /* Decrement the thread quantum */
205 Thread->Quantum -= CLOCK_QUANTUM_DECREMENT;
206
207 /* Check if the time expired */
208 if ((Thread->Quantum <= 0) && (Thread != Prcb->IdleThread))
209 {
210 /* Schedule a quantum end */
211 Prcb->QuantumEnd = 1;
212 HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
213 }
214 }