Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

158 lines
5.5 KiB

#ifndef __IrpQueue_h__
#define __IrpQueue_h__
extern "C"
{
#include <wdm.h>
}
class CTempIrpQueue
{
friend class CGuardedIrpQueue;
public:
CTempIrpQueue()
{
InitializeListHead(&m_QueueHead);
m_fLIFO = FALSE;
}
~CTempIrpQueue()
{
ASSERT(IsListEmpty(&m_QueueHead));
}
PIRP Remove();
private:
LIST_ENTRY m_QueueHead;
BOOLEAN m_fLIFO;
};
class CGuardedIrpQueue
{
public:
friend void _stdcall DriverCancel(PDEVICE_OBJECT pDeviceObject, PIRP pIrp);
friend class CShareIrpQueueSpinLock;
typedef void (_stdcall*PFN_DEC_IRP_COUNT)(PVOID pvContext);
//c'tor's and d'tors are often not called in drivers, either
//because the instance is global, or because they are a part of a
//larger structure (such as a DeviceExtension) which is allocated as
//an unstructured block of memory, so we insist that they do nothing.
//call Init and Destroy instead. (A more systematic approach to C++
//in a driver could solve this problem).
CGuardedIrpQueue(){}
~CGuardedIrpQueue(){}
void Init(int iFlags, PFN_DEC_IRP_COUNT pfnDecIrpCount, PVOID pvContext);
void Destroy(NTSTATUS NtStatus=STATUS_DELETE_PENDING);
NTSTATUS Add(PIRP pIrp);
PIRP Remove();
PIRP RemoveByPointer(PIRP pIrp);
ULONG RemoveByFileObject(PFILE_OBJECT pFileObject, CTempIrpQueue *pTempIrpQueue);
ULONG RemoveAll(CTempIrpQueue *pTempIrpQueue);
void CancelIrp(PIRP pIrp);
void CancelByFileObject(PFILE_OBJECT pFileObject);
void CancelAll(NTSTATUS NtStatus = STATUS_CANCELLED);
//Flags for constructor
static const int CANCEL_IRPS_ON_DELETE; //= 0x00000001;
static const int PRESERVE_QUEUE_ORDER; //= 0x00000002;
static const int LIFO_QUEUE_ORDER; //= 0x00000004;
private:
//The real cancel routine
void CancelRoutine(PIRP pIrp);
//Implementation sans spin locks
NTSTATUS AddImpl(PIRP pIrp, KIRQL OldIrql);
PIRP RemoveImpl();
PIRP RemoveByPointerImpl(PIRP pIrp);
ULONG RemoveByFileObjectImpl(PFILE_OBJECT pFileObject, CTempIrpQueue *pTempIrpQueue);
ULONG RemoveAllImpl(CTempIrpQueue *pTempIrpQueue);
LIST_ENTRY m_QueueHead;
KSPIN_LOCK m_QueueLock;
int m_iFlags;
PFN_DEC_IRP_COUNT m_pfnDecIrpCount;
PVOID m_pvContext;
};
//
//
// @class CShareIrpQueueSpinLock | Allows sharing of SpinLock from CGuardedIrpQueue
//
// @topic Using CShareIrpQueueSpinLock |
// ** Should only be instantiated on the stack.
// ** A single instance should be used by only one thread. i.e. no static instances
// ** Inside a single function, do not CGuardedIrpQueue's accessor, rather
// ** use the interface provided by CShareIrpQueueSpinLock
//
class CShareIrpQueueSpinLock
{
public:
CShareIrpQueueSpinLock(CGuardedIrpQueue *pIrpQueue) :
m_pIrpQueue(pIrpQueue),
m_fIsHeld(FALSE)
#if (DBG==1)
,m_debug_ThreadContext(KeGetCurrentThread())
#endif
{}
~CShareIrpQueueSpinLock()
{
ASSERT(!m_fIsHeld && "You must release (or AddAndRelease) the spin lock before this instance goes of scope!");
ASSERT(m_debug_ThreadContext==KeGetCurrentThread() && "class instance should be on local stack" );
}
//Functions to access mutex
void Acquire()
{
ASSERT(!m_fIsHeld && "An attempt to acquire a spin lock twice in the same thread!");
ASSERT(m_debug_ThreadContext==KeGetCurrentThread() && "class instance should be on local stack!");
m_fIsHeld = TRUE;
KeAcquireSpinLock(&m_pIrpQueue->m_QueueLock, &m_OldIrql);
}
void Release()
{
ASSERT(m_fIsHeld && "An attempt to release a spin lock that had not been acquired, (reminder: AddAndRelease also Releases)!");
ASSERT(m_debug_ThreadContext==KeGetCurrentThread() && "class instance should be on local stack!");
m_fIsHeld = FALSE;
KeReleaseSpinLock(&m_pIrpQueue->m_QueueLock, m_OldIrql);
}
//Functions to access IrpQueue
NTSTATUS AddAndRelease(PIRP pIrp)
{
ASSERT(m_fIsHeld && "Use CGuardedIrpQueue if you do not need to share the SpinLock!");
ASSERT(m_debug_ThreadContext==KeGetCurrentThread() && "class instance should be on local stack!");
m_fIsHeld=FALSE;
return m_pIrpQueue->AddImpl(pIrp, m_OldIrql);
}
PIRP Remove()
{
ASSERT(m_fIsHeld && "Use CGuardedIrpQueue if you do not need to share the SpinLock!");
ASSERT(m_debug_ThreadContext==KeGetCurrentThread() && "class instance should be on local stack!");
return m_pIrpQueue->RemoveImpl();
}
PIRP RemoveByPointer(PIRP pIrp)
{
ASSERT(m_fIsHeld && "Use CGuardedIrpQueue if you do not need to share the SpinLock!");
ASSERT(m_debug_ThreadContext==KeGetCurrentThread() && "class instance should be on local stack!");
return m_pIrpQueue->RemoveByPointerImpl(pIrp);
}
ULONG RemoveByFileObject(PFILE_OBJECT pFileObject, CTempIrpQueue *pTempIrpQueue)
{
ASSERT(m_fIsHeld && "Use CGuardedIrpQueue if you do not need to share the SpinLock!");
ASSERT(m_debug_ThreadContext==KeGetCurrentThread() && "class instance should be on local stack!");
return m_pIrpQueue->RemoveByFileObjectImpl(pFileObject,pTempIrpQueue);
}
ULONG RemoveAll(CTempIrpQueue *pTempIrpQueue)
{
ASSERT(m_fIsHeld && "Use CGuardedIrpQueue if you do not need to share the SpinLock!");
ASSERT(m_debug_ThreadContext==KeGetCurrentThread() && "class instance should be on local stack!");
return m_pIrpQueue->RemoveAllImpl(pTempIrpQueue);
}
private:
CGuardedIrpQueue *m_pIrpQueue;
BOOLEAN m_fIsHeld;
KIRQL m_OldIrql;
#if (DBG==1)
PKTHREAD m_debug_ThreadContext;
#endif
};
#endif //__IrpQueue_h__