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