xref: /reactos/ntoskrnl/io/iomgr/iotimer.c (revision 4585372c)
1c2c66affSColin Finck /*
2c2c66affSColin Finck  * PROJECT:         ReactOS Kernel
3c2c66affSColin Finck  * LICENSE:         GPL - See COPYING in the top level directory
4c2c66affSColin Finck  * FILE:            ntoskrnl/io/iomgr/iotimer.c
5c2c66affSColin Finck  * PURPOSE:         I/O Wrappers for Executive Timers
6c2c66affSColin Finck  * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
7c2c66affSColin Finck  */
8c2c66affSColin Finck 
9c2c66affSColin Finck /* INCLUDES *****************************************************************/
10c2c66affSColin Finck 
11c2c66affSColin Finck #include <ntoskrnl.h>
12c2c66affSColin Finck #define NDEBUG
13c2c66affSColin Finck #include <debug.h>
14c2c66affSColin Finck 
15c2c66affSColin Finck /* GLOBALS *******************************************************************/
16c2c66affSColin Finck 
17c2c66affSColin Finck /* Timer Database */
18c2c66affSColin Finck KSPIN_LOCK IopTimerLock;
19c2c66affSColin Finck LIST_ENTRY IopTimerQueueHead;
20c2c66affSColin Finck 
21c2c66affSColin Finck /* Timer Firing */
22c2c66affSColin Finck KDPC IopTimerDpc;
23c2c66affSColin Finck KTIMER IopTimer;
24c2c66affSColin Finck 
25c2c66affSColin Finck /* Keep count of how many timers we have */
26c2c66affSColin Finck ULONG IopTimerCount = 0;
27c2c66affSColin Finck 
28c2c66affSColin Finck /* PRIVATE FUNCTIONS *********************************************************/
29c2c66affSColin Finck 
30c2c66affSColin Finck VOID
31c2c66affSColin Finck NTAPI
IopTimerDispatch(IN PKDPC Dpc,IN PVOID DeferredContext,IN PVOID SystemArgument1,IN PVOID SystemArgument2)32c2c66affSColin Finck IopTimerDispatch(IN PKDPC Dpc,
33c2c66affSColin Finck                  IN PVOID DeferredContext,
34c2c66affSColin Finck                  IN PVOID SystemArgument1,
35c2c66affSColin Finck                  IN PVOID SystemArgument2)
36c2c66affSColin Finck {
37c2c66affSColin Finck     KIRQL OldIrql;
38c2c66affSColin Finck     PLIST_ENTRY TimerEntry;
39c2c66affSColin Finck     PIO_TIMER Timer;
40c2c66affSColin Finck     ULONG i;
41c2c66affSColin Finck 
42*4585372cSHermès Bélusca-Maïto     /* Check if any Timers are actually enabled as of now */
43c2c66affSColin Finck     if (IopTimerCount)
44c2c66affSColin Finck     {
45c2c66affSColin Finck         /* Lock the Timers */
46c2c66affSColin Finck         KeAcquireSpinLock(&IopTimerLock, &OldIrql);
47c2c66affSColin Finck 
48c2c66affSColin Finck         /* Call the Timer Routine of each enabled Timer */
49c2c66affSColin Finck         for (TimerEntry = IopTimerQueueHead.Flink, i = IopTimerCount;
50c2c66affSColin Finck             (TimerEntry != &IopTimerQueueHead) && i;
51c2c66affSColin Finck             TimerEntry = TimerEntry->Flink)
52c2c66affSColin Finck         {
53c2c66affSColin Finck             /* Get the timer and check if it's enabled */
54c2c66affSColin Finck             Timer = CONTAINING_RECORD(TimerEntry, IO_TIMER, IoTimerList);
55c2c66affSColin Finck             if (Timer->TimerEnabled)
56c2c66affSColin Finck             {
57c2c66affSColin Finck                 /* Call the timer routine */
58c2c66affSColin Finck                 Timer->TimerRoutine(Timer->DeviceObject, Timer->Context);
59c2c66affSColin Finck                 i--;
60c2c66affSColin Finck             }
61c2c66affSColin Finck         }
62c2c66affSColin Finck 
63c2c66affSColin Finck         /* Unlock the Timers */
64c2c66affSColin Finck         KeReleaseSpinLock(&IopTimerLock, OldIrql);
65c2c66affSColin Finck     }
66c2c66affSColin Finck }
67c2c66affSColin Finck 
68c2c66affSColin Finck VOID
69c2c66affSColin Finck NTAPI
IopRemoveTimerFromTimerList(IN PIO_TIMER Timer)70c2c66affSColin Finck IopRemoveTimerFromTimerList(IN PIO_TIMER Timer)
71c2c66affSColin Finck {
72c2c66affSColin Finck     KIRQL OldIrql;
73c2c66affSColin Finck 
74c2c66affSColin Finck     /* Lock Timers */
75c2c66affSColin Finck     KeAcquireSpinLock(&IopTimerLock, &OldIrql);
76c2c66affSColin Finck 
77c2c66affSColin Finck     /* Remove Timer from the List and Drop the Timer Count if Enabled */
78c2c66affSColin Finck     RemoveEntryList(&Timer->IoTimerList);
79c2c66affSColin Finck     if (Timer->TimerEnabled) IopTimerCount--;
80c2c66affSColin Finck 
81c2c66affSColin Finck     /* Unlock the Timers */
82c2c66affSColin Finck     KeReleaseSpinLock(&IopTimerLock, OldIrql);
83c2c66affSColin Finck }
84c2c66affSColin Finck 
85c2c66affSColin Finck /* PUBLIC FUNCTIONS **********************************************************/
86c2c66affSColin Finck 
87c2c66affSColin Finck /*
88c2c66affSColin Finck  * @implemented
89c2c66affSColin Finck  */
90c2c66affSColin Finck NTSTATUS
91c2c66affSColin Finck NTAPI
IoInitializeTimer(IN PDEVICE_OBJECT DeviceObject,IN PIO_TIMER_ROUTINE TimerRoutine,IN PVOID Context)92c2c66affSColin Finck IoInitializeTimer(IN PDEVICE_OBJECT DeviceObject,
93c2c66affSColin Finck                   IN PIO_TIMER_ROUTINE TimerRoutine,
94c2c66affSColin Finck                   IN PVOID Context)
95c2c66affSColin Finck {
96c2c66affSColin Finck     PIO_TIMER IoTimer = DeviceObject->Timer;
97c2c66affSColin Finck     PAGED_CODE();
98c2c66affSColin Finck 
99c2c66affSColin Finck     /* Check if we don't have a timer yet */
100c2c66affSColin Finck     if (!IoTimer)
101c2c66affSColin Finck     {
102c2c66affSColin Finck         /* Allocate Timer */
103c2c66affSColin Finck         IoTimer = ExAllocatePoolWithTag(NonPagedPool,
104c2c66affSColin Finck                                         sizeof(IO_TIMER),
105c2c66affSColin Finck                                         TAG_IO_TIMER);
106c2c66affSColin Finck         if (!IoTimer) return STATUS_INSUFFICIENT_RESOURCES;
107c2c66affSColin Finck 
108c2c66affSColin Finck         /* Set up the Timer Structure */
109c2c66affSColin Finck         RtlZeroMemory(IoTimer, sizeof(IO_TIMER));
110c2c66affSColin Finck         IoTimer->Type = IO_TYPE_TIMER;
111c2c66affSColin Finck         IoTimer->DeviceObject = DeviceObject;
112c2c66affSColin Finck         DeviceObject->Timer = IoTimer;
113c2c66affSColin Finck     }
114c2c66affSColin Finck 
115c2c66affSColin Finck     /* Setup the timer routine and context */
116c2c66affSColin Finck     IoTimer->TimerRoutine = TimerRoutine;
117c2c66affSColin Finck     IoTimer->Context = Context;
118c2c66affSColin Finck 
119c2c66affSColin Finck     /* Add it to the Timer List */
120c2c66affSColin Finck     ExInterlockedInsertTailList(&IopTimerQueueHead,
121c2c66affSColin Finck                                 &IoTimer->IoTimerList,
122c2c66affSColin Finck                                 &IopTimerLock);
123c2c66affSColin Finck 
124c2c66affSColin Finck     /* Return Success */
125c2c66affSColin Finck     return STATUS_SUCCESS;
126c2c66affSColin Finck }
127c2c66affSColin Finck 
128c2c66affSColin Finck /*
129c2c66affSColin Finck  * @implemented
130c2c66affSColin Finck  */
131c2c66affSColin Finck VOID
132c2c66affSColin Finck NTAPI
IoStartTimer(IN PDEVICE_OBJECT DeviceObject)133c2c66affSColin Finck IoStartTimer(IN PDEVICE_OBJECT DeviceObject)
134c2c66affSColin Finck {
135c2c66affSColin Finck     KIRQL OldIrql;
136c2c66affSColin Finck     PIO_TIMER IoTimer = DeviceObject->Timer;
137c2c66affSColin Finck 
138c2c66affSColin Finck     /* Make sure the device isn't unloading */
139c2c66affSColin Finck     if (!(((PEXTENDED_DEVOBJ_EXTENSION)(DeviceObject->DeviceObjectExtension))->
140c2c66affSColin Finck             ExtensionFlags & (DOE_UNLOAD_PENDING |
141c2c66affSColin Finck                               DOE_DELETE_PENDING |
142c2c66affSColin Finck                               DOE_REMOVE_PENDING |
143c2c66affSColin Finck                               DOE_REMOVE_PROCESSED)))
144c2c66affSColin Finck     {
145c2c66affSColin Finck         /* Lock Timers */
146c2c66affSColin Finck         KeAcquireSpinLock(&IopTimerLock, &OldIrql);
147c2c66affSColin Finck 
148c2c66affSColin Finck         /* Check if the timer isn't already enabled */
149c2c66affSColin Finck         if (!IoTimer->TimerEnabled)
150c2c66affSColin Finck         {
151c2c66affSColin Finck             /* Enable it and increase the timer count */
152c2c66affSColin Finck             IoTimer->TimerEnabled = TRUE;
153c2c66affSColin Finck             IopTimerCount++;
154c2c66affSColin Finck         }
155c2c66affSColin Finck 
156c2c66affSColin Finck         /* Unlock Timers */
157c2c66affSColin Finck         KeReleaseSpinLock(&IopTimerLock, OldIrql);
158c2c66affSColin Finck     }
159c2c66affSColin Finck }
160c2c66affSColin Finck 
161c2c66affSColin Finck /*
162c2c66affSColin Finck  * @implemented
163c2c66affSColin Finck  */
164c2c66affSColin Finck VOID
165c2c66affSColin Finck NTAPI
IoStopTimer(PDEVICE_OBJECT DeviceObject)166c2c66affSColin Finck IoStopTimer(PDEVICE_OBJECT DeviceObject)
167c2c66affSColin Finck {
168c2c66affSColin Finck     KIRQL OldIrql;
169c2c66affSColin Finck     PIO_TIMER IoTimer = DeviceObject->Timer;
170c2c66affSColin Finck 
171c2c66affSColin Finck     /* Lock Timers */
172c2c66affSColin Finck     KeAcquireSpinLock(&IopTimerLock, &OldIrql);
173c2c66affSColin Finck 
174c2c66affSColin Finck     /* Check if the timer is enabled */
175c2c66affSColin Finck     if (IoTimer->TimerEnabled)
176c2c66affSColin Finck     {
177c2c66affSColin Finck         /* Disable it and decrease the timer count */
178c2c66affSColin Finck         IoTimer->TimerEnabled = FALSE;
179c2c66affSColin Finck         IopTimerCount--;
180c2c66affSColin Finck     }
181c2c66affSColin Finck 
182c2c66affSColin Finck     /* Unlock Timers */
183c2c66affSColin Finck     KeReleaseSpinLock(&IopTimerLock, OldIrql);
184c2c66affSColin Finck }
185c2c66affSColin Finck 
186c2c66affSColin Finck /* EOF */
187