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

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

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