[HAL]: Rewrite IRQL handling. Alex's original code (lately translated to C) was a...
[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 /* Disable interrupts and end the interrupt */
116 _disable();
117 HalEndSystemInterrupt(Irql, TrapFrame);
118
119 /* Exit the interrupt */
120 KiEoiHelper(TrapFrame);
121 }
122
123 VOID
124 NTAPI
125 KeUpdateRunTime(IN PKTRAP_FRAME TrapFrame,
126 IN KIRQL Irql)
127 {
128 PKTHREAD Thread = KeGetCurrentThread();
129 PKPRCB Prcb = KeGetCurrentPrcb();
130
131 /* Increase interrupt count */
132 Prcb->InterruptCount++;
133
134 /* Check if we came from user mode */
135 #ifndef _M_ARM
136 if ((TrapFrame->SegCs & MODE_MASK) || (TrapFrame->EFlags & EFLAGS_V86_MASK))
137 #else
138 if (TrapFrame->PreviousMode == UserMode)
139 #endif
140 {
141 /* Increase thread user time */
142 Prcb->UserTime++;
143 Thread->UserTime++;
144 }
145 else
146 {
147 /* See if we were in an ISR */
148 Prcb->KernelTime++;
149 if (Irql > DISPATCH_LEVEL)
150 {
151 /* Handle that */
152 Prcb->InterruptTime++;
153 }
154 else if ((Irql < DISPATCH_LEVEL) || !(Prcb->DpcRoutineActive))
155 {
156 /* Handle being in kernel mode */
157 Thread->KernelTime++;
158 }
159 else
160 {
161 /* Handle being in a DPC */
162 Prcb->DpcTime++;
163 }
164 }
165
166 /* Update DPC rates */
167 Prcb->DpcRequestRate = ((Prcb->DpcData[0].DpcCount - Prcb->DpcLastCount) +
168 Prcb->DpcRequestRate) >> 1;
169 Prcb->DpcLastCount = Prcb->DpcData[0].DpcCount;
170
171 /* Check if the queue is large enough */
172 if ((Prcb->DpcData[0].DpcQueueDepth) && !(Prcb->DpcRoutineActive))
173 {
174 /* Request a DPC */
175 Prcb->AdjustDpcThreshold = KiAdjustDpcThreshold;
176 HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
177
178 /* Fix the maximum queue depth */
179 if ((Prcb->DpcRequestRate < KiIdealDpcRate) &&
180 (Prcb->MaximumDpcQueueDepth > 1))
181 {
182 /* Make it smaller */
183 Prcb->MaximumDpcQueueDepth--;
184 }
185 }
186 else
187 {
188 /* Check if we've reached the adjustment limit */
189 if (!(--Prcb->AdjustDpcThreshold))
190 {
191 /* Reset it, and check the queue maximum */
192 Prcb->AdjustDpcThreshold = KiAdjustDpcThreshold;
193 if (KiMaximumDpcQueueDepth != Prcb->MaximumDpcQueueDepth)
194 {
195 /* Increase it */
196 Prcb->MaximumDpcQueueDepth++;
197 }
198 }
199 }
200
201 /* Decrement the thread quantum */
202 Thread->Quantum -= CLOCK_QUANTUM_DECREMENT;
203
204 /* Check if the time expired */
205 if ((Thread->Quantum <= 0) && (Thread != Prcb->IdleThread))
206 {
207 /* Schedule a quantum end */
208 Prcb->QuantumEnd = 1;
209 HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
210 }
211 }