[AUDIT] - Irq.c is another lame wrapper.

- Remlock's code was written by Filip Navara and is clean. My additions are based on wdm.h and only add size checks and fix two visible bugs.
- Add basic support/detection for debug I/O remove blocks (we bugcheck if we identify one though).
- Simplify IoReleaseRemoveLockAndWaitEx
- Remove locks are SYNCH events, not Notification events!
- Make sure IoConnectInterrupt returns NULL to the caller on failure.

svn path=/trunk/; revision=22724
This commit is contained in:
Alex Ionescu 2006-06-30 18:54:34 +00:00
parent ea4351d9bd
commit 991efbb62a
3 changed files with 175 additions and 142 deletions

View file

@ -208,6 +208,27 @@ typedef struct _IO_WORKITEM
PVOID Context;
} IO_WORKITEM, *PIO_WORKITEM;
//
// I/O Wrapper around the Kernel Interrupt
//
typedef struct _IO_INTERRUPT
{
KINTERRUPT FirstInterrupt;
PKINTERRUPT Interrupt[MAXIMUM_PROCESSORS];
KSPIN_LOCK SpinLock;
} IO_INTERRUPT, *PIO_INTERRUPT;
//
// To simplify matters, the kernel is made to support both the checked and free
// version of the I/O Remove Lock in the same binary. This structure includes
// both, since the DDK has the structure with a compile-time #ifdef.
//
typedef struct _EXTENDED_IO_REMOVE_LOCK
{
IO_REMOVE_LOCK_COMMON_BLOCK Common;
IO_REMOVE_LOCK_DBG_BLOCK Dbg;
} EXTENDED_IO_REMOVE_LOCK, *PEXTENDED_IO_REMOVE_LOCK;
//
// Dummy File Object used inside the Open Packet so that OB knows how to
// deal with the Object Pointer even though it's not a real file.

View file

