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)
9 /* INCLUDES ******************************************************************/
15 /* FUNCTIONS *****************************************************************/
22 KeInitializeDeviceQueue(IN PKDEVICE_QUEUE DeviceQueue
)
24 /* Initialize the Header */
25 DeviceQueue
->Type
= DeviceQueueObject
;
26 DeviceQueue
->Size
= sizeof(KDEVICE_QUEUE
);
28 /* Initialize the Listhead and Spinlock */
29 InitializeListHead(&DeviceQueue
->DeviceListHead
);
30 KeInitializeSpinLock(&DeviceQueue
->Lock
);
33 DeviceQueue
->Busy
=FALSE
;
41 KeInsertDeviceQueue(IN PKDEVICE_QUEUE DeviceQueue
,
42 IN PKDEVICE_QUEUE_ENTRY DeviceQueueEntry
)
44 KLOCK_QUEUE_HANDLE DeviceLock
;
46 ASSERT_DEVICE_QUEUE(DeviceQueue
);
48 DPRINT("KeInsertDeviceQueue() DevQueue %p, Entry %p\n", DeviceQueue
, DeviceQueueEntry
);
51 KiAcquireDeviceQueueLock(DeviceQueue
, &DeviceLock
);
53 /* Check if it's not busy */
54 if (!DeviceQueue
->Busy
)
58 DeviceQueue
->Busy
= TRUE
;
62 /* Insert it into the list */
64 InsertTailList(&DeviceQueue
->DeviceListHead
,
65 &DeviceQueueEntry
->DeviceListEntry
);
68 /* Sert the Insert state into the entry */
69 DeviceQueueEntry
->Inserted
= Inserted
;
71 /* Release the lock */
72 KiReleaseDeviceQueueLock(&DeviceLock
);
74 /* Return the state */
83 KeInsertByKeyDeviceQueue(IN PKDEVICE_QUEUE DeviceQueue
,
84 IN PKDEVICE_QUEUE_ENTRY DeviceQueueEntry
,
87 KLOCK_QUEUE_HANDLE DeviceLock
;
89 PLIST_ENTRY NextEntry
;
90 PKDEVICE_QUEUE_ENTRY LastEntry
;
91 ASSERT_DEVICE_QUEUE(DeviceQueue
);
93 DPRINT("KeInsertByKeyDeviceQueue() DevQueue %p, Entry %p, SortKey 0x%x\n", DeviceQueue
, DeviceQueueEntry
, SortKey
);
96 KiAcquireDeviceQueueLock(DeviceQueue
, &DeviceLock
);
98 /* Set the Sort Key */
99 DeviceQueueEntry
->SortKey
= SortKey
;
101 /* Check if it's not busy */
102 if (!DeviceQueue
->Busy
)
106 DeviceQueue
->Busy
= TRUE
;
110 /* Make sure the list isn't empty */
111 NextEntry
= &DeviceQueue
->DeviceListHead
;
112 if (!IsListEmpty(NextEntry
))
114 /* Get the last entry */
115 LastEntry
= CONTAINING_RECORD(NextEntry
->Blink
,
119 /* Check if our sort key is lower */
120 if (SortKey
< LastEntry
->SortKey
)
122 /* Loop each sort key */
125 /* Get the next entry */
126 NextEntry
= NextEntry
->Flink
;
127 LastEntry
= CONTAINING_RECORD(NextEntry
,
131 /* Keep looping until we find a place to insert */
132 } while (SortKey
>= LastEntry
->SortKey
);
137 InsertTailList(NextEntry
, &DeviceQueueEntry
->DeviceListEntry
);
141 /* Release the lock */
142 KiReleaseDeviceQueueLock(&DeviceLock
);
144 /* Return the state */
153 KeRemoveDeviceQueue(IN PKDEVICE_QUEUE DeviceQueue
)
155 PLIST_ENTRY ListEntry
;
156 PKDEVICE_QUEUE_ENTRY ReturnEntry
;
157 KLOCK_QUEUE_HANDLE DeviceLock
;
158 ASSERT_DEVICE_QUEUE(DeviceQueue
);
160 DPRINT("KeRemoveDeviceQueue() DevQueue %p\n", DeviceQueue
);
163 KiAcquireDeviceQueueLock(DeviceQueue
, &DeviceLock
);
164 ASSERT(DeviceQueue
->Busy
);
166 /* Check if this is an empty queue */
167 if (IsListEmpty(&DeviceQueue
->DeviceListHead
))
169 /* Set it to idle and return nothing*/
170 DeviceQueue
->Busy
= FALSE
;
175 /* Remove the Entry from the List */
176 ListEntry
= RemoveHeadList(&DeviceQueue
->DeviceListHead
);
177 ReturnEntry
= CONTAINING_RECORD(ListEntry
,
181 /* Set it as non-inserted */
182 ReturnEntry
->Inserted
= FALSE
;
185 /* Release the lock */
186 KiReleaseDeviceQueueLock(&DeviceLock
);
188 /* Return the entry */
197 KeRemoveByKeyDeviceQueue(IN PKDEVICE_QUEUE DeviceQueue
,
200 PLIST_ENTRY NextEntry
;
201 PKDEVICE_QUEUE_ENTRY ReturnEntry
;
202 KLOCK_QUEUE_HANDLE DeviceLock
;
203 ASSERT_DEVICE_QUEUE(DeviceQueue
);
205 DPRINT("KeRemoveByKeyDeviceQueue() DevQueue %p, SortKey 0x%x\n", DeviceQueue
, SortKey
);
208 KiAcquireDeviceQueueLock(DeviceQueue
, &DeviceLock
);
209 ASSERT(DeviceQueue
->Busy
);
211 /* Check if this is an empty queue */
212 if (IsListEmpty(&DeviceQueue
->DeviceListHead
))
214 /* Set it to idle and return nothing*/
215 DeviceQueue
->Busy
= FALSE
;
220 /* If SortKey is greater than the last key, then return the first entry right away */
221 NextEntry
= &DeviceQueue
->DeviceListHead
;
222 ReturnEntry
= CONTAINING_RECORD(NextEntry
->Blink
,
226 /* Check if we can just get the first entry */
227 if (ReturnEntry
->SortKey
<= SortKey
)
229 /* Get the first entry */
230 ReturnEntry
= CONTAINING_RECORD(NextEntry
->Flink
,
237 NextEntry
= DeviceQueue
->DeviceListHead
.Flink
;
240 /* Make sure we don't go beyond the end of the queue */
241 ASSERT(NextEntry
!= &DeviceQueue
->DeviceListHead
);
243 /* Get the next entry and check if the key is low enough */
244 ReturnEntry
= CONTAINING_RECORD(NextEntry
,
247 if (SortKey
<= ReturnEntry
->SortKey
) break;
249 /* Try the next one */
250 NextEntry
= NextEntry
->Flink
;
254 /* We have an entry, remove it now */
255 RemoveEntryList(&ReturnEntry
->DeviceListEntry
);
257 /* Set it as non-inserted */
258 ReturnEntry
->Inserted
= FALSE
;
261 /* Release the lock */
262 KiReleaseDeviceQueueLock(&DeviceLock
);
264 /* Return the entry */
273 KeRemoveByKeyDeviceQueueIfBusy(IN PKDEVICE_QUEUE DeviceQueue
,
276 PLIST_ENTRY NextEntry
;
277 PKDEVICE_QUEUE_ENTRY ReturnEntry
;
278 KLOCK_QUEUE_HANDLE DeviceLock
;
279 ASSERT_DEVICE_QUEUE(DeviceQueue
);
281 DPRINT("KeRemoveByKeyDeviceQueueIfBusy() DevQueue %p, SortKey 0x%x\n", DeviceQueue
, SortKey
);
284 KiAcquireDeviceQueueLock(DeviceQueue
, &DeviceLock
);
286 /* Check if this is an empty or idle queue */
287 if (!(DeviceQueue
->Busy
) || (IsListEmpty(&DeviceQueue
->DeviceListHead
)))
289 /* Set it to idle and return nothing*/
290 DeviceQueue
->Busy
= FALSE
;
295 /* If SortKey is greater than the last key, then return the first entry right away */
296 NextEntry
= &DeviceQueue
->DeviceListHead
;
297 ReturnEntry
= CONTAINING_RECORD(NextEntry
->Blink
,
301 /* Check if we can just get the first entry */
302 if (ReturnEntry
->SortKey
<= SortKey
)
304 /* Get the first entry */
305 ReturnEntry
= CONTAINING_RECORD(NextEntry
->Flink
,
312 NextEntry
= DeviceQueue
->DeviceListHead
.Flink
;
315 /* Make sure we don't go beyond the end of the queue */
316 ASSERT(NextEntry
!= &DeviceQueue
->DeviceListHead
);
318 /* Get the next entry and check if the key is low enough */
319 ReturnEntry
= CONTAINING_RECORD(NextEntry
,
322 if (SortKey
<= ReturnEntry
->SortKey
) break;
324 /* Try the next one */
325 NextEntry
= NextEntry
->Flink
;
329 /* We have an entry, remove it now */
330 RemoveEntryList(&ReturnEntry
->DeviceListEntry
);
332 /* Set it as non-inserted */
333 ReturnEntry
->Inserted
= FALSE
;
336 /* Release the lock */
337 KiReleaseDeviceQueueLock(&DeviceLock
);
339 /* Return the entry */
348 KeRemoveEntryDeviceQueue(IN PKDEVICE_QUEUE DeviceQueue
,
349 IN PKDEVICE_QUEUE_ENTRY DeviceQueueEntry
)
352 KLOCK_QUEUE_HANDLE DeviceLock
;
353 ASSERT_DEVICE_QUEUE(DeviceQueue
);
355 DPRINT("KeRemoveEntryDeviceQueue() DevQueue %p, Entry %p\n", DeviceQueue
, DeviceQueueEntry
);
358 KiAcquireDeviceQueueLock(DeviceQueue
, &DeviceLock
);
359 ASSERT(DeviceQueue
->Busy
);
361 /* Check the insertion state */
362 OldState
= DeviceQueueEntry
->Inserted
;
366 DeviceQueueEntry
->Inserted
= FALSE
;
367 RemoveEntryList(&DeviceQueueEntry
->DeviceListEntry
);
370 /* Unlock and return old state */
371 KiReleaseDeviceQueueLock(&DeviceLock
);