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