Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygentimerobj.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS Kernel 00003 * LICENSE: GPL - See COPYING in the top level directory 00004 * FILE: ntoskrnl/ke/timer.c 00005 * PURPOSE: Handle Kernel Timers (Kernel-part of Executive Timers) 00006 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 00007 */ 00008 00009 /* INCLUDES ******************************************************************/ 00010 00011 #include <ntoskrnl.h> 00012 #define NDEBUG 00013 #include <debug.h> 00014 00015 /* GLOBALS *******************************************************************/ 00016 00017 KTIMER_TABLE_ENTRY KiTimerTableListHead[TIMER_TABLE_SIZE]; 00018 LARGE_INTEGER KiTimeIncrementReciprocal; 00019 UCHAR KiTimeIncrementShiftCount; 00020 BOOLEAN KiEnableTimerWatchdog = FALSE; 00021 00022 /* PRIVATE FUNCTIONS *********************************************************/ 00023 00024 BOOLEAN 00025 FASTCALL 00026 KiInsertTreeTimer(IN PKTIMER Timer, 00027 IN LARGE_INTEGER Interval) 00028 { 00029 BOOLEAN Inserted = FALSE; 00030 ULONG Hand = 0; 00031 PKSPIN_LOCK_QUEUE LockQueue; 00032 DPRINT("KiInsertTreeTimer(): Timer %p, Interval: %I64d\n", Timer, Interval.QuadPart); 00033 00034 /* Setup the timer's due time */ 00035 if (KiComputeDueTime(Timer, Interval, &Hand)) 00036 { 00037 /* Acquire the lock */ 00038 LockQueue = KiAcquireTimerLock(Hand); 00039 00040 /* Insert the timer */ 00041 if (KiInsertTimerTable(Timer, Hand)) 00042 { 00043 /* It was already there, remove it */ 00044 KiRemoveEntryTimer(Timer); 00045 Timer->Header.Inserted = FALSE; 00046 } 00047 else 00048 { 00049 /* Otherwise, we're now inserted */ 00050 Inserted = TRUE; 00051 } 00052 00053 /* Release the lock */ 00054 KiReleaseTimerLock(LockQueue); 00055 } 00056 00057 /* Release the lock and return insert status */ 00058 return Inserted; 00059 } 00060 00061 BOOLEAN 00062 FASTCALL 00063 KiInsertTimerTable(IN PKTIMER Timer, 00064 IN ULONG Hand) 00065 { 00066 LARGE_INTEGER InterruptTime; 00067 LONGLONG DueTime = Timer->DueTime.QuadPart; 00068 BOOLEAN Expired = FALSE; 00069 PLIST_ENTRY ListHead, NextEntry; 00070 PKTIMER CurrentTimer; 00071 DPRINT("KiInsertTimerTable(): Timer %p, Hand: %d\n", Timer, Hand); 00072 00073 /* Check if the period is zero */ 00074 if (!Timer->Period) Timer->Header.SignalState = FALSE; 00075 00076 /* Sanity check */ 00077 ASSERT(Hand == KiComputeTimerTableIndex(DueTime)); 00078 00079 /* Loop the timer list backwards */ 00080 ListHead = &KiTimerTableListHead[Hand].Entry; 00081 NextEntry = ListHead->Blink; 00082 while (NextEntry != ListHead) 00083 { 00084 /* Get the timer */ 00085 CurrentTimer = CONTAINING_RECORD(NextEntry, KTIMER, TimerListEntry); 00086 00087 /* Now check if we can fit it before */ 00088 if ((ULONGLONG)DueTime >= CurrentTimer->DueTime.QuadPart) break; 00089 00090 /* Keep looping */ 00091 NextEntry = NextEntry->Blink; 00092 } 00093 00094 /* Looped all the list, insert it here and get the interrupt time again */ 00095 InsertHeadList(NextEntry, &Timer->TimerListEntry); 00096 00097 /* Check if we didn't find it in the list */ 00098 if (NextEntry == ListHead) 00099 { 00100 /* Set the time */ 00101 KiTimerTableListHead[Hand].Time.QuadPart = DueTime; 00102 00103 /* Make sure it hasn't expired already */ 00104 InterruptTime.QuadPart = KeQueryInterruptTime(); 00105 if (DueTime <= InterruptTime.QuadPart) Expired = TRUE; 00106 } 00107 00108 /* Return expired state */ 00109 return Expired; 00110 } 00111 00112 BOOLEAN 00113 FASTCALL 00114 KiSignalTimer(IN PKTIMER Timer) 00115 { 00116 BOOLEAN RequestInterrupt = FALSE; 00117 PKDPC Dpc = Timer->Dpc; 00118 ULONG Period = Timer->Period; 00119 LARGE_INTEGER Interval, SystemTime; 00120 DPRINT("KiSignalTimer(): Timer %p\n", Timer); 00121 00122 /* Set default values */ 00123 Timer->Header.Inserted = FALSE; 00124 Timer->Header.SignalState = TRUE; 00125 00126 /* Check if the timer has waiters */ 00127 if (!IsListEmpty(&Timer->Header.WaitListHead)) 00128 { 00129 /* Check the type of event */ 00130 if (Timer->Header.Type == TimerNotificationObject) 00131 { 00132 /* Unwait the thread */ 00133 KxUnwaitThread(&Timer->Header, IO_NO_INCREMENT); 00134 } 00135 else 00136 { 00137 /* Otherwise unwait the thread and signal the timer */ 00138 KxUnwaitThreadForEvent((PKEVENT)Timer, IO_NO_INCREMENT); 00139 } 00140 } 00141 00142 /* Check if we have a period */ 00143 if (Period) 00144 { 00145 /* Calculate the interval and insert the timer */ 00146 Interval.QuadPart = Int32x32To64(Period, -10000); 00147 while (!KiInsertTreeTimer(Timer, Interval)); 00148 } 00149 00150 /* Check if we have a DPC */ 00151 if (Dpc) 00152 { 00153 /* Insert it in the queue */ 00154 KeQuerySystemTime(&SystemTime); 00155 KeInsertQueueDpc(Dpc, 00156 ULongToPtr(SystemTime.LowPart), 00157 ULongToPtr(SystemTime.HighPart)); 00158 RequestInterrupt = TRUE; 00159 } 00160 00161 /* Return whether we need to request a DPC interrupt or not */ 00162 return RequestInterrupt; 00163 } 00164 00165 VOID 00166 FASTCALL 00167 KiCompleteTimer(IN PKTIMER Timer, 00168 IN PKSPIN_LOCK_QUEUE LockQueue) 00169 { 00170 LIST_ENTRY ListHead; 00171 BOOLEAN RequestInterrupt = FALSE; 00172 DPRINT("KiCompleteTimer(): Timer %p, LockQueue: %p\n", Timer, LockQueue); 00173 00174 /* Remove it from the timer list */ 00175 KiRemoveEntryTimer(Timer); 00176 00177 /* Link the timer list to our stack */ 00178 ListHead.Flink = &Timer->TimerListEntry; 00179 ListHead.Blink = &Timer->TimerListEntry; 00180 Timer->TimerListEntry.Flink = &ListHead; 00181 Timer->TimerListEntry.Blink = &ListHead; 00182 00183 /* Release the timer lock */ 00184 KiReleaseTimerLock(LockQueue); 00185 00186 /* Acquire dispatcher lock */ 00187 KiAcquireDispatcherLockAtDpcLevel(); 00188 00189 /* Signal the timer if it's still on our list */ 00190 if (!IsListEmpty(&ListHead)) RequestInterrupt = KiSignalTimer(Timer); 00191 00192 /* Release the dispatcher lock */ 00193 KiReleaseDispatcherLockFromDpcLevel(); 00194 00195 /* Request a DPC if needed */ 00196 if (RequestInterrupt) HalRequestSoftwareInterrupt(DISPATCH_LEVEL); 00197 } 00198 00199 /* PUBLIC FUNCTIONS **********************************************************/ 00200 00201 /* 00202 * @implemented 00203 */ 00204 BOOLEAN 00205 NTAPI 00206 KeCancelTimer(IN OUT PKTIMER Timer) 00207 { 00208 KIRQL OldIrql; 00209 BOOLEAN Inserted; 00210 ASSERT_TIMER(Timer); 00211 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); 00212 DPRINT("KeCancelTimer(): Timer %p\n", Timer); 00213 00214 /* Lock the Database and Raise IRQL */ 00215 OldIrql = KiAcquireDispatcherLock(); 00216 00217 /* Check if it's inserted, and remove it if it is */ 00218 Inserted = Timer->Header.Inserted; 00219 if (Inserted) KxRemoveTreeTimer(Timer); 00220 00221 /* Release Dispatcher Lock */ 00222 KiReleaseDispatcherLock(OldIrql); 00223 00224 /* Return the old state */ 00225 return Inserted; 00226 } 00227 00228 /* 00229 * @implemented 00230 */ 00231 VOID 00232 NTAPI 00233 KeInitializeTimer(OUT PKTIMER Timer) 00234 { 00235 /* Call the New Function */ 00236 KeInitializeTimerEx(Timer, NotificationTimer); 00237 } 00238 00239 /* 00240 * @implemented 00241 */ 00242 VOID 00243 NTAPI 00244 KeInitializeTimerEx(OUT PKTIMER Timer, 00245 IN TIMER_TYPE Type) 00246 { 00247 DPRINT("KeInitializeTimerEx(): Timer %p, Type %s\n", 00248 Timer, (Type == NotificationTimer) ? 00249 "NotificationTimer" : "SynchronizationTimer"); 00250 00251 /* Initialize the Dispatch Header */ 00252 Timer->Header.Type = TimerNotificationObject + Type; 00253 //Timer->Header.TimerControlFlags = 0; // win does not init this field 00254 Timer->Header.Hand = sizeof(KTIMER) / sizeof(ULONG); 00255 Timer->Header.Inserted = 0; // win7: Timer->Header.TimerMiscFlags = 0; 00256 Timer->Header.SignalState = 0; 00257 InitializeListHead(&(Timer->Header.WaitListHead)); 00258 00259 /* Initalize the Other data */ 00260 Timer->DueTime.QuadPart = 0; 00261 Timer->Period = 0; 00262 } 00263 00264 /* 00265 * @implemented 00266 */ 00267 BOOLEAN 00268 NTAPI 00269 KeReadStateTimer(IN PKTIMER Timer) 00270 { 00271 /* Return the Signal State */ 00272 ASSERT_TIMER(Timer); 00273 return (BOOLEAN)Timer->Header.SignalState; 00274 } 00275 00276 /* 00277 * @implemented 00278 */ 00279 BOOLEAN 00280 NTAPI 00281 KeSetTimer(IN OUT PKTIMER Timer, 00282 IN LARGE_INTEGER DueTime, 00283 IN PKDPC Dpc OPTIONAL) 00284 { 00285 /* Call the newer function and supply a period of 0 */ 00286 return KeSetTimerEx(Timer, DueTime, 0, Dpc); 00287 } 00288 00289 /* 00290 * @implemented 00291 */ 00292 BOOLEAN 00293 NTAPI 00294 KeSetTimerEx(IN OUT PKTIMER Timer, 00295 IN LARGE_INTEGER DueTime, 00296 IN LONG Period, 00297 IN PKDPC Dpc OPTIONAL) 00298 { 00299 KIRQL OldIrql; 00300 BOOLEAN Inserted; 00301 ULONG Hand = 0; 00302 BOOLEAN RequestInterrupt = FALSE; 00303 ASSERT_TIMER(Timer); 00304 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); 00305 DPRINT("KeSetTimerEx(): Timer %p, DueTime %I64d, Period %d, Dpc %p\n", 00306 Timer, DueTime.QuadPart, Period, Dpc); 00307 00308 /* Lock the Database and Raise IRQL */ 00309 OldIrql = KiAcquireDispatcherLock(); 00310 00311 /* Check if it's inserted, and remove it if it is */ 00312 Inserted = Timer->Header.Inserted; 00313 if (Inserted) KxRemoveTreeTimer(Timer); 00314 00315 /* Set Default Timer Data */ 00316 Timer->Dpc = Dpc; 00317 Timer->Period = Period; 00318 if (!KiComputeDueTime(Timer, DueTime, &Hand)) 00319 { 00320 /* Signal the timer */ 00321 RequestInterrupt = KiSignalTimer(Timer); 00322 00323 /* Release the dispatcher lock */ 00324 KiReleaseDispatcherLockFromDpcLevel(); 00325 00326 /* Check if we need to do an interrupt */ 00327 if (RequestInterrupt) HalRequestSoftwareInterrupt(DISPATCH_LEVEL); 00328 } 00329 else 00330 { 00331 /* Insert the timer */ 00332 Timer->Header.SignalState = FALSE; 00333 KxInsertTimer(Timer, Hand); 00334 } 00335 00336 /* Exit the dispatcher */ 00337 KiExitDispatcher(OldIrql); 00338 00339 /* Return old state */ 00340 return Inserted; 00341 } 00342 Generated on Mon May 28 2012 04:37:27 for ReactOS by
1.7.6.1
|