- Implement KiAcquireDeviceQueueLock/KiReleaseDeviceQueueLock for locking KDEVICE_QUEUEs, since they can be used from Threaded DPCs which don't execute at DISPATCH_LEVEL, so the lock needs to be acquired differently.

- Add ASSERT_DEVICE_QUEUE and ASSERTify + reformat kqueue.c.
- Implement KeRemoveByKeyDeviceQueueIfBusy.
- Cleanup exception.c
- Remove dangerous/broken KeGetCurrentIrql() define.

svn path=/trunk/; revision=24087
This commit is contained in:
Alex Ionescu 2006-09-13 00:20:46 +00:00
parent c0cda24302
commit d99f96a295
5 changed files with 200 additions and 130 deletions

View file

@ -1093,6 +1093,9 @@ typedef struct _KLOCK_QUEUE_HANDLE {
((Object)->Type == DpcObject) || \ ((Object)->Type == DpcObject) || \
((Object)->Type == ThreadedDpcObject)) ((Object)->Type == ThreadedDpcObject))
#define ASSERT_DEVICE_QUEUE(Object) \
ASSERT((Object)->Type == DeviceQueueObject)
typedef struct _KDPC typedef struct _KDPC
{ {
UCHAR Type; UCHAR Type;

View file

@ -124,7 +124,6 @@ KiThreadStartup(PKSYSTEM_ROUTINE SystemRoutine,
#define LOCK "lock ; " #define LOCK "lock ; "
#else #else
#define LOCK "" #define LOCK ""
#define KeGetCurrentIrql() (((PKPCR)KPCR_BASE)->Irql)
#endif #endif
#if defined(__GNUC__) #if defined(__GNUC__)

View file

@ -696,6 +696,44 @@ KiReleaseProcessLockFromDpcLevel(IN PKLOCK_QUEUE_HANDLE Handle)
KeReleaseInStackQueuedSpinLockFromDpcLevel(Handle); KeReleaseInStackQueuedSpinLockFromDpcLevel(Handle);
} }
FORCEINLINE
VOID
KiAcquireDeviceQueueLock(IN PKDEVICE_QUEUE DeviceQueue,
IN PKLOCK_QUEUE_HANDLE DeviceLock)
{
/* Check if we were called from a threaded DPC */
if (KeGetCurrentPrcb()->DpcThreadActive)
{
/* Lock the Queue, we're not at DPC level */
KeAcquireInStackQueuedSpinLock(&DeviceQueue->Lock, DeviceLock);
}
else
{
/* We must be at DPC level, acquire the lock safely */
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
KeAcquireInStackQueuedSpinLockAtDpcLevel(&DeviceQueue->Lock,
DeviceLock);
}
}
FORCEINLINE
VOID
KiReleaseDeviceQueueLock(IN PKLOCK_QUEUE_HANDLE DeviceLock)
{
/* Check if we were called from a threaded DPC */
if (KeGetCurrentPrcb()->DpcThreadActive)
{
/* Unlock the Queue, we're not at DPC level */
KeReleaseInStackQueuedSpinLock(DeviceLock);
}
else
{
/* We must be at DPC level, release the lock safely */
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
KeReleaseInStackQueuedSpinLockFromDpcLevel(DeviceLock);
}
}
// //
// This routine queues a thread that is ready on the PRCB's ready lists. // This routine queues a thread that is ready on the PRCB's ready lists.
// If this thread cannot currently run on this CPU, then the thread is // If this thread cannot currently run on this CPU, then the thread is

View file

@ -1,18 +1,18 @@
/* /*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Kernel * PROJECT: ReactOS Kernel
* LICENSE: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/ke/exception.c * FILE: ntoskrnl/ke/exception.c
* PURPOSE: Platform independent exception handling * PURPOSE: Platform independent exception handling
* PROGRAMMER: Alex Ionescu (alex@relsoft.net) * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
*/ */
/* INCLUDES *****************************************************************/ /* INCLUDES ******************************************************************/
#include <ntoskrnl.h> #include <ntoskrnl.h>
#define NDEBUG #define NDEBUG
#include <internal/debug.h> #include <internal/debug.h>
/* FUNCTIONS ****************************************************************/ /* INCLUDES ******************************************************************/
VOID VOID
NTAPI NTAPI
@ -46,11 +46,7 @@ KiContinue(IN PCONTEXT Context,
KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(); KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
/* Raise to APC_LEVEL, only if needed */ /* Raise to APC_LEVEL, only if needed */
if (KeGetCurrentIrql() < APC_LEVEL) if (KeGetCurrentIrql() < APC_LEVEL) KeRaiseIrql(APC_LEVEL, &OldIrql);
{
/* Raise to APC_LEVEL */
KeRaiseIrql(APC_LEVEL, &OldIrql);
}
/* Set up SEH to validate the context */ /* Set up SEH to validate the context */
_SEH_TRY _SEH_TRY
@ -75,6 +71,7 @@ KiContinue(IN PCONTEXT Context,
} }
_SEH_HANDLE _SEH_HANDLE
{ {
/* Save the exception code */
Status = _SEH_GetExceptionCode(); Status = _SEH_GetExceptionCode();
} }
_SEH_END; _SEH_END;
@ -88,18 +85,17 @@ KiContinue(IN PCONTEXT Context,
NTSTATUS NTSTATUS
NTAPI NTAPI
KiRaiseException(PEXCEPTION_RECORD ExceptionRecord, KiRaiseException(IN PEXCEPTION_RECORD ExceptionRecord,
PCONTEXT Context, IN PCONTEXT Context,
PKEXCEPTION_FRAME ExceptionFrame, IN PKEXCEPTION_FRAME ExceptionFrame,
PKTRAP_FRAME TrapFrame, IN PKTRAP_FRAME TrapFrame,
BOOLEAN SearchFrames) IN BOOLEAN SearchFrames)
{ {
KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(); KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
CONTEXT LocalContext; CONTEXT LocalContext;
EXCEPTION_RECORD LocalExceptionRecord; EXCEPTION_RECORD LocalExceptionRecord;
ULONG ParameterCount, Size; ULONG ParameterCount, Size;
NTSTATUS Status = STATUS_SUCCESS; NTSTATUS Status = STATUS_SUCCESS;
DPRINT1("KiRaiseException\n");
/* Set up SEH */ /* Set up SEH */
_SEH_TRY _SEH_TRY
@ -143,10 +139,12 @@ KiRaiseException(PEXCEPTION_RECORD ExceptionRecord,
} }
_SEH_HANDLE _SEH_HANDLE
{ {
/* Get the exception code */
Status = _SEH_GetExceptionCode(); Status = _SEH_GetExceptionCode();
} }
_SEH_END; _SEH_END;
/* Make sure we didn't crash in SEH */
if (NT_SUCCESS(Status)) if (NT_SUCCESS(Status))
{ {
/* Convert the context record */ /* Convert the context record */

View file

@ -1,16 +1,12 @@
/* /*
* COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS Kernel
* PURPOSE: ReactOS kernel * LICENSE: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/ke/kqueue.c * FILE: ntoskrnl/ke/kqueue.c
* PURPOSE: Implement device queues * PURPOSE: Implement device queues
* * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
* PROGRAMMERS: Alex Ionescu (alex@relsoft.net) - Several optimizations and implement
* usage of Inserted flag + reformat and
* add debug output.
* David Welch (welch@mcmail.com)
*/ */
/* INCLUDES ****************************************************************/ /* INCLUDES ******************************************************************/
#include <ntoskrnl.h> #include <ntoskrnl.h>
#define NDEBUG #define NDEBUG
@ -20,16 +16,11 @@
/* /*
* @implemented * @implemented
*
* FUNCTION: Intializes a device queue
* ARGUMENTS:
* DeviceQueue = Device queue to initialize
*/ */
VOID VOID
STDCALL NTAPI
KeInitializeDeviceQueue(IN PKDEVICE_QUEUE DeviceQueue) KeInitializeDeviceQueue(IN PKDEVICE_QUEUE DeviceQueue)
{ {
/* Initialize the Header */ /* Initialize the Header */
DeviceQueue->Type = DeviceQueueObject; DeviceQueue->Type = DeviceQueueObject;
DeviceQueue->Size = sizeof(KDEVICE_QUEUE); DeviceQueue->Size = sizeof(KDEVICE_QUEUE);
@ -44,48 +35,41 @@ KeInitializeDeviceQueue(IN PKDEVICE_QUEUE DeviceQueue)
/* /*
* @implemented * @implemented
*
* FUNCTION: Inserts an entry in a device queue
* ARGUMENTS:
* DeviceQueue = Queue to insert the entry in
* DeviceQueueEntry = Entry to insert
* RETURNS: False is the device queue wasn't busy
* True otherwise
*/ */
BOOLEAN BOOLEAN
STDCALL NTAPI
KeInsertDeviceQueue(IN PKDEVICE_QUEUE DeviceQueue, KeInsertDeviceQueue(IN PKDEVICE_QUEUE DeviceQueue,
IN PKDEVICE_QUEUE_ENTRY DeviceQueueEntry) IN PKDEVICE_QUEUE_ENTRY DeviceQueueEntry)
{ {
KLOCK_QUEUE_HANDLE DeviceLock;
BOOLEAN Inserted; BOOLEAN Inserted;
ASSERT_DEVICE_QUEUE(DeviceQueue);
DPRINT("KeInsertDeviceQueue(DeviceQueue %x)\n", DeviceQueue); /* Lock the queue */
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); KiAcquireDeviceQueueLock(DeviceQueue, &DeviceLock);
/* Lock the Queue */
KeAcquireSpinLockAtDpcLevel(&DeviceQueue->Lock);
if (!DeviceQueue->Busy) {
/* Check if it's not busy */
if (!DeviceQueue->Busy)
{
/* Set it as busy */ /* Set it as busy */
Inserted = FALSE; Inserted = FALSE;
DeviceQueue->Busy = TRUE; DeviceQueue->Busy = TRUE;
}
} else { else
{
/* Insert it into the list */ /* Insert it into the list */
Inserted = TRUE; Inserted = TRUE;
InsertTailList(&DeviceQueue->DeviceListHead, InsertTailList(&DeviceQueue->DeviceListHead,
&DeviceQueueEntry->DeviceListEntry); &DeviceQueueEntry->DeviceListEntry);
} }
/* Sert the Insert state into the entry */ /* Sert the Insert state into the entry */
DeviceQueueEntry->Inserted = Inserted; DeviceQueueEntry->Inserted = Inserted;
/* Release lock and return */ /* Release the lock */
KeReleaseSpinLockFromDpcLevel(&DeviceQueue->Lock); KiReleaseDeviceQueueLock(&DeviceLock);
/* Return the state */
return Inserted; return Inserted;
} }
@ -93,29 +77,30 @@ KeInsertDeviceQueue(IN PKDEVICE_QUEUE DeviceQueue,
* @implemented * @implemented
*/ */
BOOLEAN BOOLEAN
STDCALL NTAPI
KeInsertByKeyDeviceQueue(IN PKDEVICE_QUEUE DeviceQueue, KeInsertByKeyDeviceQueue(IN PKDEVICE_QUEUE DeviceQueue,
IN PKDEVICE_QUEUE_ENTRY DeviceQueueEntry, IN PKDEVICE_QUEUE_ENTRY DeviceQueueEntry,
IN ULONG SortKey) IN ULONG SortKey)
{ {
KLOCK_QUEUE_HANDLE DeviceLock;
BOOLEAN Inserted; BOOLEAN Inserted;
ASSERT_DEVICE_QUEUE(DeviceQueue);
DPRINT("KeInsertByKeyDeviceQueue(DeviceQueue %x)\n", DeviceQueue); /* Lock the queue */
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); KiAcquireDeviceQueueLock(DeviceQueue, &DeviceLock);
/* Acquire the Lock */
KeAcquireSpinLockAtDpcLevel(&DeviceQueue->Lock);
/* Set the Sort Key */ /* Set the Sort Key */
DeviceQueueEntry->SortKey = SortKey; DeviceQueueEntry->SortKey = SortKey;
if (!DeviceQueue->Busy) { /* Check if it's not busy */
if (!DeviceQueue->Busy)
DeviceQueue->Busy=TRUE; {
/* Set it as busy */
Inserted = FALSE; Inserted = FALSE;
DeviceQueue->Busy = TRUE;
} else { }
else
{
/* Insert new entry after the last entry with SortKey less or equal to passed-in SortKey */ /* Insert new entry after the last entry with SortKey less or equal to passed-in SortKey */
InsertAscendingListFIFO(&DeviceQueue->DeviceListHead, InsertAscendingListFIFO(&DeviceQueue->DeviceListHead,
DeviceQueueEntry, DeviceQueueEntry,
@ -125,43 +110,38 @@ KeInsertByKeyDeviceQueue(IN PKDEVICE_QUEUE DeviceQueue,
Inserted = TRUE; Inserted = TRUE;
} }
/* Reset the Inserted State */ /* Release the lock */
DeviceQueueEntry->Inserted = Inserted; KiReleaseDeviceQueueLock(&DeviceLock);
/* Release Lock and Return */ /* Return the state */
KeReleaseSpinLockFromDpcLevel(&DeviceQueue->Lock);
return Inserted; return Inserted;
} }
/* /*
* @implemented * @implemented
*
* FUNCTION: Removes an entry from a device queue
* ARGUMENTS:
* DeviceQueue = Queue to remove the entry
* RETURNS: The removed entry
*/ */
PKDEVICE_QUEUE_ENTRY PKDEVICE_QUEUE_ENTRY
STDCALL NTAPI
KeRemoveDeviceQueue(IN PKDEVICE_QUEUE DeviceQueue) KeRemoveDeviceQueue(IN PKDEVICE_QUEUE DeviceQueue)
{ {
PLIST_ENTRY ListEntry; PLIST_ENTRY ListEntry;
PKDEVICE_QUEUE_ENTRY ReturnEntry; PKDEVICE_QUEUE_ENTRY ReturnEntry;
KLOCK_QUEUE_HANDLE DeviceLock;
ASSERT_DEVICE_QUEUE(DeviceQueue);
DPRINT("KeRemoveDeviceQueue(DeviceQueue %x)\n", DeviceQueue); /* Lock the queue */
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); KiAcquireDeviceQueueLock(DeviceQueue, &DeviceLock);
/* Acquire the Lock */
KeAcquireSpinLockAtDpcLevel(&DeviceQueue->Lock);
ASSERT(DeviceQueue->Busy); ASSERT(DeviceQueue->Busy);
/* An attempt to remove an entry from an empty (and busy) queue sets the queue idle */ /* Check if this is an empty queue */
if (IsListEmpty(&DeviceQueue->DeviceListHead)) { if (IsListEmpty(&DeviceQueue->DeviceListHead))
{
/* Set it to idle and return nothing*/
DeviceQueue->Busy = FALSE; DeviceQueue->Busy = FALSE;
ReturnEntry = NULL; ReturnEntry = NULL;
}
} else { else
{
/* Remove the Entry from the List */ /* Remove the Entry from the List */
ListEntry = RemoveHeadList(&DeviceQueue->DeviceListHead); ListEntry = RemoveHeadList(&DeviceQueue->DeviceListHead);
ReturnEntry = CONTAINING_RECORD(ListEntry, ReturnEntry = CONTAINING_RECORD(ListEntry,
@ -172,8 +152,10 @@ KeRemoveDeviceQueue(IN PKDEVICE_QUEUE DeviceQueue)
ReturnEntry->Inserted = FALSE; ReturnEntry->Inserted = FALSE;
} }
/* Release lock and Return */ /* Release the lock */
KeReleaseSpinLockFromDpcLevel(&DeviceQueue->Lock); KiReleaseDeviceQueueLock(&DeviceLock);
/* Return the entry */
return ReturnEntry; return ReturnEntry;
} }
@ -181,33 +163,34 @@ KeRemoveDeviceQueue(IN PKDEVICE_QUEUE DeviceQueue)
* @implemented * @implemented
*/ */
PKDEVICE_QUEUE_ENTRY PKDEVICE_QUEUE_ENTRY
STDCALL NTAPI
KeRemoveByKeyDeviceQueue(IN PKDEVICE_QUEUE DeviceQueue, KeRemoveByKeyDeviceQueue(IN PKDEVICE_QUEUE DeviceQueue,
IN ULONG SortKey) IN ULONG SortKey)
{ {
PLIST_ENTRY ListEntry; PLIST_ENTRY ListEntry;
PKDEVICE_QUEUE_ENTRY ReturnEntry; PKDEVICE_QUEUE_ENTRY ReturnEntry;
KLOCK_QUEUE_HANDLE DeviceLock;
ASSERT_DEVICE_QUEUE(DeviceQueue);
DPRINT("KeRemoveByKeyDeviceQueue(DeviceQueue %x)\n", DeviceQueue); /* Lock the queue */
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); KiAcquireDeviceQueueLock(DeviceQueue, &DeviceLock);
/* Acquire the Lock */
KeAcquireSpinLockAtDpcLevel(&DeviceQueue->Lock);
ASSERT(DeviceQueue->Busy); ASSERT(DeviceQueue->Busy);
/* An attempt to remove an entry from an empty (and busy) queue sets the queue idle */ /* Check if this is an empty queue */
if (IsListEmpty(&DeviceQueue->DeviceListHead)) { if (IsListEmpty(&DeviceQueue->DeviceListHead))
{
/* Set it to idle and return nothing*/
DeviceQueue->Busy = FALSE; DeviceQueue->Busy = FALSE;
ReturnEntry = NULL; ReturnEntry = NULL;
}
} else { else
{
/* Find entry with SortKey greater than or equal to the passed-in SortKey */ /* Find entry with SortKey greater than or equal to the passed-in SortKey */
LIST_FOR_EACH(ReturnEntry, &DeviceQueue->DeviceListHead, KDEVICE_QUEUE_ENTRY, DeviceListEntry) LIST_FOR_EACH(ReturnEntry, &DeviceQueue->DeviceListHead, KDEVICE_QUEUE_ENTRY, DeviceListEntry)
{ {
/* Check if keys match */ /* Check if keys match */
if (ReturnEntry->SortKey >= SortKey) { if (ReturnEntry->SortKey >= SortKey)
{
/* We found it, so just remove it */ /* We found it, so just remove it */
RemoveEntryList(&ReturnEntry->DeviceListEntry); RemoveEntryList(&ReturnEntry->DeviceListEntry);
break; break;
@ -215,8 +198,8 @@ KeRemoveByKeyDeviceQueue (IN PKDEVICE_QUEUE DeviceQueue,
} }
/* Check if we found something */ /* Check if we found something */
if (!ReturnEntry) { if (!ReturnEntry)
{
/* Not found, return the first entry */ /* Not found, return the first entry */
ListEntry = RemoveHeadList(&DeviceQueue->DeviceListHead); ListEntry = RemoveHeadList(&DeviceQueue->DeviceListHead);
ReturnEntry = CONTAINING_RECORD(ListEntry, ReturnEntry = CONTAINING_RECORD(ListEntry,
@ -228,48 +211,97 @@ KeRemoveByKeyDeviceQueue (IN PKDEVICE_QUEUE DeviceQueue,
ReturnEntry->Inserted = FALSE; ReturnEntry->Inserted = FALSE;
} }
/* Release lock and Return */ /* Release the lock */
KeReleaseSpinLockFromDpcLevel(&DeviceQueue->Lock); KiReleaseDeviceQueueLock(&DeviceLock);
return ReturnEntry;
}
/* /* Return the entry */
* @unimplemented return ReturnEntry;
*/
PKDEVICE_QUEUE_ENTRY
STDCALL
KeRemoveByKeyDeviceQueueIfBusy(IN PKDEVICE_QUEUE DeviceQueue,
IN ULONG SortKey)
{
UNIMPLEMENTED;
return 0;
} }
/* /*
* @implemented * @implemented
*/ */
BOOLEAN STDCALL PKDEVICE_QUEUE_ENTRY
NTAPI
KeRemoveByKeyDeviceQueueIfBusy(IN PKDEVICE_QUEUE DeviceQueue,
IN ULONG SortKey)
{
PLIST_ENTRY ListEntry;
PKDEVICE_QUEUE_ENTRY ReturnEntry;
KLOCK_QUEUE_HANDLE DeviceLock;
ASSERT_DEVICE_QUEUE(DeviceQueue);
/* 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
{
/* Find entry with SortKey greater than or equal to the passed-in SortKey */
LIST_FOR_EACH(ReturnEntry, &DeviceQueue->DeviceListHead, KDEVICE_QUEUE_ENTRY, DeviceListEntry)
{
/* Check if keys match */
if (ReturnEntry->SortKey >= SortKey)
{
/* We found it, so just remove it */
RemoveEntryList(&ReturnEntry->DeviceListEntry);
break;
}
}
/* Check if we found something */
if (!ReturnEntry)
{
/* Not found, return the first entry */
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
*/
BOOLEAN
NTAPI
KeRemoveEntryDeviceQueue(IN PKDEVICE_QUEUE DeviceQueue, KeRemoveEntryDeviceQueue(IN PKDEVICE_QUEUE DeviceQueue,
IN PKDEVICE_QUEUE_ENTRY DeviceQueueEntry) IN PKDEVICE_QUEUE_ENTRY DeviceQueueEntry)
{ {
KIRQL OldIrql;
BOOLEAN OldState; BOOLEAN OldState;
KLOCK_QUEUE_HANDLE DeviceLock;
ASSERT_DEVICE_QUEUE(DeviceQueue);
DPRINT("KeRemoveEntryDeviceQueue(DeviceQueue %x)\n", DeviceQueue); /* Lock the queue */
ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); KiAcquireDeviceQueueLock(DeviceQueue, &DeviceLock);
ASSERT(DeviceQueue->Busy);
/* Acquire the Lock */
KeAcquireSpinLock(&DeviceQueue->Lock, &OldIrql);
/* Check/Set Old State */
if ((OldState = DeviceQueueEntry->Inserted)) {
/* Check the insertion state */
OldState = DeviceQueueEntry->Inserted;
if (OldState)
{
/* Remove it */ /* Remove it */
DeviceQueueEntry->Inserted = FALSE; DeviceQueueEntry->Inserted = FALSE;
RemoveEntryList(&DeviceQueueEntry->DeviceListEntry); RemoveEntryList(&DeviceQueueEntry->DeviceListEntry);
} }
/* Unlock and return old state */ /* Unlock and return old state */
KeReleaseSpinLock(&DeviceQueue->Lock, OldIrql); KiReleaseDeviceQueueLock(&DeviceLock);
return OldState; return OldState;
} }