Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

timerobj.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1989 Microsoft Corporation 00004 00005 Module Name: 00006 00007 timerobj.c 00008 00009 Abstract: 00010 00011 This module implements the kernel timer object. Functions are 00012 provided to initialize, read, set, and cancel timer objects. 00013 00014 Author: 00015 00016 David N. Cutler (davec) 2-Mar-1989 00017 00018 Environment: 00019 00020 Kernel mode only. 00021 00022 Revision History: 00023 00024 --*/ 00025 00026 #include "ki.h" 00027 00028 #ifdef ALLOC_PRAGMA 00029 #pragma alloc_text(PAGELK, KeQueryTimerDueTime) 00030 #endif 00031 00032 // 00033 // The following assert macro is used to check that an input timer is 00034 // really a ktimer and not something else, like deallocated pool. 00035 // 00036 00037 #define ASSERT_TIMER(E) { \ 00038 ASSERT(((E)->Header.Type == TimerNotificationObject) || \ 00039 ((E)->Header.Type == TimerSynchronizationObject)); \ 00040 } 00041 00042 VOID 00043 KeInitializeTimer ( 00044 IN PKTIMER Timer 00045 ) 00046 00047 /*++ 00048 00049 Routine Description: 00050 00051 This function initializes a kernel timer object. 00052 00053 Arguments: 00054 00055 Timer - Supplies a pointer to a dispatcher object of type timer. 00056 00057 Return Value: 00058 00059 None. 00060 00061 --*/ 00062 00063 { 00064 00065 // 00066 // Initialize extended timer object with a type of notification and a 00067 // period of zero. 00068 // 00069 00070 KeInitializeTimerEx(Timer, NotificationTimer); 00071 return; 00072 } 00073 00074 VOID 00075 KeInitializeTimerEx ( 00076 IN PKTIMER Timer, 00077 IN TIMER_TYPE Type 00078 ) 00079 00080 /*++ 00081 00082 Routine Description: 00083 00084 This function initializes an extended kernel timer object. 00085 00086 Arguments: 00087 00088 Timer - Supplies a pointer to a dispatcher object of type timer. 00089 00090 Type - Supplies the type of timer object; NotificationTimer or 00091 SynchronizationTimer; 00092 00093 Return Value: 00094 00095 None. 00096 00097 --*/ 00098 00099 { 00100 // 00101 // Initialize standard dispatcher object header and set initial 00102 // state of timer. 00103 // 00104 00105 Timer->Header.Type = TimerNotificationObject + Type; 00106 Timer->Header.Inserted = FALSE; 00107 Timer->Header.Size = sizeof(KTIMER) / sizeof(LONG); 00108 Timer->Header.SignalState = FALSE; 00109 00110 #if DBG 00111 00112 Timer->TimerListEntry.Flink = NULL; 00113 Timer->TimerListEntry.Blink = NULL; 00114 00115 #endif 00116 00117 InitializeListHead(&Timer->Header.WaitListHead); 00118 Timer->DueTime.QuadPart = 0; 00119 Timer->Period = 0; 00120 return; 00121 } 00122 00123 VOID 00124 KeClearTimer ( 00125 IN PKTIMER Timer 00126 ) 00127 00128 /*++ 00129 00130 Routine Description: 00131 00132 This function clears the signal state of an timer object. 00133 00134 Arguments: 00135 00136 Event - Supplies a pointer to a dispatcher object of type timer. 00137 00138 Return Value: 00139 00140 None. 00141 00142 --*/ 00143 00144 { 00145 00146 ASSERT_TIMER(Timer); 00147 00148 // 00149 // Clear signal state of timer object. 00150 // 00151 00152 Timer->Header.SignalState = 0; 00153 return; 00154 } 00155 00156 BOOLEAN 00157 KeCancelTimer ( 00158 IN PKTIMER Timer 00159 ) 00160 00161 /*++ 00162 00163 Routine Description: 00164 00165 This function cancels a timer that was previously set to expire at 00166 a specified time. If the timer is not currently set, then no operation 00167 is performed. Canceling a timer does not set the state of the timer to 00168 Signaled. 00169 00170 Arguments: 00171 00172 Timer - Supplies a pointer to a dispatcher object of type timer. 00173 00174 Return Value: 00175 00176 A boolean value of TRUE is returned if the the specified timer was 00177 currently set. Else a value of FALSE is returned. 00178 00179 --*/ 00180 00181 { 00182 00183 BOOLEAN Inserted; 00184 KIRQL OldIrql; 00185 00186 ASSERT_TIMER(Timer); 00187 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); 00188 00189 // 00190 // Raise IRQL to dispatcher level, lock the dispatcher database, and 00191 // capture the timer inserted status. If the timer is currently set, 00192 // then remove it from the timer list. 00193 // 00194 00195 KiLockDispatcherDatabase(&OldIrql); 00196 Inserted = Timer->Header.Inserted; 00197 if (Inserted != FALSE) { 00198 KiRemoveTreeTimer(Timer); 00199 } 00200 00201 // 00202 // Unlock the dispatcher database, lower IRQL to its previous value, and 00203 // return boolean value that signifies whether the timer was set of not. 00204 // 00205 00206 KiUnlockDispatcherDatabase(OldIrql); 00207 return Inserted; 00208 } 00209 00210 BOOLEAN 00211 KeReadStateTimer ( 00212 IN PKTIMER Timer 00213 ) 00214 00215 /*++ 00216 00217 Routine Description: 00218 00219 This function reads the current signal state of a timer object. 00220 00221 Arguments: 00222 00223 Timer - Supplies a pointer to a dispatcher object of type timer. 00224 00225 Return Value: 00226 00227 The current signal state of the timer object. 00228 00229 --*/ 00230 00231 { 00232 00233 ASSERT_TIMER(Timer); 00234 00235 // 00236 // Return current signal state of timer object. 00237 // 00238 00239 return (BOOLEAN)Timer->Header.SignalState; 00240 } 00241 00242 BOOLEAN 00243 KeSetTimer ( 00244 IN PKTIMER Timer, 00245 IN LARGE_INTEGER DueTime, 00246 IN PKDPC Dpc OPTIONAL 00247 ) 00248 00249 /*++ 00250 00251 Routine Description: 00252 00253 This function sets a timer to expire at a specified time. If the timer is 00254 already set, then it is implicitly canceled before it is set to expire at 00255 the specified time. Setting a timer causes its due time to be computed, 00256 its state to be set to Not-Signaled, and the timer object itself to be 00257 inserted in the timer list. 00258 00259 Arguments: 00260 00261 Timer - Supplies a pointer to a dispatcher object of type timer. 00262 00263 DueTime - Supplies an absolute or relative time at which the timer 00264 is to expire. 00265 00266 Dpc - Supplies an optional pointer to a control object of type DPC. 00267 00268 Return Value: 00269 00270 A boolean value of TRUE is returned if the the specified timer was 00271 currently set. Else a value of FALSE is returned. 00272 00273 --*/ 00274 00275 { 00276 00277 // 00278 // Set the timer with a period of zero. 00279 // 00280 00281 return KeSetTimerEx(Timer, DueTime, 0, Dpc); 00282 } 00283 00284 BOOLEAN 00285 KeSetTimerEx ( 00286 IN PKTIMER Timer, 00287 IN LARGE_INTEGER DueTime, 00288 IN LONG Period OPTIONAL, 00289 IN PKDPC Dpc OPTIONAL 00290 ) 00291 00292 /*++ 00293 00294 Routine Description: 00295 00296 This function sets a timer to expire at a specified time. If the timer is 00297 already set, then it is implicitly canceled before it is set to expire at 00298 the specified time. Setting a timer causes its due time to be computed, 00299 its state to be set to Not-Signaled, and the timer object itself to be 00300 inserted in the timer list. 00301 00302 Arguments: 00303 00304 Timer - Supplies a pointer to a dispatcher object of type timer. 00305 00306 DueTime - Supplies an absolute or relative time at which the timer 00307 is to expire. 00308 00309 Period - Supplies an optional period for the timer in milliseconds. 00310 00311 Dpc - Supplies an optional pointer to a control object of type DPC. 00312 00313 Return Value: 00314 00315 A boolean value of TRUE is returned if the the specified timer was 00316 currently set. Else a value of FALSE is returned. 00317 00318 --*/ 00319 00320 { 00321 00322 BOOLEAN Inserted; 00323 LARGE_INTEGER Interval; 00324 KIRQL OldIrql; 00325 LARGE_INTEGER SystemTime; 00326 00327 ASSERT_TIMER(Timer); 00328 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); 00329 00330 // 00331 // Raise IRQL to dispatcher level and lock dispatcher database. 00332 // 00333 00334 KiLockDispatcherDatabase(&OldIrql); 00335 00336 // 00337 // Capture the timer inserted status and if the timer is currently 00338 // set, then remove it from the timer list. 00339 // 00340 00341 Inserted = Timer->Header.Inserted; 00342 if (Inserted != FALSE) { 00343 KiRemoveTreeTimer(Timer); 00344 } 00345 00346 // 00347 // Clear the signal state, set the period, set the DPC address, and 00348 // insert the timer in the timer tree. If the timer is not inserted 00349 // in the timer tree, then it has already expired and as many waiters 00350 // as possible should be continued, and a DPC, if specified should be 00351 // queued. 00352 // 00353 // N.B. The signal state must be cleared in case the period is not 00354 // zero. 00355 // 00356 00357 Timer->Header.SignalState = FALSE; 00358 Timer->Dpc = Dpc; 00359 Timer->Period = Period; 00360 if (KiInsertTreeTimer((PRKTIMER)Timer, DueTime) == FALSE) { 00361 if (IsListEmpty(&Timer->Header.WaitListHead) == FALSE) { 00362 KiWaitTest(Timer, TIMER_EXPIRE_INCREMENT); 00363 } 00364 00365 // 00366 // If a DPC is specfied, then call the DPC routine. 00367 // 00368 00369 if (Dpc != NULL) { 00370 KiQuerySystemTime(&SystemTime); 00371 KeInsertQueueDpc(Timer->Dpc, 00372 ULongToPtr(SystemTime.LowPart), 00373 ULongToPtr(SystemTime.HighPart)); 00374 } 00375 00376 // 00377 // If the timer is periodic, then compute the next interval time 00378 // and reinsert the timer in the timer tree. 00379 // 00380 // N.B. Even though the timer insertion is relative, it can still 00381 // fail if the period of the timer elapses in between computing 00382 // the time and inserting the timer in the table. If this happens, 00383 // try again. 00384 // 00385 00386 if (Period != 0) { 00387 Interval.QuadPart = Int32x32To64(Timer->Period, - 10 * 1000); 00388 while (!KiInsertTreeTimer(Timer, Interval)) { 00389 ; 00390 } 00391 } 00392 } 00393 00394 // 00395 // Unlock the dispatcher database and lower IRQL to its previous 00396 // value. 00397 // 00398 00399 KiUnlockDispatcherDatabase(OldIrql); 00400 00401 // 00402 // Return boolean value that signifies whether the timer was set of 00403 // not. 00404 // 00405 00406 return Inserted; 00407 } 00408 00409 ULONGLONG 00410 KeQueryTimerDueTime ( 00411 IN PKTIMER Timer 00412 ) 00413 00414 /*++ 00415 00416 Routine Description: 00417 00418 This function returns the InterruptTime at which the timer is 00419 pending. 0 is returned if the timer is not pending. 00420 00421 N.B. This function may only be called by the system sleep code. 00422 00423 Arguments: 00424 00425 Timer - Supplies a pointer to a dispatcher object of type timer. 00426 00427 Return Value: 00428 00429 Returns the amount of time remaining on the timer, or 0 if the 00430 timer is not pending. 00431 00432 --*/ 00433 00434 { 00435 00436 KIRQL OldIrql; 00437 LARGE_INTEGER InterruptTime; 00438 ULONGLONG DueTime; 00439 00440 ASSERT_TIMER(Timer); 00441 00442 // 00443 // Raise IRQL to dispatcher level and lock dispatcher database. 00444 // 00445 00446 KiLockDispatcherDatabase(&OldIrql); 00447 00448 // 00449 // If the timer is currently pending, compute its due time 00450 // 00451 00452 DueTime = 0; 00453 if (Timer->Header.Inserted) { 00454 DueTime = Timer->DueTime.QuadPart; 00455 } 00456 00457 // 00458 // Unlock the dispatcher database and lower IRQL to its previous 00459 // value, and return the due time 00460 // 00461 00462 KiUnlockDispatcherDatabase(OldIrql); 00463 return DueTime; 00464 } 00465 00466 PVOID 00467 KeCheckForTimer( 00468 IN PVOID BlockStart, 00469 IN ULONG BlockSize 00470 ) 00471 /*++ 00472 00473 Routine Description: 00474 00475 This function is used for debugging by checking all timers 00476 to see if any is in the memory block passed. If so, the 00477 system stops at a debug breakpoint. 00478 00479 Arguments: 00480 00481 MemoryBlock - Base address to check for timer 00482 00483 BlockSize - Size (in bytes) to check in memory block 00484 00485 Return Value: 00486 00487 The address of the currently active timer. 00488 00489 --*/ 00490 { 00491 ULONG Index; 00492 PLIST_ENTRY ListHead; 00493 PLIST_ENTRY NextEntry; 00494 KIRQL OldIrql; 00495 PKTIMER Timer; 00496 PUCHAR Address; 00497 PUCHAR Start; 00498 PUCHAR End; 00499 00500 // 00501 // Compute the ending memory location. 00502 // 00503 00504 Start = (PUCHAR)BlockStart; 00505 End = Start + BlockSize; 00506 00507 // 00508 // Raise IRQL to dispatcher level and lock dispatcher database. 00509 // 00510 00511 KiLockDispatcherDatabase(&OldIrql); 00512 00513 // 00514 // Run the entire timer database and check for any timers in 00515 // the memory block 00516 // 00517 00518 Index = 0; 00519 do { 00520 ListHead = &KiTimerTableListHead[Index]; 00521 NextEntry = ListHead->Flink; 00522 while (NextEntry != ListHead) { 00523 Timer = CONTAINING_RECORD(NextEntry, KTIMER, TimerListEntry); 00524 Address = (PUCHAR)Timer; 00525 NextEntry = NextEntry->Flink; 00526 00527 // 00528 // Check this timer object is not in the range. 00529 // In each of the following, we check that the object 00530 // does not overlap the range, for example, if the timer 00531 // object (in this first check), starts one dword before 00532 // the range being checked, we have an overlap and should 00533 // stop. 00534 // 00535 00536 if ((Address > (Start - sizeof(KTIMER))) && 00537 (Address < End)) { 00538 KeBugCheckEx(TIMER_OR_DPC_INVALID, 00539 0x0, 00540 (ULONG_PTR)Address, 00541 (ULONG_PTR)Start, 00542 (ULONG_PTR)End); 00543 } 00544 00545 if (Timer->Dpc) { 00546 00547 // 00548 // Check the timer's DPC object isn't in the range. 00549 // 00550 00551 Address = (PUCHAR)Timer->Dpc; 00552 if ((Address > (Start - sizeof(KDPC))) && 00553 (Address < End)) { 00554 KeBugCheckEx(TIMER_OR_DPC_INVALID, 00555 0x1, 00556 (ULONG_PTR)Address, 00557 (ULONG_PTR)Start, 00558 (ULONG_PTR)End); 00559 } 00560 00561 // 00562 // Check the timer's DPC routine is not in the range. 00563 // 00564 00565 Address = (PUCHAR)Timer->Dpc->DeferredRoutine; 00566 if (Address >= Start && Address < End) { 00567 KeBugCheckEx(TIMER_OR_DPC_INVALID, 00568 0x2, 00569 (ULONG_PTR)Address, 00570 (ULONG_PTR)Start, 00571 (ULONG_PTR)End); 00572 } 00573 } 00574 } 00575 00576 Index += 1; 00577 } while(Index < TIMER_TABLE_SIZE); 00578 00579 00580 // 00581 // Unlock the dispatcher database and lower IRQL to its previous value 00582 // 00583 00584 KiUnlockDispatcherDatabase(OldIrql); 00585 return NULL; 00586 }

Generated on Sat May 15 19:41:59 2004 for test by doxygen 1.3.7