WindowsデバイスドライバStartIO、IRP同期/非同期アップロード

5744 ワード

プログラムの位置:http://download.csdn.net/detail/dijkstar/8568463
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;
}