6fe893b4116eac9a886d71ae809bf201771e70a3
[reactos.git] / reactos / ntoskrnl / io / timer.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/io/timer.c
5 * PURPOSE: io timers
6 * PROGRAMMER: David Welch (welch@mcmail.com)
7 * UPDATE HISTORY:
8 * Created 22/05/98
9 * Reimplemented 05/11/04 - Alex Ionescu (alex@relsoft.net)
10 */
11
12 /* INCLUDES *****************************************************************/
13
14 #include <ntoskrnl.h>
15 #define NDEBUG
16 #include <internal/debug.h>
17
18 /* GLOBALS *******************************************************************/
19
20 #define TAG_IO_TIMER TAG('I', 'O', 'T', 'M')
21
22 /* Timer Database */
23 KSPIN_LOCK IopTimerLock;
24 LIST_ENTRY IopTimerQueueHead;
25
26 /* Timer Firing */
27 KDPC IopTimerDpc;
28 KTIMER IopTimer;
29
30 /* Keep count of how many timers we have */
31 ULONG IopTimerCount = 0;
32
33 /* FUNCTIONS *****************************************************************/
34
35 static VOID STDCALL
36 IopTimerDispatch(IN PKDPC Dpc,
37 IN PVOID DeferredContext,
38 IN PVOID SystemArgument1,
39 IN PVOID SystemArgument2)
40 {
41 KIRQL OldIrql;
42 PLIST_ENTRY TimerEntry;
43 PIO_TIMER Timer;
44 ULONG i;
45
46 DPRINT("Dispatching IO Timers. There are: %x \n", IopTimerCount);
47
48 /* Check if any Timers are actualyl enabled as of now */
49 if (IopTimerCount) {
50
51 /* Lock the Timers */
52 KeAcquireSpinLock(&IopTimerLock, &OldIrql);
53
54 /* Call the Timer Routine of each enabled Timer */
55 for(TimerEntry = IopTimerQueueHead.Flink, i = IopTimerCount;
56 (TimerEntry != &IopTimerQueueHead) && i;
57 TimerEntry = TimerEntry->Flink) {
58
59 Timer = CONTAINING_RECORD(TimerEntry, IO_TIMER, IoTimerList);
60 if (Timer->TimerEnabled) {
61 DPRINT("Dispatching a Timer Routine: %x for Device Object: %x \n",
62 Timer->TimerRoutine,
63 Timer->DeviceObject);
64 Timer->TimerRoutine(Timer->DeviceObject, Timer->Context);
65 i--;
66 }
67 }
68
69 /* Unlock the Timers */
70 KeReleaseSpinLock(&IopTimerLock, OldIrql);
71 }
72 }
73
74 VOID
75 STDCALL
76 IopRemoveTimerFromTimerList(
77 IN PIO_TIMER Timer
78 )
79 {
80 KIRQL OldIrql;
81
82 /* Lock Timers */
83 KeAcquireSpinLock(&IopTimerLock, &OldIrql);
84
85 /* Remove Timer from the List and Drop the Timer Count if Enabled */
86 RemoveEntryList(&Timer->IoTimerList);
87 if (Timer->TimerEnabled) IopTimerCount--;
88
89 /* Unlock the Timers */
90 KeReleaseSpinLock(&IopTimerLock, OldIrql);
91 }
92
93 VOID
94 FASTCALL
95 IopInitTimerImplementation(VOID)
96 /* FUNCTION: Initializes the IO Timer Object Implementation
97 * RETURNS: NOTHING
98 */
99 {
100 LARGE_INTEGER ExpireTime;
101
102 /* Initialize Timer List Lock */
103 KeInitializeSpinLock(&IopTimerLock);
104
105 /* Initialize Timer List */
106 InitializeListHead(&IopTimerQueueHead);
107
108 /* Initialize the DPC/Timer which will call the other Timer Routines */
109 ExpireTime.QuadPart = -10000000;
110 KeInitializeDpc(&IopTimerDpc, IopTimerDispatch, NULL);
111 KeInitializeTimerEx(&IopTimer, SynchronizationTimer);
112 KeSetTimerEx(&IopTimer, ExpireTime, 1000, &IopTimerDpc);
113 }
114
115 /*
116 * @implemented
117 */
118 NTSTATUS
119 STDCALL
120 IoInitializeTimer(PDEVICE_OBJECT DeviceObject,
121 PIO_TIMER_ROUTINE TimerRoutine,
122 PVOID Context)
123 /*
124 * FUNCTION: Sets up a driver-supplied IoTimer routine associated with a given
125 * device object
126 * ARGUMENTS:
127 * DeviceObject = Device object whose timer is be initialized
128 * TimerRoutine = Driver supplied routine which will be called once per
129 * second if the timer is active
130 * Context = Driver supplied context to be passed to the TimerRoutine
131 * RETURNS: Status
132 */
133 {
134 DPRINT("IoInitializeTimer() called for Device Object: %x with Routine: %x \n", DeviceObject, TimerRoutine);
135
136 /* Allocate Timer */
137 if (!DeviceObject->Timer) {
138 DeviceObject->Timer = ExAllocatePoolWithTag(NonPagedPool,
139 sizeof(IO_TIMER),
140 TAG_IO_TIMER);
141 if (!DeviceObject->Timer) return STATUS_INSUFFICIENT_RESOURCES;
142
143 /* Set up the Timer Structure */
144 DeviceObject->Timer->Type = IO_TYPE_TIMER;
145 DeviceObject->Timer->DeviceObject = DeviceObject;
146 }
147
148 DeviceObject->Timer->TimerRoutine = TimerRoutine;
149 DeviceObject->Timer->Context = Context;
150 DeviceObject->Timer->TimerEnabled = FALSE;
151
152 /* Add it to the Timer List */
153 ExInterlockedInsertTailList(&IopTimerQueueHead,
154 &DeviceObject->Timer->IoTimerList,
155 &IopTimerLock);
156
157 /* Return Success */
158 DPRINT("IoInitializeTimer() Completed\n");
159 return(STATUS_SUCCESS);
160 }
161
162 /*
163 * @implemented
164 */
165 VOID
166 STDCALL
167 IoStartTimer(PDEVICE_OBJECT DeviceObject)
168 /*
169 * FUNCTION: Starts a timer so the driver-supplied IoTimer routine will be
170 * called once per second
171 * ARGUMENTS:
172 * DeviceObject = Device whose timer is to be started
173 */
174 {
175 KIRQL OldIrql;
176
177 DPRINT("IoStartTimer for Device Object: %x\n", DeviceObject);
178
179 /* Lock Timers */
180 KeAcquireSpinLock(&IopTimerLock, &OldIrql);
181
182 /* If the timer isn't already enabled, enable it and increase IO Timer Count*/
183 if (!DeviceObject->Timer->TimerEnabled) {
184 DeviceObject->Timer->TimerEnabled = TRUE;
185 IopTimerCount++;
186 }
187
188 /* Unlock Timers */
189 KeReleaseSpinLock(&IopTimerLock, OldIrql);
190 DPRINT("IoStartTimer Completed for Device Object: %x New Count: %x \n", DeviceObject, IopTimerCount);
191 }
192
193 /*
194 * @implemented
195 */
196 VOID
197 STDCALL
198 IoStopTimer(PDEVICE_OBJECT DeviceObject)
199 /*
200 * FUNCTION: Disables for a specified device object so the driver-supplied
201 * IoTimer is not called
202 * ARGUMENTS:
203 * DeviceObject = Device whose timer is to be stopped
204 */
205 {
206 KIRQL OldIrql;
207
208 DPRINT("IoStopTimer for Device Object: %x\n", DeviceObject);
209
210 /* Lock Timers */
211 KeAcquireSpinLock(&IopTimerLock, &OldIrql);
212
213 /* If the timer is enabled, disable it and decrease IO Timer Count*/
214 if (DeviceObject->Timer->TimerEnabled) {
215 DeviceObject->Timer->TimerEnabled = FALSE;
216 IopTimerCount--;
217 }
218
219 /* Unlock Timers */
220 KeReleaseSpinLock(&IopTimerLock, OldIrql);
221 DPRINT("IoStopTimer Completed for Device Object: %x New Count: %x \n", DeviceObject, IopTimerCount);
222 }
223
224
225 /* EOF */