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