Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygentimer.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/ex/timer.c 00005 * PURPOSE: Executive Timer Implementation 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 /* Timer Object Type */ 00018 POBJECT_TYPE ExTimerType = NULL; 00019 00020 KSPIN_LOCK ExpWakeListLock; 00021 LIST_ENTRY ExpWakeList; 00022 00023 /* Timer Mapping */ 00024 static GENERIC_MAPPING ExpTimerMapping = 00025 { 00026 STANDARD_RIGHTS_READ | TIMER_QUERY_STATE, 00027 STANDARD_RIGHTS_WRITE | TIMER_MODIFY_STATE, 00028 STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE, 00029 TIMER_ALL_ACCESS 00030 }; 00031 00032 /* Timer Information Classes */ 00033 static const INFORMATION_CLASS_INFO ExTimerInfoClass[] = 00034 { 00035 /* TimerBasicInformation */ 00036 ICI_SQ_SAME(sizeof(TIMER_BASIC_INFORMATION), sizeof(ULONG), ICIF_QUERY), 00037 }; 00038 00039 /* PRIVATE FUNCTIONS *********************************************************/ 00040 00041 VOID 00042 NTAPI 00043 ExTimerRundown(VOID) 00044 { 00045 PETHREAD Thread = PsGetCurrentThread(); 00046 KIRQL OldIrql; 00047 PLIST_ENTRY CurrentEntry; 00048 PETIMER Timer; 00049 ULONG DerefsToDo; 00050 00051 /* Lock the Thread's Active Timer List and loop it */ 00052 KeAcquireSpinLock(&Thread->ActiveTimerListLock, &OldIrql); 00053 CurrentEntry = Thread->ActiveTimerListHead.Flink; 00054 while (CurrentEntry != &Thread->ActiveTimerListHead) 00055 { 00056 /* Get the timer */ 00057 Timer = CONTAINING_RECORD(CurrentEntry, ETIMER, ActiveTimerListEntry); 00058 00059 /* Reference it */ 00060 ObReferenceObject(Timer); 00061 DerefsToDo = 1; 00062 00063 /* Unlock the list */ 00064 KeReleaseSpinLock(&Thread->ActiveTimerListLock, OldIrql); 00065 00066 /* Lock the Timer */ 00067 KeAcquireSpinLock(&Timer->Lock, &OldIrql); 00068 00069 /* Lock the list again */ 00070 KeAcquireSpinLockAtDpcLevel(&Thread->ActiveTimerListLock); 00071 00072 /* Make sure that the timer is valid */ 00073 if ((Timer->ApcAssociated) && (&Thread->Tcb == Timer->TimerApc.Thread)) 00074 { 00075 /* Remove it from the list */ 00076 RemoveEntryList(&Timer->ActiveTimerListEntry); 00077 Timer->ApcAssociated = FALSE; 00078 00079 /* Cancel the timer and remove its DPC and APC */ 00080 KeCancelTimer(&Timer->KeTimer); 00081 KeRemoveQueueDpc(&Timer->TimerDpc); 00082 if (KeRemoveQueueApc(&Timer->TimerApc)) DerefsToDo++; 00083 00084 /* Add another dereference to do */ 00085 DerefsToDo++; 00086 } 00087 00088 /* Unlock the list */ 00089 KeReleaseSpinLockFromDpcLevel(&Thread->ActiveTimerListLock); 00090 00091 /* Unlock the Timer */ 00092 KeReleaseSpinLock(&Timer->Lock, OldIrql); 00093 00094 /* Dereference it */ 00095 ObDereferenceObjectEx(Timer, DerefsToDo); 00096 00097 /* Loop again */ 00098 KeAcquireSpinLock(&Thread->ActiveTimerListLock, &OldIrql); 00099 CurrentEntry = Thread->ActiveTimerListHead.Flink; 00100 } 00101 00102 /* Release lock and return */ 00103 KeReleaseSpinLock(&Thread->ActiveTimerListLock, OldIrql); 00104 } 00105 00106 VOID 00107 NTAPI 00108 ExpDeleteTimer(IN PVOID ObjectBody) 00109 { 00110 KIRQL OldIrql; 00111 PETIMER Timer = ObjectBody; 00112 00113 /* Check if it has a Wait List */ 00114 if (Timer->WakeTimerListEntry.Flink) 00115 { 00116 /* Lock the Wake List */ 00117 KeAcquireSpinLock(&ExpWakeListLock, &OldIrql); 00118 00119 /* Check again, since it might've changed before we locked */ 00120 if (Timer->WakeTimerListEntry.Flink) 00121 { 00122 /* Remove it from the Wait List */ 00123 RemoveEntryList(&Timer->WakeTimerListEntry); 00124 Timer->WakeTimerListEntry.Flink = NULL; 00125 } 00126 00127 /* Release the Wake List */ 00128 KeReleaseSpinLock(&ExpWakeListLock, OldIrql); 00129 } 00130 00131 /* Tell the Kernel to cancel the Timer and flush all queued DPCs */ 00132 KeCancelTimer(&Timer->KeTimer); 00133 KeFlushQueuedDpcs(); 00134 } 00135 00136 VOID 00137 NTAPI 00138 ExpTimerDpcRoutine(IN PKDPC Dpc, 00139 IN PVOID DeferredContext, 00140 IN PVOID SystemArgument1, 00141 IN PVOID SystemArgument2) 00142 { 00143 PETIMER Timer = DeferredContext; 00144 BOOLEAN Inserted = FALSE; 00145 00146 /* Reference the timer */ 00147 if (!ObReferenceObjectSafe(Timer)) return; 00148 00149 /* Lock the Timer */ 00150 KeAcquireSpinLockAtDpcLevel(&Timer->Lock); 00151 00152 /* Check if the timer is associated */ 00153 if (Timer->ApcAssociated) 00154 { 00155 /* Queue the APC */ 00156 Inserted = KeInsertQueueApc(&Timer->TimerApc, 00157 SystemArgument1, 00158 SystemArgument2, 00159 IO_NO_INCREMENT); 00160 } 00161 00162 /* Release the Timer */ 00163 KeReleaseSpinLockFromDpcLevel(&Timer->Lock); 00164 00165 /* Dereference it if we couldn't queue the APC */ 00166 if (!Inserted) ObDereferenceObject(Timer); 00167 } 00168 00169 VOID 00170 NTAPI 00171 ExpTimerApcKernelRoutine(IN PKAPC Apc, 00172 IN OUT PKNORMAL_ROUTINE* NormalRoutine, 00173 IN OUT PVOID* NormalContext, 00174 IN OUT PVOID* SystemArgument1, 00175 IN OUT PVOID* SystemArguemnt2) 00176 { 00177 PETIMER Timer; 00178 KIRQL OldIrql; 00179 ULONG DerefsToDo = 1; 00180 PETHREAD Thread = PsGetCurrentThread(); 00181 00182 /* We need to find out which Timer we are */ 00183 Timer = CONTAINING_RECORD(Apc, ETIMER, TimerApc); 00184 00185 /* Lock the Timer */ 00186 KeAcquireSpinLock(&Timer->Lock, &OldIrql); 00187 00188 /* Lock the Thread's Active Timer List*/ 00189 KeAcquireSpinLockAtDpcLevel(&Thread->ActiveTimerListLock); 00190 00191 /* Make sure that the Timer is valid, and that it belongs to this thread */ 00192 if ((Timer->ApcAssociated) && (&Thread->Tcb == Timer->TimerApc.Thread)) 00193 { 00194 /* Check if it's not periodic */ 00195 if (!Timer->Period) 00196 { 00197 /* Remove it from the Active Timers List */ 00198 RemoveEntryList(&Timer->ActiveTimerListEntry); 00199 00200 /* Disable it */ 00201 Timer->ApcAssociated = FALSE; 00202 DerefsToDo++; 00203 } 00204 } 00205 else 00206 { 00207 /* Clear the normal routine */ 00208 *NormalRoutine = NULL; 00209 } 00210 00211 /* Release locks */ 00212 KeReleaseSpinLockFromDpcLevel(&Thread->ActiveTimerListLock); 00213 KeReleaseSpinLock(&Timer->Lock, OldIrql); 00214 00215 /* Dereference as needed */ 00216 ObDereferenceObjectEx(Timer, DerefsToDo); 00217 } 00218 00219 VOID 00220 INIT_FUNCTION 00221 NTAPI 00222 ExpInitializeTimerImplementation(VOID) 00223 { 00224 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; 00225 UNICODE_STRING Name; 00226 00227 /* Create the Timer Object Type */ 00228 RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer)); 00229 RtlInitUnicodeString(&Name, L"Timer"); 00230 ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer); 00231 ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK; 00232 ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(ETIMER); 00233 ObjectTypeInitializer.GenericMapping = ExpTimerMapping; 00234 ObjectTypeInitializer.PoolType = NonPagedPool; 00235 ObjectTypeInitializer.ValidAccessMask = TIMER_ALL_ACCESS; 00236 ObjectTypeInitializer.DeleteProcedure = ExpDeleteTimer; 00237 ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &ExTimerType); 00238 00239 /* Initialize the Wait List and Lock */ 00240 KeInitializeSpinLock(&ExpWakeListLock); 00241 InitializeListHead(&ExpWakeList); 00242 } 00243 00244 /* PUBLIC FUNCTIONS **********************************************************/ 00245 00246 NTSTATUS 00247 NTAPI 00248 NtCancelTimer(IN HANDLE TimerHandle, 00249 OUT PBOOLEAN CurrentState OPTIONAL) 00250 { 00251 PETIMER Timer; 00252 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 00253 BOOLEAN State; 00254 KIRQL OldIrql; 00255 PETHREAD TimerThread; 00256 ULONG DerefsToDo = 1; 00257 NTSTATUS Status; 00258 PAGED_CODE(); 00259 00260 /* Check if we need to probe */ 00261 if ((CurrentState) && (PreviousMode != KernelMode)) 00262 { 00263 _SEH2_TRY 00264 { 00265 /* Make sure the pointer is valid */ 00266 ProbeForWriteBoolean(CurrentState); 00267 } 00268 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 00269 { 00270 /* Return the exception code */ 00271 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 00272 } 00273 _SEH2_END; 00274 } 00275 00276 /* Get the Timer Object */ 00277 Status = ObReferenceObjectByHandle(TimerHandle, 00278 TIMER_MODIFY_STATE, 00279 ExTimerType, 00280 PreviousMode, 00281 (PVOID*)&Timer, 00282 NULL); 00283 if (NT_SUCCESS(Status)) 00284 { 00285 /* Lock the Timer */ 00286 KeAcquireSpinLock(&Timer->Lock, &OldIrql); 00287 00288 /* Check if it's enabled */ 00289 if (Timer->ApcAssociated) 00290 { 00291 /* Get the Thread. */ 00292 TimerThread = CONTAINING_RECORD(Timer->TimerApc.Thread, 00293 ETHREAD, 00294 Tcb); 00295 00296 /* Lock its active list */ 00297 KeAcquireSpinLockAtDpcLevel(&TimerThread->ActiveTimerListLock); 00298 00299 /* Remove it */ 00300 RemoveEntryList(&TimerThread->ActiveTimerListHead); 00301 Timer->ApcAssociated = FALSE; 00302 00303 /* Unlock the list */ 00304 KeReleaseSpinLockFromDpcLevel(&TimerThread->ActiveTimerListLock); 00305 00306 /* Cancel the Timer */ 00307 KeCancelTimer(&Timer->KeTimer); 00308 KeRemoveQueueDpc(&Timer->TimerDpc); 00309 if (KeRemoveQueueApc(&Timer->TimerApc)) DerefsToDo++; 00310 DerefsToDo++; 00311 } 00312 else 00313 { 00314 /* If timer was disabled, we still need to cancel it */ 00315 KeCancelTimer(&Timer->KeTimer); 00316 } 00317 00318 /* Handle a Wake Timer */ 00319 if (Timer->WakeTimerListEntry.Flink) 00320 { 00321 /* Lock the Wake List */ 00322 KeAcquireSpinLockAtDpcLevel(&ExpWakeListLock); 00323 00324 /* Check again, since it might've changed before we locked */ 00325 if (Timer->WakeTimerListEntry.Flink) 00326 { 00327 /* Remove it from the Wait List */ 00328 RemoveEntryList(&Timer->WakeTimerListEntry); 00329 Timer->WakeTimerListEntry.Flink = NULL; 00330 } 00331 00332 /* Release the Wake List */ 00333 KeReleaseSpinLockFromDpcLevel(&ExpWakeListLock); 00334 } 00335 00336 /* Unlock the Timer */ 00337 KeReleaseSpinLock(&Timer->Lock, OldIrql); 00338 00339 /* Read the old State */ 00340 State = KeReadStateTimer(&Timer->KeTimer); 00341 00342 /* Dereference the Object */ 00343 ObDereferenceObjectEx(Timer, DerefsToDo); 00344 00345 /* Check if caller wants the state */ 00346 if (CurrentState) 00347 { 00348 _SEH2_TRY 00349 { 00350 /* Return the Timer State */ 00351 *CurrentState = State; 00352 } 00353 _SEH2_EXCEPT(ExSystemExceptionFilter()) 00354 { 00355 00356 } 00357 _SEH2_END; 00358 } 00359 } 00360 00361 /* Return to Caller */ 00362 return Status; 00363 } 00364 00365 NTSTATUS 00366 NTAPI 00367 NtCreateTimer(OUT PHANDLE TimerHandle, 00368 IN ACCESS_MASK DesiredAccess, 00369 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, 00370 IN TIMER_TYPE TimerType) 00371 { 00372 PETIMER Timer; 00373 HANDLE hTimer; 00374 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 00375 NTSTATUS Status; 00376 PAGED_CODE(); 00377 00378 /* Check for correct timer type */ 00379 if ((TimerType != NotificationTimer) && 00380 (TimerType != SynchronizationTimer)) 00381 { 00382 /* Fail */ 00383 return STATUS_INVALID_PARAMETER_4; 00384 } 00385 00386 /* Check if we need to probe */ 00387 if (PreviousMode != KernelMode) 00388 { 00389 _SEH2_TRY 00390 { 00391 /* Make sure the pointer is valid */ 00392 ProbeForWriteHandle(TimerHandle); 00393 } 00394 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 00395 { 00396 /* Return the exception code */ 00397 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 00398 } 00399 _SEH2_END; 00400 } 00401 00402 /* Create the Object */ 00403 Status = ObCreateObject(PreviousMode, 00404 ExTimerType, 00405 ObjectAttributes, 00406 PreviousMode, 00407 NULL, 00408 sizeof(ETIMER), 00409 0, 00410 0, 00411 (PVOID*)&Timer); 00412 if (NT_SUCCESS(Status)) 00413 { 00414 /* Initialize the DPC */ 00415 KeInitializeDpc(&Timer->TimerDpc, ExpTimerDpcRoutine, Timer); 00416 00417 /* Initialize the Kernel Timer */ 00418 KeInitializeTimerEx(&Timer->KeTimer, TimerType); 00419 00420 /* Initialize the timer fields */ 00421 KeInitializeSpinLock(&Timer->Lock); 00422 Timer->ApcAssociated = FALSE; 00423 Timer->WakeTimer = FALSE; 00424 Timer->WakeTimerListEntry.Flink = NULL; 00425 00426 /* Insert the Timer */ 00427 Status = ObInsertObject((PVOID)Timer, 00428 NULL, 00429 DesiredAccess, 00430 0, 00431 NULL, 00432 &hTimer); 00433 00434 /* Check for success */ 00435 if (NT_SUCCESS(Status)) 00436 { 00437 /* Enter SEH */ 00438 _SEH2_TRY 00439 { 00440 /* Return the Timer Handle */ 00441 *TimerHandle = hTimer; 00442 } 00443 _SEH2_EXCEPT(ExSystemExceptionFilter()) 00444 { 00445 00446 } 00447 _SEH2_END; 00448 } 00449 } 00450 00451 /* Return to Caller */ 00452 return Status; 00453 } 00454 00455 NTSTATUS 00456 NTAPI 00457 NtOpenTimer(OUT PHANDLE TimerHandle, 00458 IN ACCESS_MASK DesiredAccess, 00459 IN POBJECT_ATTRIBUTES ObjectAttributes) 00460 { 00461 HANDLE hTimer; 00462 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 00463 NTSTATUS Status; 00464 PAGED_CODE(); 00465 00466 /* Check Parameter Validity */ 00467 if (PreviousMode != KernelMode) 00468 { 00469 _SEH2_TRY 00470 { 00471 /* Make sure the pointer is valid */ 00472 ProbeForWriteHandle(TimerHandle); 00473 } 00474 _SEH2_EXCEPT(ExSystemExceptionFilter()) 00475 { 00476 /* Return the exception code */ 00477 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 00478 } 00479 _SEH2_END; 00480 } 00481 00482 /* Open the Timer */ 00483 Status = ObOpenObjectByName(ObjectAttributes, 00484 ExTimerType, 00485 PreviousMode, 00486 NULL, 00487 DesiredAccess, 00488 NULL, 00489 &hTimer); 00490 if (NT_SUCCESS(Status)) 00491 { 00492 /* Enter SEH */ 00493 _SEH2_TRY 00494 { 00495 /* Return the Timer Handle */ 00496 *TimerHandle = hTimer; 00497 } 00498 _SEH2_EXCEPT(ExSystemExceptionFilter()) 00499 { 00500 00501 } 00502 _SEH2_END; 00503 } 00504 00505 /* Return to Caller */ 00506 return Status; 00507 } 00508 00509 NTSTATUS 00510 NTAPI 00511 NtQueryTimer(IN HANDLE TimerHandle, 00512 IN TIMER_INFORMATION_CLASS TimerInformationClass, 00513 OUT PVOID TimerInformation, 00514 IN ULONG TimerInformationLength, 00515 OUT PULONG ReturnLength OPTIONAL) 00516 { 00517 PETIMER Timer; 00518 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 00519 NTSTATUS Status; 00520 PTIMER_BASIC_INFORMATION BasicInfo = TimerInformation; 00521 PAGED_CODE(); 00522 00523 /* Check Validity */ 00524 Status = DefaultQueryInfoBufferCheck(TimerInformationClass, 00525 ExTimerInfoClass, 00526 sizeof(ExTimerInfoClass) / 00527 sizeof(ExTimerInfoClass[0]), 00528 TimerInformation, 00529 TimerInformationLength, 00530 ReturnLength, 00531 NULL, 00532 PreviousMode); 00533 if (!NT_SUCCESS(Status)) return Status; 00534 00535 /* Get the Timer Object */ 00536 Status = ObReferenceObjectByHandle(TimerHandle, 00537 TIMER_QUERY_STATE, 00538 ExTimerType, 00539 PreviousMode, 00540 (PVOID*)&Timer, 00541 NULL); 00542 if (NT_SUCCESS(Status)) 00543 { 00544 /* Return the Basic Information */ 00545 _SEH2_TRY 00546 { 00547 /* Return the remaining time, corrected */ 00548 BasicInfo->TimeRemaining.QuadPart = Timer-> 00549 KeTimer.DueTime.QuadPart - 00550 KeQueryInterruptTime(); 00551 00552 /* Return the current state */ 00553 BasicInfo->SignalState = KeReadStateTimer(&Timer->KeTimer); 00554 00555 /* Return the buffer length if requested */ 00556 if (ReturnLength) *ReturnLength = sizeof(TIMER_BASIC_INFORMATION); 00557 } 00558 _SEH2_EXCEPT(ExSystemExceptionFilter()) 00559 { 00560 /* Get the exception code */ 00561 Status = _SEH2_GetExceptionCode(); 00562 } 00563 _SEH2_END; 00564 00565 /* Dereference Object */ 00566 ObDereferenceObject(Timer); 00567 } 00568 00569 /* Return Status */ 00570 return Status; 00571 } 00572 00573 NTSTATUS 00574 NTAPI 00575 NtSetTimer(IN HANDLE TimerHandle, 00576 IN PLARGE_INTEGER DueTime, 00577 IN PTIMER_APC_ROUTINE TimerApcRoutine OPTIONAL, 00578 IN PVOID TimerContext OPTIONAL, 00579 IN BOOLEAN WakeTimer, 00580 IN LONG Period OPTIONAL, 00581 OUT PBOOLEAN PreviousState OPTIONAL) 00582 { 00583 PETIMER Timer; 00584 KIRQL OldIrql; 00585 BOOLEAN State; 00586 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 00587 PETHREAD Thread = PsGetCurrentThread(); 00588 LARGE_INTEGER TimerDueTime; 00589 PETHREAD TimerThread; 00590 ULONG DerefsToDo = 1; 00591 NTSTATUS Status = STATUS_SUCCESS; 00592 PAGED_CODE(); 00593 00594 /* Check for a valid Period */ 00595 if (Period < 0) return STATUS_INVALID_PARAMETER_6; 00596 00597 /* Check if we need to probe */ 00598 if (PreviousMode != KernelMode) 00599 { 00600 _SEH2_TRY 00601 { 00602 /* Probe and capture the due time */ 00603 TimerDueTime = ProbeForReadLargeInteger(DueTime); 00604 00605 /* Probe the state pointer if one was passed */ 00606 if (PreviousState) ProbeForWriteBoolean(PreviousState); 00607 } 00608 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 00609 { 00610 /* Return the exception code */ 00611 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 00612 } 00613 _SEH2_END; 00614 } 00615 else 00616 { 00617 /* Capture the time directly */ 00618 TimerDueTime = *DueTime; 00619 } 00620 00621 /* Get the Timer Object */ 00622 Status = ObReferenceObjectByHandle(TimerHandle, 00623 TIMER_MODIFY_STATE, 00624 ExTimerType, 00625 PreviousMode, 00626 (PVOID*)&Timer, 00627 NULL); 00628 00629 /* 00630 * Tell the user we don't support Wake Timers... 00631 * when we have the ability to use/detect the Power Management 00632 * functionality required to support them, make this check dependent 00633 * on the actual PM capabilities 00634 */ 00635 if (WakeTimer) Status = STATUS_TIMER_RESUME_IGNORED; 00636 00637 /* Check status */ 00638 if (NT_SUCCESS(Status)) 00639 { 00640 /* Lock the Timer */ 00641 KeAcquireSpinLock(&Timer->Lock, &OldIrql); 00642 00643 /* Cancel Running Timer */ 00644 if (Timer->ApcAssociated) 00645 { 00646 /* Get the Thread. */ 00647 TimerThread = CONTAINING_RECORD(Timer->TimerApc.Thread, 00648 ETHREAD, 00649 Tcb); 00650 00651 /* Lock its active list */ 00652 KeAcquireSpinLockAtDpcLevel(&TimerThread->ActiveTimerListLock); 00653 00654 /* Remove it */ 00655 RemoveEntryList(&TimerThread->ActiveTimerListHead); 00656 Timer->ApcAssociated = FALSE; 00657 00658 /* Unlock the list */ 00659 KeReleaseSpinLockFromDpcLevel(&TimerThread->ActiveTimerListLock); 00660 00661 /* Cancel the Timer */ 00662 KeCancelTimer(&Timer->KeTimer); 00663 KeRemoveQueueDpc(&Timer->TimerDpc); 00664 if (KeRemoveQueueApc(&Timer->TimerApc)) DerefsToDo++; 00665 DerefsToDo++; 00666 } 00667 else 00668 { 00669 /* If timer was disabled, we still need to cancel it */ 00670 KeCancelTimer(&Timer->KeTimer); 00671 } 00672 00673 /* Read the State */ 00674 State = KeReadStateTimer(&Timer->KeTimer); 00675 00676 /* Handle Wake Timers */ 00677 Timer->WakeTimer = WakeTimer; 00678 KeAcquireSpinLockAtDpcLevel(&ExpWakeListLock); 00679 if ((WakeTimer) && !(Timer->WakeTimerListEntry.Flink)) 00680 { 00681 /* Insert it into the list */ 00682 InsertTailList(&ExpWakeList, &Timer->WakeTimerListEntry); 00683 } 00684 else if (!(WakeTimer) && (Timer->WakeTimerListEntry.Flink)) 00685 { 00686 /* Remove it from the list */ 00687 RemoveEntryList(&Timer->WakeTimerListEntry); 00688 Timer->WakeTimerListEntry.Flink = NULL; 00689 } 00690 KeReleaseSpinLockFromDpcLevel(&ExpWakeListLock); 00691 00692 /* Set up the APC Routine if specified */ 00693 Timer->Period = Period; 00694 if (TimerApcRoutine) 00695 { 00696 /* Initialize the APC */ 00697 KeInitializeApc(&Timer->TimerApc, 00698 &Thread->Tcb, 00699 CurrentApcEnvironment, 00700 ExpTimerApcKernelRoutine, 00701 (PKRUNDOWN_ROUTINE)NULL, 00702 (PKNORMAL_ROUTINE)TimerApcRoutine, 00703 PreviousMode, 00704 TimerContext); 00705 00706 /* Lock the Thread's Active List and Insert */ 00707 KeAcquireSpinLockAtDpcLevel(&Thread->ActiveTimerListLock); 00708 InsertTailList(&Thread->ActiveTimerListHead, 00709 &Timer->ActiveTimerListEntry); 00710 Timer->ApcAssociated = TRUE; 00711 KeReleaseSpinLockFromDpcLevel(&Thread->ActiveTimerListLock); 00712 00713 /* One less dereference to do */ 00714 DerefsToDo--; 00715 } 00716 00717 /* Enable and Set the Timer */ 00718 KeSetTimerEx(&Timer->KeTimer, 00719 TimerDueTime, 00720 Period, 00721 TimerApcRoutine ? &Timer->TimerDpc : NULL); 00722 00723 /* Unlock the Timer */ 00724 KeReleaseSpinLock(&Timer->Lock, OldIrql); 00725 00726 /* Dereference if it was previously enabled */ 00727 if (DerefsToDo) ObDereferenceObjectEx(Timer, DerefsToDo); 00728 00729 /* Check if we need to return the State */ 00730 if (PreviousState) 00731 { 00732 /* Enter SEH */ 00733 _SEH2_TRY 00734 { 00735 /* Return the Timer State */ 00736 *PreviousState = State; 00737 } 00738 _SEH2_EXCEPT(ExSystemExceptionFilter()) 00739 { 00740 00741 } 00742 _SEH2_END; 00743 } 00744 } 00745 00746 /* Return to Caller */ 00747 return Status; 00748 } Generated on Sun May 27 2012 04:18:16 for ReactOS by
1.7.6.1
|