- Move the code from my previous commit before signalling the user event
[reactos.git] / reactos / ntoskrnl / io / iomgr / iotimer.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/iocomp.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 */