- Fix KiDispatchException to unmask KI_EXCEPTION_INTERNAL when setting the exception...
[reactos.git] / reactos / ntoskrnl / ke / devqueue.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ke/devqueue.c
5 * PURPOSE: Implement device queues
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <internal/debug.h>
14
15 /* FUNCTIONS *****************************************************************/
16
17 /*
18 * @implemented
19 */
20 VOID
21 NTAPI
22 KeInitializeDeviceQueue(IN PKDEVICE_QUEUE DeviceQueue)
23 {
24 /* Initialize the Header */
25 DeviceQueue->Type = DeviceQueueObject;
26 DeviceQueue->Size = sizeof(KDEVICE_QUEUE);
27
28 /* Initialize the Listhead and Spinlock */
29 InitializeListHead(&DeviceQueue->DeviceListHead);
30 KeInitializeSpinLock(&DeviceQueue->Lock);
31
32 /* Set it as busy */
33 DeviceQueue->Busy=FALSE;
34 }
35
36 /*
37 * @implemented
38 */
39 BOOLEAN
40 NTAPI
41 KeInsertDeviceQueue(IN PKDEVICE_QUEUE DeviceQueue,
42 IN PKDEVICE_QUEUE_ENTRY DeviceQueueEntry)
43 {
44 KLOCK_QUEUE_HANDLE DeviceLock;
45 BOOLEAN Inserted;
46 ASSERT_DEVICE_QUEUE(DeviceQueue);
47
48 /* Lock the queue */
49 KiAcquireDeviceQueueLock(DeviceQueue, &DeviceLock);
50
51 /* Check if it's not busy */
52 if (!DeviceQueue->Busy)
53 {
54 /* Set it as busy */
55 Inserted = FALSE;
56 DeviceQueue->Busy = TRUE;
57 }
58 else
59 {
60 /* Insert it into the list */
61 Inserted = TRUE;
62 InsertTailList(&DeviceQueue->DeviceListHead,
63 &DeviceQueueEntry->DeviceListEntry);
64 }
65
66 /* Sert the Insert state into the entry */
67 DeviceQueueEntry->Inserted = Inserted;
68
69 /* Release the lock */
70 KiReleaseDeviceQueueLock(&DeviceLock);
71
72 /* Return the state */
73 return Inserted;
74 }
75
76 /*
77 * @implemented
78 */
79 BOOLEAN
80 NTAPI
81 KeInsertByKeyDeviceQueue(IN PKDEVICE_QUEUE DeviceQueue,
82 IN PKDEVICE_QUEUE_ENTRY DeviceQueueEntry,
83 IN ULONG SortKey)
84 {
85 KLOCK_QUEUE_HANDLE DeviceLock;
86 BOOLEAN Inserted;
87 ASSERT_DEVICE_QUEUE(DeviceQueue);
88
89 /* Lock the queue */
90 KiAcquireDeviceQueueLock(DeviceQueue, &DeviceLock);
91
92 /* Set the Sort Key */
93 DeviceQueueEntry->SortKey = SortKey;
94
95 /* Check if it's not busy */
96 if (!DeviceQueue->Busy)
97 {
98 /* Set it as busy */
99 Inserted = FALSE;
100 DeviceQueue->Busy = TRUE;
101 }
102 else
103 {
104 /* Insert new entry after the last entry with SortKey less or equal to passed-in SortKey */
105 InsertAscendingListFIFO(&DeviceQueue->DeviceListHead,
106 DeviceQueueEntry,
107 KDEVICE_QUEUE_ENTRY,
108 DeviceListEntry,
109 SortKey);
110 Inserted = TRUE;
111 }
112
113 /* Release the lock */
114 KiReleaseDeviceQueueLock(&DeviceLock);
115
116 /* Return the state */
117 return Inserted;
118 }
119
120 /*
121 * @implemented
122 */
123 PKDEVICE_QUEUE_ENTRY
124 NTAPI
125 KeRemoveDeviceQueue(IN PKDEVICE_QUEUE DeviceQueue)
126 {
127 PLIST_ENTRY ListEntry;
128 PKDEVICE_QUEUE_ENTRY ReturnEntry;
129 KLOCK_QUEUE_HANDLE DeviceLock;
130 ASSERT_DEVICE_QUEUE(DeviceQueue);
131
132 /* Lock the queue */
133 KiAcquireDeviceQueueLock(DeviceQueue, &DeviceLock);
134 ASSERT(DeviceQueue->Busy);
135
136 /* Check if this is an empty queue */
137 if (IsListEmpty(&DeviceQueue->DeviceListHead))
138 {
139 /* Set it to idle and return nothing*/
140 DeviceQueue->Busy = FALSE;
141 ReturnEntry = NULL;
142 }
143 else
144 {
145 /* Remove the Entry from the List */
146 ListEntry = RemoveHeadList(&DeviceQueue->DeviceListHead);
147 ReturnEntry = CONTAINING_RECORD(ListEntry,
148 KDEVICE_QUEUE_ENTRY,
149 DeviceListEntry);
150
151 /* Set it as non-inserted */
152 ReturnEntry->Inserted = FALSE;
153 }
154
155 /* Release the lock */
156 KiReleaseDeviceQueueLock(&DeviceLock);
157
158 /* Return the entry */
159 return ReturnEntry;
160 }
161
162 /*
163 * @implemented
164 */
165 PKDEVICE_QUEUE_ENTRY
166 NTAPI
167 KeRemoveByKeyDeviceQueue(IN PKDEVICE_QUEUE DeviceQueue,
168 IN ULONG SortKey)
169 {
170 PLIST_ENTRY ListEntry;
171 PKDEVICE_QUEUE_ENTRY ReturnEntry;
172 KLOCK_QUEUE_HANDLE DeviceLock;
173 ASSERT_DEVICE_QUEUE(DeviceQueue);
174
175 /* Lock the queue */
176 KiAcquireDeviceQueueLock(DeviceQueue, &DeviceLock);
177 ASSERT(DeviceQueue->Busy);
178
179 /* Check if this is an empty queue */
180 if (IsListEmpty(&DeviceQueue->DeviceListHead))
181 {
182 /* Set it to idle and return nothing*/
183 DeviceQueue->Busy = FALSE;
184 ReturnEntry = NULL;
185 }
186 else
187 {
188 /* Find entry with SortKey greater than or equal to the passed-in SortKey */
189 LIST_FOR_EACH(ReturnEntry, &DeviceQueue->DeviceListHead, KDEVICE_QUEUE_ENTRY, DeviceListEntry)
190 {
191 /* Check if keys match */
192 if (ReturnEntry->SortKey >= SortKey)
193 {
194 /* We found it, so just remove it */
195 RemoveEntryList(&ReturnEntry->DeviceListEntry);
196 break;
197 }
198 }
199
200 /* Check if we found something */
201 if (!ReturnEntry)
202 {
203 /* Not found, return the first entry */
204 ListEntry = RemoveHeadList(&DeviceQueue->DeviceListHead);
205 ReturnEntry = CONTAINING_RECORD(ListEntry,
206 KDEVICE_QUEUE_ENTRY,
207 DeviceListEntry);
208 }
209
210 /* Set it as non-inserted */
211 ReturnEntry->Inserted = FALSE;
212 }
213
214 /* Release the lock */
215 KiReleaseDeviceQueueLock(&DeviceLock);
216
217 /* Return the entry */
218 return ReturnEntry;
219 }
220
221 /*
222 * @implemented
223 */
224 PKDEVICE_QUEUE_ENTRY
225 NTAPI
226 KeRemoveByKeyDeviceQueueIfBusy(IN PKDEVICE_QUEUE DeviceQueue,
227 IN ULONG SortKey)
228 {
229 PLIST_ENTRY ListEntry;
230 PKDEVICE_QUEUE_ENTRY ReturnEntry;
231 KLOCK_QUEUE_HANDLE DeviceLock;
232 ASSERT_DEVICE_QUEUE(DeviceQueue);
233
234 /* Lock the queue */
235 KiAcquireDeviceQueueLock(DeviceQueue, &DeviceLock);
236
237 /* Check if this is an empty or idle queue */
238 if (!(DeviceQueue->Busy) || (IsListEmpty(&DeviceQueue->DeviceListHead)))
239 {
240 /* Set it to idle and return nothing*/
241 DeviceQueue->Busy = FALSE;
242 ReturnEntry = NULL;
243 }
244 else
245 {
246 /* Find entry with SortKey greater than or equal to the passed-in SortKey */
247 LIST_FOR_EACH(ReturnEntry, &DeviceQueue->DeviceListHead, KDEVICE_QUEUE_ENTRY, DeviceListEntry)
248 {
249 /* Check if keys match */
250 if (ReturnEntry->SortKey >= SortKey)
251 {
252 /* We found it, so just remove it */
253 RemoveEntryList(&ReturnEntry->DeviceListEntry);
254 break;
255 }
256 }
257
258 /* Check if we found something */
259 if (!ReturnEntry)
260 {
261 /* Not found, return the first entry */
262 ListEntry = RemoveHeadList(&DeviceQueue->DeviceListHead);
263 ReturnEntry = CONTAINING_RECORD(ListEntry,
264 KDEVICE_QUEUE_ENTRY,
265 DeviceListEntry);
266 }
267
268 /* Set it as non-inserted */
269 ReturnEntry->Inserted = FALSE;
270 }
271
272 /* Release the lock */
273 KiReleaseDeviceQueueLock(&DeviceLock);
274
275 /* Return the entry */
276 return ReturnEntry;
277 }
278
279 /*
280 * @implemented
281 */
282 BOOLEAN
283 NTAPI
284 KeRemoveEntryDeviceQueue(IN PKDEVICE_QUEUE DeviceQueue,
285 IN PKDEVICE_QUEUE_ENTRY DeviceQueueEntry)
286 {
287 BOOLEAN OldState;
288 KLOCK_QUEUE_HANDLE DeviceLock;
289 ASSERT_DEVICE_QUEUE(DeviceQueue);
290
291 /* Lock the queue */
292 KiAcquireDeviceQueueLock(DeviceQueue, &DeviceLock);
293 ASSERT(DeviceQueue->Busy);
294
295 /* Check the insertion state */
296 OldState = DeviceQueueEntry->Inserted;
297 if (OldState)
298 {
299 /* Remove it */
300 DeviceQueueEntry->Inserted = FALSE;
301 RemoveEntryList(&DeviceQueueEntry->DeviceListEntry);
302 }
303
304 /* Unlock and return old state */
305 KiReleaseDeviceQueueLock(&DeviceLock);
306 return OldState;
307 }