[HAL]
[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 #ifdef _M_IX86
23 VOID
24 __attribute__((regparm(3)))
25 KeUpdateSystemTimeHandler(IN ULONG Increment,
26 IN KIRQL Irql,
27 IN PKTRAP_FRAME TrapFrame)
28 #else
29 VOID
30 NTAPI
31 KeUpdateSystemTime(IN PKTRAP_FRAME TrapFrame,
32 IN KIRQL Irql,
33 IN ULONG Increment)
34 #endif
35 {
36 PKPRCB Prcb = KeGetCurrentPrcb();
37 ULARGE_INTEGER CurrentTime, InterruptTime;
38 ULONG Hand, OldTickCount;
39
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;
47
48 /* Update tick count */
49 InterlockedExchangeAdd(&KiTickOffset, -(LONG)Increment);
50
51 /* Check for incomplete tick */
52 OldTickCount = KeTickCount.LowPart;
53 if (KiTickOffset <= 0)
54 {
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;
62
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;
70
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;
75
76 /* Check for timer expiration */
77 Hand = OldTickCount & (TIMER_TABLE_SIZE - 1);
78 if (KiTimerTableListHead[Hand].Time.QuadPart <= InterruptTime.QuadPart)
79 {
80 /* Check if we are already doing expiration */
81 if (!Prcb->TimerRequest)
82 {
83 /* Request a DPC to handle this */
84 Prcb->TimerRequest = (ULONG_PTR)TrapFrame;
85 Prcb->TimerHand = Hand;
86 HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
87 }
88 }
89
90 /* Check for expiration with the new tick count as well */
91 OldTickCount++;
92 }
93
94 /* Check for timer expiration */
95 Hand = OldTickCount & (TIMER_TABLE_SIZE - 1);
96 if (KiTimerTableListHead[Hand].Time.QuadPart <= InterruptTime.QuadPart)
97 {
98 /* Check if we are already doing expiration */
99 if (!Prcb->TimerRequest)
100 {
101 /* Request a DPC to handle this */
102 Prcb->TimerRequest = (ULONG_PTR)TrapFrame;
103 Prcb->TimerHand = Hand;
104 HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
105 }
106 }
107
108 /* Check if this was a full tick */
109 if (KiTickOffset <= 0)
110 {
111 /* Update the tick offset */
112 KiTickOffset += KeMaximumIncrement;
113
114 /* Update system runtime */
115 KeUpdateRunTime(TrapFrame, Irql);
116 }
117 else
118 {
119 /* Increase interrupt count and exit */
120 Prcb->InterruptCount++;
121 }
122 }
123
124 VOID
125 NTAPI
126 KeUpdateRunTime(IN PKTRAP_FRAME TrapFrame,
127 IN KIRQL Irql)
128 {
129 PKTHREAD Thread = KeGetCurrentThread();
130 PKPRCB Prcb = KeGetCurrentPrcb();
131
132 /* Increase interrupt count */
133 Prcb->InterruptCount++;
134
135 /* Check if we came from user mode */
136 #if defined(_M_IX86)
137 if ((TrapFrame->SegCs & MODE_MASK) || (TrapFrame->EFlags & EFLAGS_V86_MASK))
138 #else
139 if (TrapFrame->PreviousMode == UserMode)
140 #endif
141 {
142 /* Increase thread user time */
143 Prcb->UserTime++;
144 Thread->UserTime++;
145 }
146 else
147 {
148 /* See if we were in an ISR */
149 Prcb->KernelTime++;
150 if (Irql > DISPATCH_LEVEL)
151 {
152 /* Handle that */
153 Prcb->InterruptTime++;
154 }
155 else if ((Irql < DISPATCH_LEVEL) || !(Prcb->DpcRoutineActive))
156 {
157 /* Handle being in kernel mode */
158 Thread->KernelTime++;
159 }
160 else
161 {
162 /* Handle being in a DPC */
163 Prcb->DpcTime++;
164 }
165 }
166
167 /* Update DPC rates */
168 Prcb->DpcRequestRate = ((Prcb->DpcData[0].DpcCount - Prcb->DpcLastCount) +
169 Prcb->DpcRequestRate) >> 1;
170 Prcb->DpcLastCount = Prcb->DpcData[0].DpcCount;
171
172 /* Check if the queue is large enough */
173 if ((Prcb->DpcData[0].DpcQueueDepth) && !(Prcb->DpcRoutineActive))
174 {
175 /* Request a DPC */
176 Prcb->AdjustDpcThreshold = KiAdjustDpcThreshold;
177 HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
178
179 /* Fix the maximum queue depth */
180 if ((Prcb->DpcRequestRate < KiIdealDpcRate) &&
181 (Prcb->MaximumDpcQueueDepth > 1))
182 {
183 /* Make it smaller */
184 Prcb->MaximumDpcQueueDepth--;
185 }
186 }
187 else
188 {
189 /* Check if we've reached the adjustment limit */
190 if (!(--Prcb->AdjustDpcThreshold))
191 {
192 /* Reset it, and check the queue maximum */
193 Prcb->AdjustDpcThreshold = KiAdjustDpcThreshold;
194 if (KiMaximumDpcQueueDepth != Prcb->MaximumDpcQueueDepth)
195 {
196 /* Increase it */
197 Prcb->MaximumDpcQueueDepth++;
198 }
199 }
200 }
201
202 /* Decrement the thread quantum */
203 Thread->Quantum -= CLOCK_QUANTUM_DECREMENT;
204
205 /* Check if the time expired */
206 if ((Thread->Quantum <= 0) && (Thread != Prcb->IdleThread))
207 {
208 /* Schedule a quantum end */
209 Prcb->QuantumEnd = 1;
210 HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
211 }
212 }