- Create KD branch. All debugging support is removed in this branch (no symbols,...
[reactos.git] / reactos / ntoskrnl / ke / clock.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ke/clock.c
5 * PURPOSE: System Clock Support
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* GLOBALS *******************************************************************/
16
17 LARGE_INTEGER KeBootTime;
18 ULONGLONG KeBootTimeBias;
19 volatile KSYSTEM_TIME KeTickCount = {0};
20 volatile ULONG KiRawTicks = 0;
21 ULONG KeMaximumIncrement;
22 ULONG KeMinimumIncrement;
23 ULONG KeTimeAdjustment;
24 ULONG KeTimeIncrement;
25 LONG KiTickOffset = 0;
26
27 /* PRIVATE FUNCTIONS *********************************************************/
28
29 VOID
30 NTAPI
31 KeSetSystemTime(IN PLARGE_INTEGER NewTime,
32 OUT PLARGE_INTEGER OldTime,
33 IN BOOLEAN FixInterruptTime,
34 IN PLARGE_INTEGER HalTime OPTIONAL)
35 {
36 TIME_FIELDS TimeFields;
37 KIRQL OldIrql, OldIrql2;
38 LARGE_INTEGER DeltaTime;
39 PLIST_ENTRY ListHead, NextEntry;
40 PKTIMER Timer;
41 PKSPIN_LOCK_QUEUE LockQueue;
42 LIST_ENTRY TempList, TempList2;
43 ULONG Hand, i;
44 PKTIMER_TABLE_ENTRY TimerEntry;
45
46 /* Sanity checks */
47 ASSERT((NewTime->HighPart & 0xF0000000) == 0);
48 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
49
50 /* Check if this is for the HAL */
51 if (HalTime) RtlTimeToTimeFields(HalTime, &TimeFields);
52
53 /* Set affinity to this CPU, lock the dispatcher, and raise IRQL */
54 KeSetSystemAffinityThread(1);
55 OldIrql = KiAcquireDispatcherLock();
56 KeRaiseIrql(HIGH_LEVEL, &OldIrql2);
57
58 /* Query the system time now */
59 KeQuerySystemTime(OldTime);
60
61 /* Set the new system time */
62 SharedUserData->SystemTime.LowPart = NewTime->LowPart;
63 SharedUserData->SystemTime.High1Time = NewTime->HighPart;
64 SharedUserData->SystemTime.High2Time = NewTime->HighPart;
65
66 /* Check if this was for the HAL and set the RTC time */
67 if (HalTime) ExCmosClockIsSane = HalSetRealTimeClock(&TimeFields);
68
69 /* Calculate the difference between the new and the old time */
70 DeltaTime.QuadPart = NewTime->QuadPart - OldTime->QuadPart;
71
72 /* Update system boot time */
73 KeBootTime.QuadPart += DeltaTime.QuadPart;
74 KeBootTimeBias = KeBootTimeBias + DeltaTime.QuadPart;
75
76 /* Lower IRQL back */
77 KeLowerIrql(OldIrql2);
78
79 /* Check if we need to adjust interrupt time */
80 if (FixInterruptTime) KEBUGCHECK(0);
81
82 /* Setup a temporary list of absolute timers */
83 InitializeListHead(&TempList);
84
85 /* Loop current timers */
86 for (i = 0; i < TIMER_TABLE_SIZE; i++)
87 {
88 /* Loop the entries in this table and lock the timers */
89 ListHead = &KiTimerTableListHead[i].Entry;
90 LockQueue = KiAcquireTimerLock(i);
91 NextEntry = ListHead->Flink;
92 while (NextEntry != ListHead)
93 {
94 /* Get the timer */
95 Timer = CONTAINING_RECORD(NextEntry, KTIMER, TimerListEntry);
96 NextEntry = NextEntry->Flink;
97
98 /* Is is absolute? */
99 if (Timer->Header.Absolute)
100 {
101 /* Remove it from the timer list */
102 if (RemoveEntryList(&Timer->TimerListEntry))
103 {
104 /* Get the entry and check if it's empty */
105 TimerEntry = &KiTimerTableListHead[Timer->Header.Hand];
106 if (IsListEmpty(&TimerEntry->Entry))
107 {
108 /* Clear the time then */
109 TimerEntry->Time.HighPart = 0xFFFFFFFF;
110 }
111 }
112
113 /* Insert it into our temporary list */
114 DPRINT1("Adding a timer!\n");
115 InsertTailList(&TempList, &Timer->TimerListEntry);
116 }
117 }
118
119 /* Release the lock */
120 KiReleaseTimerLock(LockQueue);
121 }
122
123 /* Setup a temporary list of expired timers */
124 InitializeListHead(&TempList2);
125
126 /* Loop absolute timers */
127 while (TempList.Flink != &TempList)
128 {
129 /* Get the timer */
130 Timer = CONTAINING_RECORD(TempList.Flink, KTIMER, TimerListEntry);
131 RemoveEntryList(&Timer->TimerListEntry);
132
133 /* Update the due time and handle */
134 Timer->DueTime.QuadPart -= DeltaTime.QuadPart;
135 Hand = KiComputeTimerTableIndex(Timer->DueTime.QuadPart);
136 Timer->Header.Hand = (UCHAR)Hand;
137
138 /* Lock the timer and re-insert it */
139 LockQueue = KiAcquireTimerLock(Hand);
140 if (KiInsertTimerTable(Timer, Hand))
141 {
142 /* Remove it from the timer list */
143 if (RemoveEntryList(&Timer->TimerListEntry))
144 {
145 /* Get the entry and check if it's empty */
146 TimerEntry = &KiTimerTableListHead[Timer->Header.Hand];
147 if (IsListEmpty(&TimerEntry->Entry))
148 {
149 /* Clear the time then */
150 TimerEntry->Time.HighPart = 0xFFFFFFFF;
151 }
152 }
153
154 /* Insert it into our temporary list */
155 DPRINT1("Adding a timer 2!\n");
156 InsertTailList(&TempList2, &Timer->TimerListEntry);
157 }
158
159 /* Release the lock */
160 KiReleaseTimerLock(LockQueue);
161 }
162
163 /* FIXME: Process expired timers! */
164 KiReleaseDispatcherLock(OldIrql);
165
166 /* Revert affinity */
167 KeRevertToUserAffinityThread();
168 }
169
170 /* PUBLIC FUNCTIONS **********************************************************/
171
172 /*
173 * @implemented
174 */
175 ULONG
176 NTAPI
177 KeQueryTimeIncrement(VOID)
178 {
179 /* Return the increment */
180 return KeMaximumIncrement;
181 }
182
183 /*
184 * @implemented
185 */
186 #undef KeQueryTickCount
187 VOID
188 NTAPI
189 KeQueryTickCount(IN PLARGE_INTEGER TickCount)
190 {
191 /* Loop until we get a perfect match */
192 for (;;)
193 {
194 /* Read the tick count value */
195 TickCount->HighPart = KeTickCount.High1Time;
196 TickCount->LowPart = KeTickCount.LowPart;
197 if (TickCount->HighPart == KeTickCount.High2Time) break;
198 YieldProcessor();
199 }
200 }
201
202 /*
203 * @implemented
204 */
205 VOID
206 NTAPI
207 KeQuerySystemTime(OUT PLARGE_INTEGER CurrentTime)
208 {
209 /* Loop until we get a perfect match */
210 for (;;)
211 {
212 /* Read the time value */
213 CurrentTime->HighPart = SharedUserData->SystemTime.High1Time;
214 CurrentTime->LowPart = SharedUserData->SystemTime.LowPart;
215 if (CurrentTime->HighPart ==
216 SharedUserData->SystemTime.High2Time) break;
217 YieldProcessor();
218 }
219 }
220
221 /*
222 * @implemented
223 */
224 ULONGLONG
225 NTAPI
226 KeQueryInterruptTime(VOID)
227 {
228 LARGE_INTEGER CurrentTime;
229
230 /* Loop until we get a perfect match */
231 for (;;)
232 {
233 /* Read the time value */
234 CurrentTime.HighPart = SharedUserData->InterruptTime.High1Time;
235 CurrentTime.LowPart = SharedUserData->InterruptTime.LowPart;
236 if (CurrentTime.HighPart ==
237 SharedUserData->InterruptTime.High2Time) break;
238 YieldProcessor();
239 }
240
241 /* Return the time value */
242 return CurrentTime.QuadPart;
243 }
244
245 /*
246 * @implemented
247 */
248 VOID
249 NTAPI
250 KeSetTimeIncrement(IN ULONG MaxIncrement,
251 IN ULONG MinIncrement)
252 {
253 /* Set some Internal Variables */
254 KeMaximumIncrement = MaxIncrement;
255 KeMinimumIncrement = max(MinIncrement, 10000);
256 KeTimeAdjustment = MaxIncrement;
257 KeTimeIncrement = MaxIncrement;
258 KiTickOffset = MaxIncrement;
259 }
260
261 NTSTATUS
262 NTAPI
263 NtQueryTimerResolution(OUT PULONG MinimumResolution,
264 OUT PULONG MaximumResolution,
265 OUT PULONG ActualResolution)
266 {
267 UNIMPLEMENTED;
268 return STATUS_NOT_IMPLEMENTED;
269 }
270
271 NTSTATUS
272 NTAPI
273 NtSetTimerResolution(IN ULONG DesiredResolution,
274 IN BOOLEAN SetResolution,
275 OUT PULONG CurrentResolution)
276 {
277 UNIMPLEMENTED;
278 return STATUS_NOT_IMPLEMENTED;
279 }
280
281 /* EOF */