- Two more leftovers.
[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 InsertTailList(&TempList, &Timer->TimerListEntry);
115 }
116 }
117
118 /* Release the lock */
119 KiReleaseTimerLock(LockQueue);
120 }
121
122 /* Setup a temporary list of expired timers */
123 InitializeListHead(&TempList2);
124
125 /* Loop absolute timers */
126 while (TempList.Flink != &TempList)
127 {
128 /* Get the timer */
129 Timer = CONTAINING_RECORD(TempList.Flink, KTIMER, TimerListEntry);
130 RemoveEntryList(&Timer->TimerListEntry);
131
132 /* Update the due time and handle */
133 Timer->DueTime.QuadPart -= DeltaTime.QuadPart;
134 Hand = KiComputeTimerTableIndex(Timer->DueTime.QuadPart);
135 Timer->Header.Hand = (UCHAR)Hand;
136
137 /* Lock the timer and re-insert it */
138 LockQueue = KiAcquireTimerLock(Hand);
139 if (KiInsertTimerTable(Timer, Hand))
140 {
141 /* Remove it from the timer list */
142 if (RemoveEntryList(&Timer->TimerListEntry))
143 {
144 /* Get the entry and check if it's empty */
145 TimerEntry = &KiTimerTableListHead[Timer->Header.Hand];
146 if (IsListEmpty(&TimerEntry->Entry))
147 {
148 /* Clear the time then */
149 TimerEntry->Time.HighPart = 0xFFFFFFFF;
150 }
151 }
152
153 /* Insert it into our temporary list */
154 InsertTailList(&TempList2, &Timer->TimerListEntry);
155 }
156
157 /* Release the lock */
158 KiReleaseTimerLock(LockQueue);
159 }
160
161 /* FIXME: Process expired timers! */
162 KiReleaseDispatcherLock(OldIrql);
163
164 /* Revert affinity */
165 KeRevertToUserAffinityThread();
166 }
167
168 /* PUBLIC FUNCTIONS **********************************************************/
169
170 /*
171 * @implemented
172 */
173 ULONG
174 NTAPI
175 KeQueryTimeIncrement(VOID)
176 {
177 /* Return the increment */
178 return KeMaximumIncrement;
179 }
180
181 /*
182 * @implemented
183 */
184 #undef KeQueryTickCount
185 VOID
186 NTAPI
187 KeQueryTickCount(IN PLARGE_INTEGER TickCount)
188 {
189 /* Loop until we get a perfect match */
190 for (;;)
191 {
192 /* Read the tick count value */
193 TickCount->HighPart = KeTickCount.High1Time;
194 TickCount->LowPart = KeTickCount.LowPart;
195 if (TickCount->HighPart == KeTickCount.High2Time) break;
196 YieldProcessor();
197 }
198 }
199
200 /*
201 * @implemented
202 */
203 VOID
204 NTAPI
205 KeQuerySystemTime(OUT PLARGE_INTEGER CurrentTime)
206 {
207 /* Loop until we get a perfect match */
208 for (;;)
209 {
210 /* Read the time value */
211 CurrentTime->HighPart = SharedUserData->SystemTime.High1Time;
212 CurrentTime->LowPart = SharedUserData->SystemTime.LowPart;
213 if (CurrentTime->HighPart ==
214 SharedUserData->SystemTime.High2Time) break;
215 YieldProcessor();
216 }
217 }
218
219 /*
220 * @implemented
221 */
222 ULONGLONG
223 NTAPI
224 KeQueryInterruptTime(VOID)
225 {
226 LARGE_INTEGER CurrentTime;
227
228 /* Loop until we get a perfect match */
229 for (;;)
230 {
231 /* Read the time value */
232 CurrentTime.HighPart = SharedUserData->InterruptTime.High1Time;
233 CurrentTime.LowPart = SharedUserData->InterruptTime.LowPart;
234 if (CurrentTime.HighPart ==
235 SharedUserData->InterruptTime.High2Time) break;
236 YieldProcessor();
237 }
238
239 /* Return the time value */
240 return CurrentTime.QuadPart;
241 }
242
243 /*
244 * @implemented
245 */
246 VOID
247 NTAPI
248 KeSetTimeIncrement(IN ULONG MaxIncrement,
249 IN ULONG MinIncrement)
250 {
251 /* Set some Internal Variables */
252 KeMaximumIncrement = MaxIncrement;
253 KeMinimumIncrement = max(MinIncrement, 10000);
254 KeTimeAdjustment = MaxIncrement;
255 KeTimeIncrement = MaxIncrement;
256 KiTickOffset = MaxIncrement;
257 }
258
259 NTSTATUS
260 NTAPI
261 NtQueryTimerResolution(OUT PULONG MinimumResolution,
262 OUT PULONG MaximumResolution,
263 OUT PULONG ActualResolution)
264 {
265 UNIMPLEMENTED;
266 return STATUS_NOT_IMPLEMENTED;
267 }
268
269 NTSTATUS
270 NTAPI
271 NtSetTimerResolution(IN ULONG DesiredResolution,
272 IN BOOLEAN SetResolution,
273 OUT PULONG CurrentResolution)
274 {
275 UNIMPLEMENTED;
276 return STATUS_NOT_IMPLEMENTED;
277 }
278
279 /* EOF */