ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

timer.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.