mirror of
https://github.com/reactos/reactos.git
synced 2024-11-23 11:33:31 +08:00
374 lines
11 KiB
C
374 lines
11 KiB
C
/*
|
|
* PROJECT: ReactOS Kernel
|
|
* LICENSE: GPL - See COPYING in the top level directory
|
|
* FILE: ntoskrnl/ke/devqueue.c
|
|
* PURPOSE: Implement device queues
|
|
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
|
|
*/
|
|
|
|
/* INCLUDES ******************************************************************/
|
|
|
|
#include <ntoskrnl.h>
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
/* FUNCTIONS *****************************************************************/
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID
|
|
NTAPI
|
|
KeInitializeDeviceQueue(IN PKDEVICE_QUEUE DeviceQueue)
|
|
{
|
|
/* Initialize the Header */
|
|
DeviceQueue->Type = DeviceQueueObject;
|
|
DeviceQueue->Size = sizeof(KDEVICE_QUEUE);
|
|
|
|
/* Initialize the Listhead and Spinlock */
|
|
InitializeListHead(&DeviceQueue->DeviceListHead);
|
|
KeInitializeSpinLock(&DeviceQueue->Lock);
|
|
|
|
/* Set it as busy */
|
|
DeviceQueue->Busy=FALSE;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOLEAN
|
|
NTAPI
|
|
KeInsertDeviceQueue(IN PKDEVICE_QUEUE DeviceQueue,
|
|
IN PKDEVICE_QUEUE_ENTRY DeviceQueueEntry)
|
|
{
|
|
KLOCK_QUEUE_HANDLE DeviceLock;
|
|
BOOLEAN Inserted;
|
|
ASSERT_DEVICE_QUEUE(DeviceQueue);
|
|
|
|
DPRINT("KeInsertDeviceQueue() DevQueue %p, Entry %p\n", DeviceQueue, DeviceQueueEntry);
|
|
|
|
/* Lock the queue */
|
|
KiAcquireDeviceQueueLock(DeviceQueue, &DeviceLock);
|
|
|
|
/* Check if it's not busy */
|
|
if (!DeviceQueue->Busy)
|
|
{
|
|
/* Set it as busy */
|
|
Inserted = FALSE;
|
|
DeviceQueue->Busy = TRUE;
|
|
}
|
|
else
|
|
{
|
|
/* Insert it into the list */
|
|
Inserted = TRUE;
|
|
InsertTailList(&DeviceQueue->DeviceListHead,
|
|
&DeviceQueueEntry->DeviceListEntry);
|
|
}
|
|
|
|
/* Set the Insert state into the entry */
|
|
DeviceQueueEntry->Inserted = Inserted;
|
|
|
|
/* Release the lock */
|
|
KiReleaseDeviceQueueLock(&DeviceLock);
|
|
|
|
/* Return the state */
|
|
return Inserted;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOLEAN
|
|
NTAPI
|
|
KeInsertByKeyDeviceQueue(IN PKDEVICE_QUEUE DeviceQueue,
|
|
IN PKDEVICE_QUEUE_ENTRY DeviceQueueEntry,
|
|
IN ULONG SortKey)
|
|
{
|
|
KLOCK_QUEUE_HANDLE DeviceLock;
|
|
BOOLEAN Inserted;
|
|
PLIST_ENTRY NextEntry;
|
|
PKDEVICE_QUEUE_ENTRY LastEntry;
|
|
ASSERT_DEVICE_QUEUE(DeviceQueue);
|
|
|
|
DPRINT("KeInsertByKeyDeviceQueue() DevQueue %p, Entry %p, SortKey 0x%x\n", DeviceQueue, DeviceQueueEntry, SortKey);
|
|
|
|
/* Lock the queue */
|
|
KiAcquireDeviceQueueLock(DeviceQueue, &DeviceLock);
|
|
|
|
/* Set the Sort Key */
|
|
DeviceQueueEntry->SortKey = SortKey;
|
|
|
|
/* Check if it's not busy */
|
|
if (!DeviceQueue->Busy)
|
|
{
|
|
/* Set it as busy */
|
|
Inserted = FALSE;
|
|
DeviceQueue->Busy = TRUE;
|
|
}
|
|
else
|
|
{
|
|
/* Make sure the list isn't empty */
|
|
NextEntry = &DeviceQueue->DeviceListHead;
|
|
if (!IsListEmpty(NextEntry))
|
|
{
|
|
/* Get the last entry */
|
|
LastEntry = CONTAINING_RECORD(NextEntry->Blink,
|
|
KDEVICE_QUEUE_ENTRY,
|
|
DeviceListEntry);
|
|
|
|
/* Check if our sort key is lower */
|
|
if (SortKey < LastEntry->SortKey)
|
|
{
|
|
/* Loop each sort key */
|
|
do
|
|
{
|
|
/* Get the next entry */
|
|
NextEntry = NextEntry->Flink;
|
|
LastEntry = CONTAINING_RECORD(NextEntry,
|
|
KDEVICE_QUEUE_ENTRY,
|
|
DeviceListEntry);
|
|
|
|
/* Keep looping until we find a place to insert */
|
|
} while (SortKey >= LastEntry->SortKey);
|
|
}
|
|
}
|
|
|
|
/* Now insert us */
|
|
InsertTailList(NextEntry, &DeviceQueueEntry->DeviceListEntry);
|
|
Inserted = TRUE;
|
|
}
|
|
|
|
/* Release the lock */
|
|
KiReleaseDeviceQueueLock(&DeviceLock);
|
|
|
|
/* Return the state */
|
|
return Inserted;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
PKDEVICE_QUEUE_ENTRY
|
|
NTAPI
|
|
KeRemoveDeviceQueue(IN PKDEVICE_QUEUE DeviceQueue)
|
|
{
|
|
PLIST_ENTRY ListEntry;
|
|
PKDEVICE_QUEUE_ENTRY ReturnEntry;
|
|
KLOCK_QUEUE_HANDLE DeviceLock;
|
|
ASSERT_DEVICE_QUEUE(DeviceQueue);
|
|
|
|
DPRINT("KeRemoveDeviceQueue() DevQueue %p\n", DeviceQueue);
|
|
|
|
/* Lock the queue */
|
|
KiAcquireDeviceQueueLock(DeviceQueue, &DeviceLock);
|
|
ASSERT(DeviceQueue->Busy);
|
|
|
|
/* Check if this is an empty queue */
|
|
if (IsListEmpty(&DeviceQueue->DeviceListHead))
|
|
{
|
|
/* Set it to idle and return nothing*/
|
|
DeviceQueue->Busy = FALSE;
|
|
ReturnEntry = NULL;
|
|
}
|
|
else
|
|
{
|
|
/* Remove the Entry from the List */
|
|
ListEntry = RemoveHeadList(&DeviceQueue->DeviceListHead);
|
|
ReturnEntry = CONTAINING_RECORD(ListEntry,
|
|
KDEVICE_QUEUE_ENTRY,
|
|
DeviceListEntry);
|
|
|
|
/* Set it as non-inserted */
|
|
ReturnEntry->Inserted = FALSE;
|
|
}
|
|
|
|
/* Release the lock */
|
|
KiReleaseDeviceQueueLock(&DeviceLock);
|
|
|
|
/* Return the entry */
|
|
return ReturnEntry;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
PKDEVICE_QUEUE_ENTRY
|
|
NTAPI
|
|
KeRemoveByKeyDeviceQueue(IN PKDEVICE_QUEUE DeviceQueue,
|
|
IN ULONG SortKey)
|
|
{
|
|
PLIST_ENTRY NextEntry;
|
|
PKDEVICE_QUEUE_ENTRY ReturnEntry;
|
|
KLOCK_QUEUE_HANDLE DeviceLock;
|
|
ASSERT_DEVICE_QUEUE(DeviceQueue);
|
|
|
|
DPRINT("KeRemoveByKeyDeviceQueue() DevQueue %p, SortKey 0x%x\n", DeviceQueue, SortKey);
|
|
|
|
/* Lock the queue */
|
|
KiAcquireDeviceQueueLock(DeviceQueue, &DeviceLock);
|
|
ASSERT(DeviceQueue->Busy);
|
|
|
|
/* Check if this is an empty queue */
|
|
if (IsListEmpty(&DeviceQueue->DeviceListHead))
|
|
{
|
|
/* Set it to idle and return nothing*/
|
|
DeviceQueue->Busy = FALSE;
|
|
ReturnEntry = NULL;
|
|
}
|
|
else
|
|
{
|
|
/* If SortKey is greater than the last key, then return the first entry right away */
|
|
NextEntry = &DeviceQueue->DeviceListHead;
|
|
ReturnEntry = CONTAINING_RECORD(NextEntry->Blink,
|
|
KDEVICE_QUEUE_ENTRY,
|
|
DeviceListEntry);
|
|
|
|
/* Check if we can just get the first entry */
|
|
if (ReturnEntry->SortKey <= SortKey)
|
|
{
|
|
/* Get the first entry */
|
|
ReturnEntry = CONTAINING_RECORD(NextEntry->Flink,
|
|
KDEVICE_QUEUE_ENTRY,
|
|
DeviceListEntry);
|
|
}
|
|
else
|
|
{
|
|
/* Loop the list */
|
|
NextEntry = DeviceQueue->DeviceListHead.Flink;
|
|
while (TRUE)
|
|
{
|
|
/* Make sure we don't go beyond the end of the queue */
|
|
ASSERT(NextEntry != &DeviceQueue->DeviceListHead);
|
|
|
|
/* Get the next entry and check if the key is low enough */
|
|
ReturnEntry = CONTAINING_RECORD(NextEntry,
|
|
KDEVICE_QUEUE_ENTRY,
|
|
DeviceListEntry);
|
|
if (SortKey <= ReturnEntry->SortKey) break;
|
|
|
|
/* Try the next one */
|
|
NextEntry = NextEntry->Flink;
|
|
}
|
|
}
|
|
|
|
/* We have an entry, remove it now */
|
|
RemoveEntryList(&ReturnEntry->DeviceListEntry);
|
|
|
|
/* Set it as non-inserted */
|
|
ReturnEntry->Inserted = FALSE;
|
|
}
|
|
|
|
/* Release the lock */
|
|
KiReleaseDeviceQueueLock(&DeviceLock);
|
|
|
|
/* Return the entry */
|
|
return ReturnEntry;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
PKDEVICE_QUEUE_ENTRY
|
|
NTAPI
|
|
KeRemoveByKeyDeviceQueueIfBusy(IN PKDEVICE_QUEUE DeviceQueue,
|
|
IN ULONG SortKey)
|
|
{
|
|
PLIST_ENTRY NextEntry;
|
|
PKDEVICE_QUEUE_ENTRY ReturnEntry;
|
|
KLOCK_QUEUE_HANDLE DeviceLock;
|
|
ASSERT_DEVICE_QUEUE(DeviceQueue);
|
|
|
|
DPRINT("KeRemoveByKeyDeviceQueueIfBusy() DevQueue %p, SortKey 0x%x\n", DeviceQueue, SortKey);
|
|
|
|
/* Lock the queue */
|
|
KiAcquireDeviceQueueLock(DeviceQueue, &DeviceLock);
|
|
|
|
/* Check if this is an empty or idle queue */
|
|
if (!(DeviceQueue->Busy) || (IsListEmpty(&DeviceQueue->DeviceListHead)))
|
|
{
|
|
/* Set it to idle and return nothing*/
|
|
DeviceQueue->Busy = FALSE;
|
|
ReturnEntry = NULL;
|
|
}
|
|
else
|
|
{
|
|
/* If SortKey is greater than the last key, then return the first entry right away */
|
|
NextEntry = &DeviceQueue->DeviceListHead;
|
|
ReturnEntry = CONTAINING_RECORD(NextEntry->Blink,
|
|
KDEVICE_QUEUE_ENTRY,
|
|
DeviceListEntry);
|
|
|
|
/* Check if we can just get the first entry */
|
|
if (ReturnEntry->SortKey <= SortKey)
|
|
{
|
|
/* Get the first entry */
|
|
ReturnEntry = CONTAINING_RECORD(NextEntry->Flink,
|
|
KDEVICE_QUEUE_ENTRY,
|
|
DeviceListEntry);
|
|
}
|
|
else
|
|
{
|
|
/* Loop the list */
|
|
NextEntry = DeviceQueue->DeviceListHead.Flink;
|
|
while (TRUE)
|
|
{
|
|
/* Make sure we don't go beyond the end of the queue */
|
|
ASSERT(NextEntry != &DeviceQueue->DeviceListHead);
|
|
|
|
/* Get the next entry and check if the key is low enough */
|
|
ReturnEntry = CONTAINING_RECORD(NextEntry,
|
|
KDEVICE_QUEUE_ENTRY,
|
|
DeviceListEntry);
|
|
if (SortKey <= ReturnEntry->SortKey) break;
|
|
|
|
/* Try the next one */
|
|
NextEntry = NextEntry->Flink;
|
|
}
|
|
}
|
|
|
|
/* We have an entry, remove it now */
|
|
RemoveEntryList(&ReturnEntry->DeviceListEntry);
|
|
|
|
/* Set it as non-inserted */
|
|
ReturnEntry->Inserted = FALSE;
|
|
}
|
|
|
|
/* Release the lock */
|
|
KiReleaseDeviceQueueLock(&DeviceLock);
|
|
|
|
/* Return the entry */
|
|
return ReturnEntry;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOLEAN
|
|
NTAPI
|
|
KeRemoveEntryDeviceQueue(IN PKDEVICE_QUEUE DeviceQueue,
|
|
IN PKDEVICE_QUEUE_ENTRY DeviceQueueEntry)
|
|
{
|
|
BOOLEAN OldState;
|
|
KLOCK_QUEUE_HANDLE DeviceLock;
|
|
ASSERT_DEVICE_QUEUE(DeviceQueue);
|
|
|
|
DPRINT("KeRemoveEntryDeviceQueue() DevQueue %p, Entry %p\n", DeviceQueue, DeviceQueueEntry);
|
|
|
|
/* Lock the queue */
|
|
KiAcquireDeviceQueueLock(DeviceQueue, &DeviceLock);
|
|
ASSERT(DeviceQueue->Busy);
|
|
|
|
/* Check the insertion state */
|
|
OldState = DeviceQueueEntry->Inserted;
|
|
if (OldState)
|
|
{
|
|
/* Remove it */
|
|
DeviceQueueEntry->Inserted = FALSE;
|
|
RemoveEntryList(&DeviceQueueEntry->DeviceListEntry);
|
|
}
|
|
|
|
/* Unlock and return old state */
|
|
KiReleaseDeviceQueueLock(&DeviceLock);
|
|
return OldState;
|
|
}
|