typedef struct _KDEVICE_QUEUE { //IRP队列来实现串行
CSHORT Type;
CSHORT Size;
LIST_ENTRY devicelisthead;
KSPIN_LOCK Lock;
BOOLEAN Busy;
} KDEVICE_QUEUE, *PKDEVICE_QUEUE, *RESTRICTED_POINTER PRKDEVICE_QUEUE;
typedef struct _KDEVICE_QUEUE_ENTRY{
LIST_ENTRY DeviceListEntry;
ULONG SortKey;
BOOLEAN Inserted;
}KDEVICE_QUEUE_ENTRY, *PKDEVICE_QUEUE_ENTRY, *RESTRICTED_POINTER PRKDEVICE_QUEUE_ENTRY;
VOID IoStartPacket(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PULONG Key OPTIONAL,
IN PDRIVER_CANCEL CancelFunction OPTIONAL)
{
KIRQL oldIrql;
KIRQL cancelIrql = PASSIVE_LEVEL;
BOOLEAN i;
KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
if (CancelFunction)
{
IoAcquireCancelSpinLock( &cancelIrql );
Irp->CancelRoutine = CancelFunction;
}
i = KeInsertDeviceQueue(&DeviceObject->DeviceQueue, &Irp->Tail.Overlay.DeviceQueueEntry);
if (!i)
{
DeviceObject->CurrentIrp = Irp;
if (CancelFunction)
{
IoReleaseCancelSpinLock( cancelIrql );
}
DeviceObject->DriverObject->DriverStartIo(DeviceObject, Irp);
}
else
{
if (CancelFunction)
{
if (Irp->Cancel)
{
Irp->CancelIrql = cancelIrql;
Irp->CancelRoutine = (PDRIVER_CANCEL) NULL;
CancelFunction( DeviceObject, Irp );
}
else
{
IoReleaseCancelSpinLock( cancelIrql );
}
}
}
KeLowerIrql( oldIrql );
}
BOOLEAN NTAPI KeInsertDeviceQueue(IN PKDEVICE_QUEUE DeviceQueue,
IN PKDEVICE_QUEUE_ENTRY DeviceQueueEntry)
{
KLOCK_QUEUE_HANDLE DeviceLock;
BOOLEAN Inserted;
ASSERT_DEVICE_QUEUE(DeviceQueue);
/* 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; //返回TRUE表示已排入队列,FALSE表示可以继续操作
}
VOID IopStartNextPacket(IN PDEVICE_OBJECT DeviceObject, IN LOGICAL Cancelable)
{
KIRQL cancelIrql = PASSIVE_LEVEL;
PIRP irp;
PKDEVICE_QUEUE_ENTRY packet;
if (Cancelable)
{
IoAcquireCancelSpinLock( &cancelIrql );
}
DeviceObject->CurrentIrp = (PIRP) NULL;
packet = KeRemoveDeviceQueue( &DeviceObject->DeviceQueue );
if (packet)
{
irp = CONTAINING_RECORD( packet, IRP, Tail.Overlay.DeviceQueueEntry );
DeviceObject->CurrentIrp = irp;
if (Cancelable)
{
IoReleaseCancelSpinLock( cancelIrql );
}
DeviceObject->DriverObject->DriverStartIo( DeviceObject, irp );
}
else
{
if (Cancelable)
{
IoReleaseCancelSpinLock( cancelIrql );
}
}
}
宏 CONTAINING_RECORD 的用处其实还是相当大的, 而且很是方便, 它的主要作用是:根据结构体中的某成员的地址来推算出该结构体整体的地址!
#define CONTAINING_RECORD(addr,type,field) ((type*)((unsigned char*)addr - (unsigned long)&((type*)0)->field))
// addr: 结构体中某个成员变量的地址
// type: 结构体的原型
// field: 结构体的某个成员(与前面相同)