Of course, I forgot to commit the new file in revision 22049...
[reactos.git] / reactos / ntoskrnl / ke / kqueue.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PURPOSE: ReactOS kernel
4 * FILE: ntoskrnl/ke/kqueue.c
5 * PURPOSE: Implement device queues
6 *
7 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) - Several optimizations and implement
8 * usage of Inserted flag + reformat and
9 * add debug output.
10 * David Welch (welch@mcmail.com)
11 */
12
13 /* INCLUDES ****************************************************************/
14
15 #include <ntoskrnl.h>
16 #define NDEBUG
17 #include <internal/debug.h>
18
19 /* FUNCTIONS *****************************************************************/
20
21 /*
22 * @implemented
23 *
24 * FUNCTION: Intializes a device queue
25 * ARGUMENTS:
26 * DeviceQueue = Device queue to initialize
27 */
28 VOID
29 STDCALL
30 KeInitializeDeviceQueue(IN PKDEVICE_QUEUE DeviceQueue)
31 {
32
33 /* Initialize the Header */
34 DeviceQueue->Type = DeviceQueueObject;
35 DeviceQueue->Size = sizeof(KDEVICE_QUEUE);
36
37 /* Initialize the Listhead and Spinlock */
38 InitializeListHead(&DeviceQueue->DeviceListHead);
39 KeInitializeSpinLock(&DeviceQueue->Lock);
40
41 /* Set it as busy */
42 DeviceQueue->Busy=FALSE;
43 }
44
45 /*
46 * @implemented
47 *
48 * FUNCTION: Inserts an entry in a device queue
49 * ARGUMENTS:
50 * DeviceQueue = Queue to insert the entry in
51 * DeviceQueueEntry = Entry to insert
52 * RETURNS: False is the device queue wasn't busy
53 * True otherwise
54 */
55 BOOLEAN
56 STDCALL
57 KeInsertDeviceQueue(IN PKDEVICE_QUEUE DeviceQueue,
58 IN PKDEVICE_QUEUE_ENTRY DeviceQueueEntry)
59 {
60 BOOLEAN Inserted;
61
62 DPRINT("KeInsertDeviceQueue(DeviceQueue %x)\n", DeviceQueue);
63 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
64
65 /* Lock the Queue */
66 KeAcquireSpinLockAtDpcLevel(&DeviceQueue->Lock);
67
68 if (!DeviceQueue->Busy) {
69
70 /* Set it as busy */
71 Inserted = FALSE;
72 DeviceQueue->Busy = TRUE;
73
74 } else {
75
76 /* Insert it into the list */
77 Inserted = TRUE;
78 InsertTailList(&DeviceQueue->DeviceListHead,
79 &DeviceQueueEntry->DeviceListEntry);
80
81
82 }
83
84 /* Sert the Insert state into the entry */
85 DeviceQueueEntry->Inserted = Inserted;
86
87 /* Release lock and return */
88 KeReleaseSpinLockFromDpcLevel(&DeviceQueue->Lock);
89 return Inserted;
90 }
91
92 /*
93 * @implemented
94 */
95 BOOLEAN
96 STDCALL
97 KeInsertByKeyDeviceQueue(IN PKDEVICE_QUEUE DeviceQueue,
98 IN PKDEVICE_QUEUE_ENTRY DeviceQueueEntry,
99 IN ULONG SortKey)
100 {
101 BOOLEAN Inserted;
102
103 DPRINT("KeInsertByKeyDeviceQueue(DeviceQueue %x)\n", DeviceQueue);
104 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
105
106 /* Acquire the Lock */
107 KeAcquireSpinLockAtDpcLevel(&DeviceQueue->Lock);
108
109 /* Set the Sort Key */
110 DeviceQueueEntry->SortKey=SortKey;
111
112 if (!DeviceQueue->Busy) {
113
114 DeviceQueue->Busy=TRUE;
115 Inserted = FALSE;
116
117 } else {
118
119 /* Insert new entry after the last entry with SortKey less or equal to passed-in SortKey */
120 InsertAscendingListFIFO(&DeviceQueue->DeviceListHead,
121 DeviceQueueEntry,
122 KDEVICE_QUEUE_ENTRY,
123 DeviceListEntry,
124 SortKey);
125 Inserted = TRUE;
126 }
127
128 /* Reset the Inserted State */
129 DeviceQueueEntry->Inserted = Inserted;
130
131 /* Release Lock and Return */
132 KeReleaseSpinLockFromDpcLevel(&DeviceQueue->Lock);
133 return Inserted;
134 }
135
136 /*
137 * @implemented
138 *
139 * FUNCTION: Removes an entry from a device queue
140 * ARGUMENTS:
141 * DeviceQueue = Queue to remove the entry
142 * RETURNS: The removed entry
143 */
144 PKDEVICE_QUEUE_ENTRY
145 STDCALL
146 KeRemoveDeviceQueue(IN PKDEVICE_QUEUE DeviceQueue)
147 {
148 PLIST_ENTRY ListEntry;
149 PKDEVICE_QUEUE_ENTRY ReturnEntry;
150
151 DPRINT("KeRemoveDeviceQueue(DeviceQueue %x)\n", DeviceQueue);
152 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
153
154 /* Acquire the Lock */
155 KeAcquireSpinLockAtDpcLevel(&DeviceQueue->Lock);
156 ASSERT(DeviceQueue->Busy);
157
158 /* An attempt to remove an entry from an empty (and busy) queue sets the queue idle */
159 if (IsListEmpty(&DeviceQueue->DeviceListHead)) {
160 DeviceQueue->Busy = FALSE;
161 ReturnEntry = NULL;
162
163 } else {
164
165 /* Remove the Entry from the List */
166 ListEntry = RemoveHeadList(&DeviceQueue->DeviceListHead);
167 ReturnEntry = CONTAINING_RECORD(ListEntry,
168 KDEVICE_QUEUE_ENTRY,
169 DeviceListEntry);
170
171 /* Set it as non-inserted */
172 ReturnEntry->Inserted = FALSE;
173 }
174
175 /* Release lock and Return */
176 KeReleaseSpinLockFromDpcLevel(&DeviceQueue->Lock);
177 return ReturnEntry;
178 }
179
180 /*
181 * @implemented
182 */
183 PKDEVICE_QUEUE_ENTRY
184 STDCALL
185 KeRemoveByKeyDeviceQueue (IN PKDEVICE_QUEUE DeviceQueue,
186 IN ULONG SortKey)
187 {
188 PLIST_ENTRY ListEntry;
189 PKDEVICE_QUEUE_ENTRY ReturnEntry;
190
191 DPRINT("KeRemoveByKeyDeviceQueue(DeviceQueue %x)\n", DeviceQueue);
192 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
193
194 /* Acquire the Lock */
195 KeAcquireSpinLockAtDpcLevel(&DeviceQueue->Lock);
196 ASSERT(DeviceQueue->Busy);
197
198 /* An attempt to remove an entry from an empty (and busy) queue sets the queue idle */
199 if (IsListEmpty(&DeviceQueue->DeviceListHead)) {
200
201 DeviceQueue->Busy = FALSE;
202 ReturnEntry = NULL;
203
204 } else {
205
206 /* Find entry with SortKey greater than or equal to the passed-in SortKey */
207 LIST_FOR_EACH(ReturnEntry, &DeviceQueue->DeviceListHead, KDEVICE_QUEUE_ENTRY, DeviceListEntry)
208 {
209 /* Check if keys match */
210 if (ReturnEntry->SortKey >= SortKey) {
211 /* We found it, so just remove it */
212 RemoveEntryList(&ReturnEntry->DeviceListEntry);
213 break;
214 }
215 }
216
217 /* Check if we found something */
218 if (!ReturnEntry) {
219
220 /* Not found, return the first entry */
221 ListEntry = RemoveHeadList(&DeviceQueue->DeviceListHead);
222 ReturnEntry = CONTAINING_RECORD(ListEntry,
223 KDEVICE_QUEUE_ENTRY,
224 DeviceListEntry);
225 }
226
227 /* Set it as non-inserted */
228 ReturnEntry->Inserted = FALSE;
229 }
230
231 /* Release lock and Return */
232 KeReleaseSpinLockFromDpcLevel(&DeviceQueue->Lock);
233 return ReturnEntry;
234 }
235
236 /*
237 * @unimplemented
238 */
239 PKDEVICE_QUEUE_ENTRY
240 STDCALL
241 KeRemoveByKeyDeviceQueueIfBusy(IN PKDEVICE_QUEUE DeviceQueue,
242 IN ULONG SortKey)
243 {
244 UNIMPLEMENTED;
245 return 0;
246 }
247
248 /*
249 * @implemented
250 */
251 BOOLEAN STDCALL
252 KeRemoveEntryDeviceQueue(IN PKDEVICE_QUEUE DeviceQueue,
253 IN PKDEVICE_QUEUE_ENTRY DeviceQueueEntry)
254 {
255 KIRQL OldIrql;
256 BOOLEAN OldState;
257
258 DPRINT("KeRemoveEntryDeviceQueue(DeviceQueue %x)\n", DeviceQueue);
259 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
260
261 /* Acquire the Lock */
262 KeAcquireSpinLock(&DeviceQueue->Lock, &OldIrql);
263
264 /* Check/Set Old State */
265 if ((OldState = DeviceQueueEntry->Inserted)) {
266
267 /* Remove it */
268 DeviceQueueEntry->Inserted = FALSE;
269 RemoveEntryList(&DeviceQueueEntry->DeviceListEntry);
270 }
271
272 /* Unlock and return old state */
273 KeReleaseSpinLock(&DeviceQueue->Lock, OldIrql);
274 return OldState;
275 }