WindowsデバイスドライバStartIO、IRP同期/非同期アップロード
5744 ワード
プログラムの位置:http://download.csdn.net/detail/dijkstar/8568463
StartIOは非常に使いやすいです.本質的には、アプリケーション層から渡された読み取り要求、書き込み要求、IOCTL要求を一つの列に置いて、WDM内部シリアルスケジューリングによって、自分でこのような要求キューを維持しないようにしました.以下は駆動層におけるStartIOの内容です.
【同期ブロック】呼び出しは、ソケットの標準関数方式のように、recvfromのように、呼び出しが完了するまで戻ってきます.この目的を達成するためには、CreateFileの場合は、最後から2番目のパラメータ【不可】にFILE_が付いている必要があります.FLAG_OVERLAPPEDマーク;このような呼び方は最も簡単で、一般的に自分でアプリケーション層でスレッドを開く必要があります.スレッドのwhileサイクルではReadFile()はブロックコールなので、このループはCPUを消費しません.
【非同期はすぐに戻ります】呼び出し、ReadFile()を呼び出した場合、すぐに戻ります.その目的を達成するためには、CreateFileの場合は、最後から2番目のパラメータにFILE_が付いている必要があります.FLAG_OVERLAPPEDマーク;すぐに戻るので、自分で待ちイベントを作成してブロックを実現します.以下はアプリケーション層非同期/同期呼び出しの実現です.先にコメントしたのは非同期方式で、後の注釈が開かれているのは同期方式です.
StartIOは非常に使いやすいです.本質的には、アプリケーション層から渡された読み取り要求、書き込み要求、IOCTL要求を一つの列に置いて、WDM内部シリアルスケジューリングによって、自分でこのような要求キューを維持しないようにしました.以下は駆動層におけるStartIOの内容です.
#pragma LOCKEDCODE
VOID HelloDDKStartIO(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)
{
PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
KIRQL oldirql;
//KdPrint(("Enter HelloDDKStartIO
"));
// cancel
IoAcquireCancelSpinLock(&oldirql);
if (Irp!=DeviceObject->CurrentIrp||Irp->Cancel)
{
// IRP, ,
// , StartIO
IoReleaseCancelSpinLock(oldirql);
KdPrint(("Leave HelloDDKStartIO
"));
return;
}else
{
// IRP,
// IRP NULL
IoSetCancelRoutine(Irp,NULL);
IoReleaseCancelSpinLock(oldirql);
}
switch(IrpStack->MajorFunction)
{
case IRP_MJ_READ:
{
unsigned char i=0;
KEVENT event;
static unsigned char k = 0x30;// '0'
KeInitializeEvent(&event,NotificationEvent,FALSE);
// 2
LARGE_INTEGER timeout;
timeout.QuadPart = -2*1000*1000*10;
// 3 , IRP 2
KeWaitForSingleObject(&event,Executive,KernelMode,FALSE,&timeout);
// ,
ULONG uLen = IrpStack->Parameters.Read.Length;
k++;
for(i=0; i<uLen; i++)
{
unsigned char tmp= i+k;//0x30, 0x31,.... ,
unsigned char *p=(unsigned char *)Irp->AssociatedIrp.SystemBuffer;
memcpy(&p[i], &tmp, 1);
}
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = uLen; //
IoCompleteRequest(Irp,IO_NO_INCREMENT);
break;
}
case IRP_MJ_WRITE:
// ,
//..............
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0; //
IoCompleteRequest(Irp,IO_NO_INCREMENT);
break;
case IRP_MJ_DEVICE_CONTROL:
//..............
//IOCTL ,
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0; //
IoCompleteRequest(Irp,IO_NO_INCREMENT);
break;
}
// IRP, StartIo
IoStartNextPacket(DeviceObject,TRUE);
//KdPrint(("Leave HelloDDKStartIO
"));
}
StartIOを実現するために、「IRP MJuREAD」の要求を持って、この派遣処理においては、まずこの読み出し要求を保留し、その後、その要求をシステムのキューに挿入し、最後に保留状態に戻ります.NTSTATUS HelloDDKRead(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp)
{
//KdPrint(("Enter HelloDDKRead
"));
PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
pDevObj->DeviceExtension;
// IRP
IoMarkIrpPending(pIrp);
// IRP
IoStartPacket(pDevObj,pIrp,0,OnCancelIRP);
//KdPrint(("Leave HelloDDKRead
"));
// pending
return STATUS_PENDING;
}
このように、アプリケーション層に対応するReadFile()処理には、2つの呼び出し選択があり、1つは「同期ブロッキング」呼び出しであり、1つは「非同期即時復帰」コールである.【同期ブロック】呼び出しは、ソケットの標準関数方式のように、recvfromのように、呼び出しが完了するまで戻ってきます.この目的を達成するためには、CreateFileの場合は、最後から2番目のパラメータ【不可】にFILE_が付いている必要があります.FLAG_OVERLAPPEDマーク;このような呼び方は最も簡単で、一般的に自分でアプリケーション層でスレッドを開く必要があります.スレッドのwhileサイクルではReadFile()はブロックコールなので、このループはCPUを消費しません.
【非同期はすぐに戻ります】呼び出し、ReadFile()を呼び出した場合、すぐに戻ります.その目的を達成するためには、CreateFileの場合は、最後から2番目のパラメータにFILE_が付いている必要があります.FLAG_OVERLAPPEDマーク;すぐに戻るので、自分で待ちイベントを作成してブロックを実現します.以下はアプリケーション層非同期/同期呼び出しの実現です.先にコメントしたのは非同期方式で、後の注釈が開かれているのは同期方式です.
typedef struct
{
HANDLE hDevice;
int inx;
}MY_TYPE;
UINT WINAPI Thread(LPVOID context)
{
MY_TYPE *p = (MY_TYPE *)context;
printf(" : %d
", p->inx);
DWORD dwStart = GetTickCount();
// 2
OVERLAPPED overlap={0};
overlap.hEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
UCHAR buffer[100] = {0};
ULONG ulRead;
/*
//
// 【 】
// CreateFile , FILE_FLAG_OVERLAPPED!!
//
BOOL bRead = ReadFile(p->hDevice, buffer, 10, &ulRead,&overlap);
if(bRead == FALSE)
{
DWORD nRet = GetLastError();
if( nRet== ERROR_IO_PENDING)//ERROR_IO_PENDING =997
{
// 1: GetOverlappedResult,
GetOverlappedResult(p->hDevice, &overlap, &ulRead, TRUE);
buffer[ulRead] = 0x00;
// 2:
//WaitForMultipleObjects(overlap.hEvent, INFINITE);
DWORD dwEnd = GetTickCount();
printf(" : %d, :%.1fs, :%d, %s
", p->inx, (dwEnd- dwStart)/1000.0, ulRead, buffer);
return 0;
}
else
printf(" : %d
", nRet);
}
*/
//
// 【 】
// CreateFile , 【 】 FILE_FLAG_OVERLAPPED!!
//
BOOL bRead = ReadFile(p->hDevice, buffer,10,&ulRead, NULL);
buffer[ulRead] = 0x00;
DWORD dwEnd = GetTickCount();
printf(" : %d, :%.1fs, :%d, %s
", p->inx, (dwEnd- dwStart)/1000.0, ulRead, buffer);
return 0;
}
アプリケーション層起動プログラム:(特にCreateFile時の最後から二番目のパラメータのフラグ設定に注意)int main()
{
HANDLE hDevice =
CreateFile("\\\\.\\HelloDDK",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
//FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED,//【 】
FILE_ATTRIBUTE_NORMAL,//【 】
NULL );
if (hDevice == INVALID_HANDLE_VALUE)
{
printf("Open Device failed!");
return 1;
}
MY_TYPE my[3] = {0};
HANDLE hThread[3];
my[0].hDevice = hDevice;
my[0].inx = 0;
hThread[0] = (HANDLE) _beginthreadex (NULL,0,Thread,&my[0],0,NULL);
my[1].hDevice = hDevice;
my[1].inx = 1;
hThread[1] = (HANDLE) _beginthreadex (NULL,0,Thread,&my[1],0,NULL);
my[2].hDevice = hDevice;
my[2].inx = 2;
hThread[2] = (HANDLE) _beginthreadex (NULL,0,Thread,&my[2],0,NULL);
//
WaitForMultipleObjects(3,hThread,TRUE,INFINITE);
// IRP_MJ_CLEANUP IRP
CloseHandle(hDevice);
return 0;
}