/* * 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 #define NDEBUG #include /* 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; }