Sync to trunk HEAD (r43416)
[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, 0, 0 };
20 ULONG KeMaximumIncrement;
21 ULONG KeMinimumIncrement;
22 ULONG KeTimeAdjustment;
23 ULONG KeTimeIncrement;
24 LONG KiTickOffset = 0;
25
26 /* PRIVATE FUNCTIONS *********************************************************/
27
28 VOID
29 NTAPI
30 KeSetSystemTime(IN PLARGE_INTEGER NewTime,
31 OUT PLARGE_INTEGER OldTime,
32 IN BOOLEAN FixInterruptTime,
33 IN PLARGE_INTEGER HalTime OPTIONAL)
34 {
35 TIME_FIELDS TimeFields;
36 KIRQL OldIrql, OldIrql2;
37 LARGE_INTEGER DeltaTime;
38 PLIST_ENTRY ListHead, NextEntry;
39 PKTIMER Timer;
40 PKSPIN_LOCK_QUEUE LockQueue;
41 LIST_ENTRY TempList, TempList2;
42 ULONG Hand, i;
43
44 /* Sanity checks */
45 ASSERT((NewTime->HighPart & 0xF0000000) == 0);
46 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
47
48 /* Check if this is for the HAL */
49 if (HalTime) RtlTimeToTimeFields(HalTime, &TimeFields);
50
51 /* Set affinity to this CPU, lock the dispatcher, and raise IRQL */
52 KeSetSystemAffinityThread(1);
53 OldIrql = KiAcquireDispatcherLock();
54 KeRaiseIrql(HIGH_LEVEL, &OldIrql2);
55
56 /* Query the system time now */
57 KeQuerySystemTime(OldTime);
58
59 /* Set the new system time (ordering of these operations is critical) */
60 SharedUserData->SystemTime.High2Time = NewTime->HighPart;
61 SharedUserData->SystemTime.LowPart = NewTime->LowPart;
62 SharedUserData->SystemTime.High1Time = NewTime->HighPart;
63
64 /* Check if this was for the HAL and set the RTC time */
65 if (HalTime) ExCmosClockIsSane = HalSetRealTimeClock(&TimeFields);
66
67 /* Calculate the difference between the new and the old time */
68 DeltaTime.QuadPart = NewTime->QuadPart - OldTime->QuadPart;
69
70 /* Update system boot time */
71 KeBootTime.QuadPart += DeltaTime.QuadPart;
72 KeBootTimeBias = KeBootTimeBias + DeltaTime.QuadPart;
73
74 /* Lower IRQL back */
75 KeLowerIrql(OldIrql2);
76
77 /* Check if we need to adjust interrupt time */
78 if (FixInterruptTime) ASSERT(FALSE);
79
80 /* Setup a temporary list of absolute timers */
81 InitializeListHead(&TempList);
82
83 /* Loop current timers */
84 for (i = 0; i < TIMER_TABLE_SIZE; i++)
85 {
86 /* Loop the entries in this table and lock the timers */
87 ListHead = &KiTimerTableListHead[i].Entry;
88 LockQueue = KiAcquireTimerLock(i);
89 NextEntry = ListHead->Flink;
90 while (NextEntry != ListHead)
91 {
92 /* Get the timer */
93 Timer = CONTAINING_RECORD(NextEntry, KTIMER, TimerListEntry);
94 NextEntry = NextEntry->Flink;
95
96 /* Is it absolute? */
97 if (Timer->Header.Absolute)
98 {
99 /* Remove it from the timer list */
100 KiRemoveEntryTimer(Timer);
101
102 /* Insert it into our temporary list */
103 InsertTailList(&TempList, &Timer->TimerListEntry);
104 }
105 }
106
107 /* Release the lock */
108 KiReleaseTimerLock(LockQueue);
109 }
110
111 /* Setup a temporary list of expired timers */
112 InitializeListHead(&TempList2);
113
114 /* Loop absolute timers */
115 while (TempList.Flink != &TempList)
116 {
117 /* Get the timer */
118 Timer = CONTAINING_RECORD(TempList.Flink, KTIMER, TimerListEntry);
119 RemoveEntryList(&Timer->TimerListEntry);
120
121 /* Update the due time and handle */
122 Timer->DueTime.QuadPart -= DeltaTime.QuadPart;
123 Hand = KiComputeTimerTableIndex(Timer->DueTime.QuadPart);
124 Timer->Header.Hand = (UCHAR)Hand;
125
126 /* Lock the timer and re-insert it */
127 LockQueue = KiAcquireTimerLock(Hand);
128 if (KiInsertTimerTable(Timer, Hand))
129 {
130 /* Remove it from the timer list */
131 KiRemoveEntryTimer(Timer);
132
133 /* Insert it into our temporary list */
134 InsertTailList(&TempList2, &Timer->TimerListEntry);
135 }
136
137 /* Release the lock */
138 KiReleaseTimerLock(LockQueue);
139 }
140
141 /* Process expired timers. This releases the dispatcher lock. */
142 KiTimerListExpire(&TempList2, OldIrql);
143
144 /* Revert affinity */
145 KeRevertToUserAffinityThread();
146 }
147
148 /* PUBLIC FUNCTIONS **********************************************************/
149
150 /*
151 * @implemented
152 */
153 ULONG
154 NTAPI
155 KeQueryTimeIncrement(VOID)
156 {
157 /* Return the increment */
158 return KeMaximumIncrement;
159 }
160
161 /*
162 * @implemented
163 */
164 #undef KeQueryTickCount
165 VOID
166 NTAPI
167 KeQueryTickCount(IN PLARGE_INTEGER TickCount)
168 {
169 /* Loop until we get a perfect match */
170 for (;;)
171 {
172 /* Read the tick count value */
173 TickCount->HighPart = KeTickCount.High1Time;
174 TickCount->LowPart = KeTickCount.LowPart;
175 if (TickCount->HighPart == KeTickCount.High2Time) break;
176 YieldProcessor();
177 }
178 }
179
180 #ifndef _M_AMD64
181 /*
182 * @implemented
183 */
184 VOID
185 NTAPI
186 KeQuerySystemTime(OUT PLARGE_INTEGER CurrentTime)
187 {
188 /* Loop until we get a perfect match */
189 for (;;)
190 {
191 /* Read the time value */
192 CurrentTime->HighPart = SharedUserData->SystemTime.High1Time;
193 CurrentTime->LowPart = SharedUserData->SystemTime.LowPart;
194 if (CurrentTime->HighPart ==
195 SharedUserData->SystemTime.High2Time) break;
196 YieldProcessor();
197 }
198 }
199
200 /*
201 * @implemented
202 */
203 ULONGLONG
204 NTAPI
205 KeQueryInterruptTime(VOID)
206 {
207 LARGE_INTEGER CurrentTime;
208
209 /* Loop until we get a perfect match */
210 for (;;)
211 {
212 /* Read the time value */
213 CurrentTime.HighPart = SharedUserData->InterruptTime.High1Time;
214 CurrentTime.LowPart = SharedUserData->InterruptTime.LowPart;
215 if (CurrentTime.HighPart ==
216 SharedUserData->InterruptTime.High2Time) break;
217 YieldProcessor();
218 }
219
220 /* Return the time value */
221 return CurrentTime.QuadPart;
222 }
223 #endif
224
225 /*
226 * @implemented
227 */
228 VOID
229 NTAPI
230 KeSetTimeIncrement(IN ULONG MaxIncrement,
231 IN ULONG MinIncrement)
232 {
233 /* Set some Internal Variables */
234 KeMaximumIncrement = MaxIncrement;
235 KeMinimumIncrement = max(MinIncrement, 10000);
236 KeTimeAdjustment = MaxIncrement;
237 KeTimeIncrement = MaxIncrement;
238 KiTickOffset = MaxIncrement;
239 }
240
241 NTSTATUS
242 NTAPI
243 NtQueryTimerResolution(OUT PULONG MinimumResolution,
244 OUT PULONG MaximumResolution,
245 OUT PULONG ActualResolution)
246 {
247 UNIMPLEMENTED;
248 return STATUS_NOT_IMPLEMENTED;
249 }
250
251 NTSTATUS
252 NTAPI
253 NtSetTimerResolution(IN ULONG DesiredResolution,
254 IN BOOLEAN SetResolution,
255 OUT PULONG CurrentResolution)
256 {
257 UNIMPLEMENTED;
258 return STATUS_NOT_IMPLEMENTED;
259 }
260
261 /* EOF */