@ -1,11 +1,9 @@
/* $Id$
*
* 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/io/irq.c
* PURPOSE: IRQ handling
*
* PROGRAMMERS: David Welch (welch@mcmail.com)
* PURPOSE: I/O Wrappers (called Completion Ports) for Kernel Queues
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES *****************************************************************/
@ -14,58 +12,24 @@
#define NDEBUG
#include <internal/debug.h>
/* TYPES ********************************************************************/
typedef struct _IO_INTERRUPT
{
KINTERRUPT FirstInterrupt;
PKINTERRUPT Interrupt[MAXIMUM_PROCESSORS];
KSPIN_LOCK SpinLock;
} IO_INTERRUPT, *PIO_INTERRUPT;
/* FUNCTIONS *****************************************************************/
/*
* FUNCTION: Registers a driver's isr to be called when its device interrupts
* ARGUMENTS:
* InterruptObject (OUT) = Points to the interrupt object created on
* return
* ServiceRoutine = Routine to be called when the device interrupts
* ServiceContext = Parameter to be passed to ServiceRoutine
* SpinLock = Initalized spinlock that will be used to synchronize
* access between the isr and other driver routines. This is
* required if the isr handles more than one vector or the
* driver has more than one isr
* Vector = Interrupt vector to allocate
* (returned from HalGetInterruptVector)
* Irql = DIRQL returned from HalGetInterruptVector
* SynchronizeIrql = DIRQL at which the isr will execute. This must
* be the highest of all the DIRQLs returned from
* HalGetInterruptVector if the driver has multiple
* isrs
* InterruptMode = Specifies if the interrupt is LevelSensitive or
* Latched
* ShareVector = Specifies if the vector can be shared
* ProcessorEnableMask = Processors on the isr can run
* FloatingSave = TRUE if the floating point stack should be saved when
* the isr runs. Must be false for x86 drivers
* RETURNS: Status
* IRQL: PASSIVE_LEVEL
*
* @implemented
*/
NTSTATUS
STDCALL
IoConnectInterrupt(PKINTERRUPT* InterruptObject,
PKSERVICE_ROUTINE ServiceRoutine,
PVOID ServiceContext,
PKSPIN_LOCK SpinLock,
ULONG Vector,
KIRQL Irql,
KIRQL SynchronizeIrql,
KINTERRUPT_MODE InterruptMode,
BOOLEAN ShareVector,
KAFFINITY ProcessorEnableMask,
BOOLEAN FloatingSave)
NTAPI
IoConnectInterrupt(OUT PKINTERRUPT *InterruptObject,
IN PKSERVICE_ROUTINE ServiceRoutine,
IN PVOID ServiceContext,
IN PKSPIN_LOCK SpinLock,
IN ULONG Vector,
IN KIRQL Irql,
IN KIRQL SynchronizeIrql,
IN KINTERRUPT_MODE InterruptMode,
IN BOOLEAN ShareVector,
IN KAFFINITY ProcessorEnableMask,
IN BOOLEAN FloatingSave)
{
PKINTERRUPT Interrupt;
PKINTERRUPT InterruptUsed;
@ -74,10 +38,10 @@ IoConnectInterrupt(PKINTERRUPT* InterruptObject,
BOOLEAN FirstRun = TRUE;
ULONG count;
LONG i;
PAGED_CODE();
DPRINT("IoConnectInterrupt(Vector %x)\n",Vector);
/* Assume failure */
*InterruptObject = NULL;
/* Convert the Mask */
ProcessorEnableMask &= ((1 << KeNumberProcessors) - 1);
@ -96,17 +60,10 @@ IoConnectInterrupt(PKINTERRUPT* InterruptObject,
(count - 1)* sizeof(KINTERRUPT) +
sizeof(IO_INTERRUPT),
TAG_KINTERRUPT);
if (!IoInterrupt) return(STATUS_INSUFFICIENT_RESOURCES);
if (!IoInterrupt) return STATUS_INSUFFICIENT_RESOURCES;
/* Select which Spinlock to use */
if (SpinLock)
{
SpinLockUsed = SpinLock;
}
else
{
SpinLockUsed = &IoInterrupt->SpinLock;
}
SpinLockUsed = SpinLock ? SpinLock : &IoInterrupt->SpinLock;
/* We first start with a built-in Interrupt inside the I/O Structure */
*InterruptObject = &IoInterrupt->FirstInterrupt;
@ -152,6 +109,8 @@ IoConnectInterrupt(PKINTERRUPT* InterruptObject,
/* Far enough, so disconnect everything */
IoDisconnectInterrupt(&IoInterrupt->FirstInterrupt);
}
/* And fail */
return STATUS_INVALID_PARAMETER;
}
@ -173,20 +132,14 @@ IoConnectInterrupt(PKINTERRUPT* InterruptObject,
}
/*
* FUNCTION: Releases a drivers isr
* ARGUMENTS:
* InterruptObject = isr to release
*
* @implemented
*/
VOID
STDCALL
NTAPI
IoDisconnectInterrupt(PKINTERRUPT InterruptObject)
{
LONG i;
PIO_INTERRUPT IoInterrupt;
PAGED_CODE();
/* Get the I/O Interrupt */
@ -200,8 +153,10 @@ IoDisconnectInterrupt(PKINTERRUPT InterruptObject)
/* Now disconnect the others */
for (i = 0; i < KeNumberProcessors; i++)
{
/* Make sure one was registered */
if (IoInterrupt->Interrupt[i])
{
/* Disconnect it */
KeDisconnectInterrupt(&InterruptObject[i]);
}
}

View file

@ -1,17 +1,16 @@
/* $Id$
*
* 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/io/remlock.c
* PURPOSE: Remove Lock functions
*
* PROGRAMMERS: Filip Navara (xnavara@volny.cz)
* PURPOSE: Remove Lock Support
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
* Filip Navara (navaraf@reactos.org)
*/
/* INCLUDES ******************************************************************/
#define NDEBUG
#include <ntoskrnl.h>
#define NDEBUG
#include <internal/debug.h>
/* FUNCTIONS *****************************************************************/
@ -20,42 +19,78 @@
* @implemented
*/
VOID
STDCALL
IoInitializeRemoveLockEx(
IN PIO_REMOVE_LOCK RemoveLock,
NTAPI
IoInitializeRemoveLockEx(IN PIO_REMOVE_LOCK RemoveLock,
IN ULONG AllocateTag,
IN ULONG MaxLockedMinutes,
IN ULONG HighWatermark,
IN ULONG RemlockSize)
{
DPRINT("IoInitializeRemoveLockEx called\n");
RtlZeroMemory(RemoveLock, RemlockSize);
RemoveLock->Common.IoCount = 1;
KeInitializeEvent(&RemoveLock->Common.RemoveEvent, NotificationEvent, FALSE);
PEXTENDED_IO_REMOVE_LOCK Lock = (PEXTENDED_IO_REMOVE_LOCK)RemoveLock;
PAGED_CODE();
/* Check if this is a debug lock */
if (RemlockSize == sizeof(IO_REMOVE_LOCK_DBG_BLOCK))
{
/* Clear the lock */
RtlZeroMemory(Lock, RemlockSize);
/* Setup debug parameters */
Lock->Dbg.HighWatermark = HighWatermark;
Lock->Dbg.MaxLockedTicks = MaxLockedMinutes * 600000000;
Lock->Dbg.AllocateTag = AllocateTag;
KeInitializeSpinLock(&Lock->Dbg.Spin);
}
else
{
/* Otherwise, setup a free block */
Lock->Common.Removed = FALSE;
Lock->Common.IoCount = 1;
KeInitializeEvent(&Lock->Common.RemoveEvent,
SynchronizationEvent,
FALSE);
}
}
/*
* @implemented
*/
NTSTATUS
STDCALL
IoAcquireRemoveLockEx(
IN PIO_REMOVE_LOCK RemoveLock,
NTAPI
IoAcquireRemoveLockEx(IN PIO_REMOVE_LOCK RemoveLock,
IN OPTIONAL PVOID Tag,
IN LPCSTR File,
IN ULONG Line,
IN ULONG RemlockSize)
{
DPRINT("IoAcquireRemoveLockEx called\n");
InterlockedIncrement(&RemoveLock->Common.IoCount);
if (RemoveLock->Common.Removed)
PEXTENDED_IO_REMOVE_LOCK Lock = (PEXTENDED_IO_REMOVE_LOCK)RemoveLock;
/* Increase the lock count */
InterlockedIncrement(&Lock->Common.IoCount);
if (!Lock->Common.Removed)
{
if (InterlockedDecrement(&RemoveLock->Common.IoCount) == 0)
/* Check what kind of lock this is */
if (RemlockSize == sizeof(IO_REMOVE_LOCK_DBG_BLOCK))
{
KeSetEvent(&RemoveLock->Common.RemoveEvent, IO_NO_INCREMENT, FALSE);
/* FIXME: Not yet supported */
DPRINT1("UNIMPLEMENTED\n");
KEBUGCHECK(0);
}
}
else
{
/* Otherwise, decrement the count and check if it's gone */
if (!InterlockedDecrement(&Lock->Common.IoCount))
{
/* Signal the event */
KeSetEvent(&Lock->Common.RemoveEvent, IO_NO_INCREMENT, FALSE);
}
/* Return pending delete */
return STATUS_DELETE_PENDING;
}
/* Otherwise, return success */
return STATUS_SUCCESS;
}
@ -63,19 +98,26 @@ IoAcquireRemoveLockEx(
* @implemented
*/
VOID
STDCALL
IoReleaseRemoveLockEx(
IN PIO_REMOVE_LOCK RemoveLock,
NTAPI
IoReleaseRemoveLockEx(IN PIO_REMOVE_LOCK RemoveLock,
IN PVOID Tag,
IN ULONG RemlockSize)
{
LONG IoCount;
PEXTENDED_IO_REMOVE_LOCK Lock = (PEXTENDED_IO_REMOVE_LOCK)RemoveLock;
DPRINT("IoReleaseRemoveLockEx called\n");
IoCount = InterlockedDecrement(&RemoveLock->Common.IoCount);
if (IoCount == 0)
/* Check what kind of lock this is */
if (RemlockSize == sizeof(IO_REMOVE_LOCK_DBG_BLOCK))
{
KeSetEvent(&RemoveLock->Common.RemoveEvent, IO_NO_INCREMENT, FALSE);
/* FIXME: Not yet supported */
DPRINT1("UNIMPLEMENTED\n");
KEBUGCHECK(0);
}
/* Decrement the lock count */
if (!InterlockedDecrement(&Lock->Common.IoCount));
{
/* Signal the event */
KeSetEvent(&Lock->Common.RemoveEvent, IO_NO_INCREMENT, FALSE);
}
}
@ -83,18 +125,33 @@ IoReleaseRemoveLockEx(
* @implemented
*/
VOID
STDCALL
IoReleaseRemoveLockAndWaitEx(
IN PIO_REMOVE_LOCK RemoveLock,
NTAPI
IoReleaseRemoveLockAndWaitEx(IN PIO_REMOVE_LOCK RemoveLock,
IN PVOID Tag,
IN ULONG RemlockSize)
{
DPRINT("IoReleaseRemoveLockAndWaitEx called\n");
RemoveLock->Common.Removed = TRUE;
InterlockedDecrement(&RemoveLock->Common.IoCount);
IoReleaseRemoveLockEx(RemoveLock, Tag, RemlockSize);
KeWaitForSingleObject(&RemoveLock->Common.RemoveEvent, Executive, KernelMode,
FALSE, NULL);
PEXTENDED_IO_REMOVE_LOCK Lock = (PEXTENDED_IO_REMOVE_LOCK)RemoveLock;
PAGED_CODE();
/* Remove the lock and decrement the count */
Lock->Common.Removed = TRUE;
if (InterlockedDecrement(&Lock->Common.IoCount) > 0)
{
/* Wait for it */
KeWaitForSingleObject(&Lock->Common.RemoveEvent,
Executive,
KernelMode,
FALSE,
NULL);
}
/* Check what kind of lock this is */
if (RemlockSize == sizeof(IO_REMOVE_LOCK_DBG_BLOCK))
{
/* FIXME: Not yet supported */
DPRINT1("UNIMPLEMENTED\n");
KEBUGCHECK(0);
}
}
/* EOF */