zoukankan      html  css  js  c++  java
  • 驱动程序的同步学习

    中断请求: IRQ

    1)外部中断=硬件产生的中断 一般16个中断信号

    2)由软件指令int n 产生的中断

    可编程中断控制器: PIC


    高级可编程控制器 APIC  兼容PIC  IRQ增加到了24个  设备管理器可以查看到这些

    每个IRQ有个字的优先级别 正在运行的线程随时可以被中断打断

    进入中断处理程序


    中断请求级 IRQL   

    WINDOWS将中断的概念进行了扩展 提出了一个中断请求级IRQL的概念  其中规定了 32个中断请求级别

    0-2 软件中断

    3-31硬件中断 这里包括APIC中的24个中断

    用户模式代码运行再最低级   PASSIVE_LEVEL 级别  必要时进入与DISPATCH_LEVEL级别

    WINDOWS负责线程的组件式运行再DISPATCH_LEVEL级别的

    在内核模式下  可以通过调用  KeGetCurrentIrpI  内核函数来得到当前的IRQL级别

    线程优先级 的优先级最低  可以被其他IRQL级别的程序打断

    如何提升+降低 IRQL:

    ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL)
    KIRQL oldirql;
    KeRaiseIrql(DISPATCH_LEVEL, &oldirql);
    ///////////////////////////////
    KeLowerIrql(oldirql);

    自旋锁:

    //My_SpinLock 为 设备扩展定义

    PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;
    KIRQL oldirql;
    KeAcquireSpinLock(&pdx->My_SpinLock,&oldirql);

    KeReleaseSpinLock(&pdx->My_SpinLock,&oldirql);

    用户模式下的同步对象起始是内核模式下同步对象的再次封装:

    这里分析 用户模式  事件函数:

    #include "stdafx.h"
    #include <windows.h>
    #include <process.h>    /* _beginthread, _endthread */
    #include <stddef.h>
    #include <stdlib.h>
    #include <conio.h>
    
    
    UINT WINAPI ThreadProc(
    						LPVOID lpParameter   // thread data
    						)
    {
    	printf("进入thread1
    ");
    	HANDLE *hEvent = (HANDLE*)lpParameter;
    	Sleep(5000);
    	printf("准备激活
    ");
    	SetEvent(*hEvent);
    	printf("激活了
    ");
    	return 0;
    }
    
    int main(int argc, char* argv[])
    {
    	HANDLE hEvent;
    	
    	hEvent = CreateEvent(NULL,FALSE,FALSE,NULL);//自动 初始化 不 激活
    	
    	printf("hEvent 没有激活
    ");
    	HANDLE handle = (HANDLE)_beginthreadex(NULL,0,ThreadProc,&hEvent,0,NULL);
    
    		printf("等待激活
    ");
    	WaitForSingleObject(hEvent,INFINITE);
    	printf("结束了!
    ");
    	return 0;
    }
    ··
    这里分析 用户模式  信号灯函数:

    #include "stdafx.h"
    #include <windows.h>
    #include <process.h>    /* _beginthread, _endthread */
    #include <stddef.h>
    #include <stdlib.h>
    #include <conio.h>
    
    
    UINT WINAPI ThreadProc(
    						LPVOID lpParameter   // thread data
    						)
    {
    	printf("进入thread1
    ");
    	HANDLE *hSemaphore = (HANDLE*)lpParameter;
    	Sleep(5000);
    	printf("准备增加了信号
    ");
    	ReleaseSemaphore(*hSemaphore,1,NULL);
    	printf("增加了信号
    ");
    	return 0;
    }
    
    int main(int argc, char* argv[])
    {
    	HANDLE hSemaphore;
    	
    	hSemaphore = CreateSemaphoreA(NULL,2,2,NULL);
    		printf("信号为2
    ");
    	WaitForSingleObject(hSemaphore,INFINITE);
    	printf("信号为1
    ");
    	WaitForSingleObject(hSemaphore,INFINITE);
    	printf("信号为0
    ");
    	HANDLE handle = (HANDLE)_beginthreadex(NULL,0,ThreadProc,&hSemaphore,0,NULL);
    
    	printf("等待hSemaphore 激活
    ");
    	WaitForSingleObject(hSemaphore,INFINITE);
    	printf("结束了!
    ");
    	return 0;
    }
     一增加了 信号  主线程就能运行了   当主线程 结束  线程1  就结束了

    这里分析 用户模式  互斥对象函数:  

    #include "stdafx.h"
    #include <windows.h>
    #include <process.h>    /* _beginthread, _endthread */
    #include <stddef.h>
    #include <stdlib.h>
    #include <conio.h>
    
    //互斥对象作同步处理工作
    UINT WINAPI ThreadProc1(
    						LPVOID lpParameter   // thread data
    						)
    {
    	WaitForSingleObject(lpParameter,INFINITE);
    	printf("进入ThreadProc1
    ");
    	Sleep(1000);
    	printf("离开ThreadProc1
    ");
    	ReleaseMutex(lpParameter);
    	return 0;
    }
    UINT WINAPI ThreadProc2(
    						LPVOID lpParameter   // thread data
    						)
    {
    	WaitForSingleObject(lpParameter,INFINITE);
    	printf("进入ThreadProc2
    ");
    	Sleep(1000);
    	printf("离开ThreadProc2
    ");
    	ReleaseMutex(lpParameter);
    	return 0;
    }
    
    int main(int argc, char* argv[])
    {
    	HANDLE hMutex = CreateMutex(NULL,FALSE,NULL);//未被占用   激活状态 
    
    	HANDLE handle1 = (HANDLE)_beginthreadex(NULL,0,ThreadProc1,&hMutex,0,NULL);
    	HANDLE handle2 = (HANDLE)_beginthreadex(NULL,0,ThreadProc2,&hMutex,0,NULL);
    
    	Sleep(6000);//等待运行完
    	printf("结束了!
    ");
    	return 0;
    }
     同时进行的函数
    还有就是线程对象的同步:

    #include "stdafx.h"
    #include <windows.h>
    #include <process.h>    /* _beginthread, _endthread */
    #include <stddef.h>
    #include <stdlib.h>
    #include <conio.h>
    
    //互斥对象作同步处理工作
    UINT WINAPI ThreadProc1(
    						LPVOID lpParameter   // thread data
    						)
    {
    	printf("进入ThreadProc1
    ");
    	Sleep(1000);
    	printf("离开ThreadProc1
    ");
    	return 0;
    }
    UINT WINAPI ThreadProc2(
    						LPVOID lpParameter   // thread data
    						)
    {
    	printf("进入ThreadProc2
    ");
    	Sleep(1000);
    	printf("离开ThreadProc2
    ");
    	return 0;
    }
    
    int main(int argc, char* argv[])
    {
    	HANDLE hThread[2];
    
    	hThread[0] = (HANDLE)_beginthreadex(NULL,0,ThreadProc1,NULL,0,NULL);
    	hThread[1] = (HANDLE)_beginthreadex(NULL,0,ThreadProc2,NULL,0,NULL);
    	
    	WaitForMultipleObjects(2,hThread,TRUE,INFINITE);
    	//第三个参数是 是否等待全部同步函数
    	printf("结束了!
    ");
    	return 0;
    }


    下面是 驱动同步函数介绍:

    NTSTATUS 
      KeWaitForSingleObject(
        IN PVOID  Object,
        IN KWAIT_REASON  WaitReason,         //Executive
        IN KPROCESSOR_MODE  WaitMode,        //KernelMode
        IN BOOLEAN  Alertable,               //FALSE
        IN PLARGE_INTEGER  Timeout  OPTIONAL //NULL
        );
    NTSTATUS 
      KeWaitForMultipleObjects(
        IN ULONG  Count,
        IN PVOID  Object[],
        IN WAIT_TYPE  WaitType,
        IN KWAIT_REASON  WaitReason,
        IN KPROCESSOR_MODE  WaitMode,
        IN BOOLEAN  Alertable,
        IN PLARGE_INTEGER  Timeout  OPTIONAL,
        IN PKWAIT_BLOCK  WaitBlockArray  OPTIONAL
        
    NTSTATUS 
      PsCreateSystemThread(
        OUT PHANDLE  ThreadHandle,                         //用于输出,得到新创建的线程句柄
        IN ULONG  DesiredAccess,                           //创建权限
        IN POBJECT_ATTRIBUTES  ObjectAttributes  OPTIONAL, //NULL
        IN HANDLE  ProcessHandle  OPTIONAL,                //NULL则为系统线程  如果该值是一个进程句柄 则新创建的线程属于这个指定的进程 NtCurrentProcess可以得到当前进程的句柄
        OUT PCLIENT_ID  ClientId  OPTIONAL,                //NULL
        IN PKSTART_ROUTINE  StartRoutine,                  //新线程地址
        IN PVOID  StartContext                             //新线程接收参数
        );
    
    内核模式下 强制线程结束   否则线程无法退出
    NTSTATUS 
      PsTerminateSystemThread(
        IN NTSTATUS  ExitStatus
        );
    
    查看当前进程名称:

    	PEPROCESS pEProcess = IoGetCurrentProcess();
    	PTSTR ProcessName = (PTSTR)((ULONG)pEProcess + 0x174);
    	KdPrint(("This Thread run in %s process
    ",ProcessName));

    下面是创建线程例子:

    #pragma INITCODE
    VOID MyProcessThread(IN PVOID pContext)
    {
    		KdPrint(("Enter MyProcessThread!
    "));
    		
    		PEPROCESS PePROCESS = IoGetCurrentProcess();
    		PTSTR ProcessName = (PTSTR)((ULONG)PePROCESS + 0x174);
    		KdPrint(("This Thread is in %s process
    ",ProcessName));
    		
    		KdPrint(("leave MyProcessThread
    "));
    	PsTerminateSystemThread(STATUS_SUCCESS);
    }
    #pragma INITCODE
    VOID SystemThread(IN PVOID pContext)
    {
    	KdPrint(("Enter SystemThread!
    "));
    	PEPROCESS PePROCESS = IoGetCurrentProcess();
    	PTSTR ProcessName = (PTSTR)((ULONG)PePROCESS + 0x174);
    	KdPrint(("This Thread is in %s process
    ",ProcessName));
    	
    	KdPrint(("leave SystemThread
    "));
    	PsTerminateSystemThread(STATUS_SUCCESS);
    }
    #pragma INITCODE
    VOID CreateThread_Test()
    {
    	HANDLE hSystemThread ,hMyThread;
    	NTSTATUS status = PsCreateSystemThread(&hSystemThread,0,
    		NULL,
    		NULL,
    		NULL,
    		SystemThread,
    		NULL);
    
    	status = PsCreateSystemThread(&hMyThread,0,
    		NULL,
    		NtCurrentProcess(),
    		NULL,
    		MyProcessThread,
    		NULL);
    }
    
    内核模式下的事件对象

    VOID 
      KeInitializeEvent(
        IN PRKEVENT  Event,    //初始化时间对象指针
        IN EVENT_TYPE  Type,   //通知事件(手动事件): NotificationEvent   同步事件(自动事件):  SynchronizationEvent
        IN BOOLEAN  State      //真 状态为激发
        );
    
    LONG 
      KeSetEvent(
        IN PRKEVENT  Event,
        IN KPRIORITY  Increment,   //IO_NO_INCREMENT
        IN BOOLEAN  Wait           //FALSE
        );
    
    下面为驱动 与 用户之间  如何使用事件对象:

    #pragma INITCODE
    VOID MyProcessThread(IN PVOID pContext)
    {
    	PKEVENT pEvent = (PKEVENT)pContext;
    
    		KdPrint(("Enter MyProcessThread!
    "));
    		
    		PEPROCESS PePROCESS = IoGetCurrentProcess();
    		PTSTR ProcessName = (PTSTR)((ULONG)PePROCESS + 0x174);
    		KdPrint(("This Thread is in %s process
    ",ProcessName));
    		
    		KeSetEvent(pEvent,IO_NO_INCREMENT,FALSE);
    
    		KdPrint(("leave MyProcessThread
    "));
    	
    		PsTerminateSystemThread(STATUS_SUCCESS);
    }
    #pragma PAGEDCODE
    VOID CreateThread_Test()
    {
    	KEVENT KEvent;
    	HANDLE hThread;
    
    	KeInitializeEvent(&KEvent,NotificationEvent,FALSE);
    	
    	KdPrint(("开始创建线程
    "));
    	NTSTATUS status = PsCreateSystemThread(&hThread,0,NULL,NtCurrentProcess(),NULL,MyProcessThread,&KEvent);
    
    	KeWaitForSingleObject(&KEvent,Executive,KernelMode,FALSE,NULL);
    	KdPrint(("CreateThread_Test结束
    "));
    }
    驱动程序与应用程序交互事件对象:

    将句柄转化为指针:   在使用完 下面这个函数后,需要调用 ObReferenceObject 函数使 计数减1

    NTSTATUS 
      ObReferenceObjectByHandle(                                    //返回一个状态值  表明是否成功得到指针
        IN HANDLE  Handle,
        IN ACCESS_MASK  DesiredAccess,
        IN POBJECT_TYPE  ObjectType  OPTIONAL,
        IN KPROCESSOR_MODE  AccessMode,
        OUT PVOID  *Object,
        OUT POBJECT_HANDLE_INFORMATION  HandleInformation  OPTIONAL
        );
    
    VOID
      ObReferenceObject(
        IN PVOID  Object
        );
    
    BOOL DeviceIoControl(
      HANDLE hDevice,              // handle to device
      DWORD dwIoControlCode,       // operation
      LPVOID lpInBuffer,           // input data buffer
      DWORD nInBufferSize,         // size of input data buffer
      LPVOID lpOutBuffer,          // output data buffer
      DWORD nOutBufferSize,        // size of output data buffer
      LPDWORD lpBytesReturned,     // byte count
      LPOVERLAPPED lpOverlapped    // overlapped information
    );
    下面为驱动代码:

    #define IOCTL_TRANSMIT_EVENT CTL_CODE(
    			FILE_DEVICE_UNKNOWN, 
    			0x800, 
    			METHOD_BUFFERED, 
    			FILE_ANY_ACCESS)
    
    #include "Driver.h"
    #pragma INITCODE
    extern "C" NTSTATUS DriverEntry (
    			IN PDRIVER_OBJECT pDriverObject,
    			IN PUNICODE_STRING pRegistryPath	) 
    {
    	NTSTATUS status;
    	KdPrint(("Enter DriverEntry
    "));
    
    	//设置卸载函数
    	pDriverObject->DriverUnload = HelloDDKUnload;
    
    	//设置派遣函数
    	for (int i = 0; i < arraysize(pDriverObject->MajorFunction); ++i)
    		pDriverObject->MajorFunction[i] = HelloDDKDispatchRoutin;
    
    	pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = HelloDDKDeviceIOControl;
    	
    	//创建驱动设备对象
    	status = CreateDevice(pDriverObject);
    
    	KdPrint(("Leave DriverEntry
    "));
    	return status;
    }
    /////////////////////////////////////////////////////////////////////
    #pragma INITCODE
    NTSTATUS CreateDevice (
    		IN PDRIVER_OBJECT	pDriverObject) 
    {
    	NTSTATUS status;
    	PDEVICE_OBJECT pDevObj;
    	PDEVICE_EXTENSION pDevExt;
    	
    	//创建设备名称
    	UNICODE_STRING devName;
    	RtlInitUnicodeString(&devName,L"\Device\MyDDKDevice");
    	
    	//创建设备
    	status = IoCreateDevice( pDriverObject,
    						sizeof(DEVICE_EXTENSION),
    						&(UNICODE_STRING)devName,
    						FILE_DEVICE_UNKNOWN,
    						0, TRUE,
    						&pDevObj );
    	if (!NT_SUCCESS(status))
    		return status;
    
    	pDevObj->Flags |= DO_DIRECT_IO;
    	pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;
    	pDevExt->pDevice = pDevObj;
    	pDevExt->ustrDeviceName = devName;
    
    	//申请模拟文件的缓冲区
    	pDevExt->buffer = (PUCHAR)ExAllocatePool(PagedPool,MAX_FILE_LENGTH);
    	//设置模拟文件大小
    	pDevExt->file_length = 0;
    
    	//创建符号链接
    	UNICODE_STRING symLinkName;
    	RtlInitUnicodeString(&symLinkName,L"\??\HelloDDK");
    	pDevExt->ustrSymLinkName = symLinkName;
    	status = IoCreateSymbolicLink( &symLinkName,&devName );
    	if (!NT_SUCCESS(status)) 
    	{
    		IoDeleteDevice( pDevObj );
    		return status;
    	}
    	return STATUS_SUCCESS;
    }
    
    /////////////////////////////////////////////////////////////////////
    #pragma PAGEDCODE
    VOID HelloDDKUnload (IN PDRIVER_OBJECT pDriverObject) 
    {
    	PDEVICE_OBJECT	pNextObj;
    	KdPrint(("Enter DriverUnload
    "));
    	pNextObj = pDriverObject->DeviceObject;
    	while (pNextObj != NULL) 
    	{
    		PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
    			pNextObj->DeviceExtension;
    		if (pDevExt->buffer)
    		{
    			ExFreePool(pDevExt->buffer);
    			pDevExt->buffer = NULL;
    		}
    
    		//删除符号链接
    		UNICODE_STRING pLinkName = pDevExt->ustrSymLinkName;
    		IoDeleteSymbolicLink(&pLinkName);
    		pNextObj = pNextObj->NextDevice;
    		IoDeleteDevice( pDevExt->pDevice );
    	}
    }
    /////////////////////////////////////////////////////////////////////
    #pragma PAGEDCODE
    NTSTATUS HelloDDKDispatchRoutin(IN PDEVICE_OBJECT pDevObj,
    								 IN PIRP pIrp) 
    {
    	KdPrint(("Enter HelloDDKDispatchRoutin
    "));
    
    	PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
    	//建立一个字符串数组与IRP类型对应起来
    	static char* irpname[] = 
    	{
    		"IRP_MJ_CREATE",
    		"IRP_MJ_CREATE_NAMED_PIPE",
    		"IRP_MJ_CLOSE",
    		"IRP_MJ_READ",
    		"IRP_MJ_WRITE",
    		"IRP_MJ_QUERY_INFORMATION",
    		"IRP_MJ_SET_INFORMATION",
    		"IRP_MJ_QUERY_EA",
    		"IRP_MJ_SET_EA",
    		"IRP_MJ_FLUSH_BUFFERS",
    		"IRP_MJ_QUERY_VOLUME_INFORMATION",
    		"IRP_MJ_SET_VOLUME_INFORMATION",
    		"IRP_MJ_DIRECTORY_CONTROL",
    		"IRP_MJ_FILE_SYSTEM_CONTROL",
    		"IRP_MJ_DEVICE_CONTROL",
    		"IRP_MJ_INTERNAL_DEVICE_CONTROL",
    		"IRP_MJ_SHUTDOWN",
    		"IRP_MJ_LOCK_CONTROL",
    		"IRP_MJ_CLEANUP",
    		"IRP_MJ_CREATE_MAILSLOT",
    		"IRP_MJ_QUERY_SECURITY",
    		"IRP_MJ_SET_SECURITY",
    		"IRP_MJ_POWER",
    		"IRP_MJ_SYSTEM_CONTROL",
    		"IRP_MJ_DEVICE_CHANGE",
    		"IRP_MJ_QUERY_QUOTA",
    		"IRP_MJ_SET_QUOTA",
    		"IRP_MJ_PNP",
    	};
    
    	UCHAR type = stack->MajorFunction;
    	if (type >= arraysize(irpname))
    		KdPrint((" - Unknown IRP, major type %X
    ", type));
    	else
    		KdPrint(("	%s
    ", irpname[type]));
    
    	NTSTATUS status = STATUS_SUCCESS;
    	// 完成IRP
    	pIrp->IoStatus.Status = status;
    	pIrp->IoStatus.Information = 0;	// bytes xfered
    	IoCompleteRequest( pIrp, IO_NO_INCREMENT );
    
    	KdPrint(("Leave HelloDDKDispatchRoutin
    "));
    
    	return status;
    }
    /////////////////////////////////////////////////////////////////////
    #pragma PAGEDCODE//主要是看这里
    NTSTATUS HelloDDKDeviceIOControl(IN PDEVICE_OBJECT pDevObj,
    								 IN PIRP pIrp)
    {
    	NTSTATUS status = STATUS_SUCCESS;
    	KdPrint(("Enter HelloDDKDeviceIOControl
    "));
    
    	//得到当前堆栈
    	PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
    	//得到输入缓冲区大小
    	ULONG cbin = stack->Parameters.DeviceIoControl.InputBufferLength;
    	//得到输出缓冲区大小
    	ULONG cbout = stack->Parameters.DeviceIoControl.OutputBufferLength;
    	//得到IOCTL码
    	ULONG code = stack->Parameters.DeviceIoControl.IoControlCode;
    
    	ULONG info = 0;
    
    	switch (code)
    	{						// process request
    		case IOCTL_TRANSMIT_EVENT:
    		{
    			KdPrint(("IOCTL_TEST1
    "));
    			HANDLE hUserEvent = *(HANDLE*)pIrp->AssociatedIrp.SystemBuffer;//用户模式传递过来的值
    			PKEVENT pEvent;
    				KdPrint(("句柄转换为指针
    "));
    			status = ObReferenceObjectByHandle(hUserEvent,
    				EVENT_MODIFY_STATE,
    				*ExEventObjectType,
    				KernelMode,
    				(PVOID*)&pEvent,NULL);
    
    			//设置事件
    				KdPrint(("设置事件
    "));
    			KeSetEvent(pEvent,IO_NO_INCREMENT,FALSE);
    			//减少引用计数
    				KdPrint(("减少引用计数
    "));
    			ObDereferenceObject(pEvent);
    			break;
    		}
    
    		default:
    			status = STATUS_INVALID_VARIANT;
    	}
    
    	// 完成IRP
    	pIrp->IoStatus.Status = status;
    	pIrp->IoStatus.Information = info;	// bytes xfered
    	IoCompleteRequest( pIrp, IO_NO_INCREMENT );
    
    	KdPrint(("Leave HelloDDKDeviceIOControl
    "));
    
    	return status;
    }
    
    下面为用户模式代码:

    #include <windows.h>
    #include <stdio.h>
    //使用CTL_CODE必须加入winioctl.h
    #include <winioctl.h>
    #include "Ioctls.h"
    #include <process.h>    /* _beginthread, _endthread */
    #include <stddef.h>
    #include <stdlib.h>
    #include <conio.h>
    
    UINT WINAPI thread1(
    						LPVOID lpParameter   // thread data
    						)
    {
    	printf("进入线程thread1
     在此期间不停输出1");
    	while (1)
    	{
    		printf("1
    ");
    	}
    	return 0;
    }
    
    int main()
    {
    	HANDLE hDevice = 
    		CreateFile("\\.\HelloDDK",
    					GENERIC_READ | GENERIC_WRITE,
    					0,		// share mode none
    					NULL,	// no security
    					OPEN_EXISTING,
    					FILE_ATTRIBUTE_NORMAL,
    					NULL );		// no template
    
    	if (hDevice == INVALID_HANDLE_VALUE)
    	{
    		printf("Failed to obtain file handle to device: "
    			"%s with Win32 error code: %d
    ",
    			"MyWDMDevice", GetLastError() );
    		return 1;
    	}
    	DWORD dwOutput;
    	BOOL bRet;
    	
    	//创建用户模式同步事件
    	printf("创建事件对象
    ");
    	HANDLE hEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
    	//建立辅助线程
    	printf("创建辅助线程
    ");
    	HANDLE hThread1 = (HANDLE)_beginthreadex(NULL,0,thread1,&hEvent,0,NULL);
    
    	printf("将事件句柄传递给驱动程序
    ");
    	
    	bRet = DeviceIoControl(hDevice,IOCTL_TRANSMIT_EVENT,&hEvent,sizeof(hEvent),NULL,0,&dwOutput,NULL);
    	
    	printf("等待线程0.5S  然后等待事件被激活 
    ");
    	Sleep(500);
    	WaitForSingleObject(hEvent,INFINITE);
    	printf("事件被激活了
    ");
    	
    	CloseHandle(hDevice);
    	CloseHandle(hThread1);
    	CloseHandle(hEvent);
    
    	return 0;
    }


    最后的效果是   用户模式下  创建一个     自动的 没有激活的      事件对象   传递进内核模式     内核模式下   激活事件对象   此时 驱动暂停! 用户程序输出完 后 驱动才输出完 





    驱动与驱动 之间使用事件

    创建有名的事件:

    IoCreateNotificationEvent  和   IoCreateSynchronizationEvent  内核函数

    通知事件(手动) 同步事件(自动)

    如果存在此名称的事件对象,会打开这个内核事件对象,如果不存在指定名称的事件对象,则创建这个内核事件对象


    内核模式下的信号灯:

    VOID 
      KeInitializeSemaphore(         //初始化
        IN PRKSEMAPHORE  Semaphore,  //得到内核信号灯对象指针
        IN LONG  Count,              //个数
        IN LONG  Limit               //上限
        );
    
    LONG 
      KeReadStateSemaphore(          //读取信号灯当前计数
        IN PRKSEMAPHORE  Semaphore
        );
    
    LONG 
      KeReleaseSemaphore(            //释放信号灯会增加信号灯计数 可以用这个函数指定增量值
        IN PRKSEMAPHORE  Semaphore,
        IN KPRIORITY  Increment,
        IN LONG  Adjustment,
        IN BOOLEAN  Wait
        );
    
    获取信号灯  用  KeWaitXX 系列函数,信号灯-- 否则陷入等待

    下面是驱动程序中利用 信号灯代码:

    #pragma INITCODE
    VOID MyThread(IN PVOID pContest)
    {
    	PKSEMAPHORE pkSemaphore = (PKSEMAPHORE)pContest;
    	
    	KdPrint(("Enter my thread
    "));
    	KeReleaseSemaphore(pkSemaphore,IO_NO_INCREMENT,1,FALSE);
    	KdPrint(("Leave MyThread
    "));
    	PsTerminateSystemThread(STATUS_SUCCESS);
    }
    #pragma PAGEDCODE
    VOID Test()
    {
    	KSEMAPHORE ksemaphore;
    	HANDLE hMyThread;
    	LONG count;
    	
    		KdPrint(("enter Test"));
    	KeInitializeSemaphore(&ksemaphore,2,2);
    	count = KeReadStateSemaphore(&ksemaphore);
    	
    	KdPrint(("ksemaphore  计数: %d
    ",count));
    	
    	KeWaitForSingleObject(&ksemaphore,Executive,KernelMode,FALSE,NULL);
    	
    	count = KeReadStateSemaphore(&ksemaphore);
    	KdPrint(("ksemaphore  计数: %d
    ",count));
    	
    	KeWaitForSingleObject(&ksemaphore,Executive,KernelMode,FALSE,NULL);
    	
    	count = KeReadStateSemaphore(&ksemaphore);
    	KdPrint(("ksemaphore  计数: %d
    ",count));
    	
    	NTSTATUS status = PsCreateSystemThread(&hMyThread,0,NULL,NtCurrentProcess(),
    		NULL,MyThread,&ksemaphore);
    	
    		KdPrint(("leave Test"));
    	KeWaitForSingleObject(&ksemaphore,Executive,KernelMode,FALSE,NULL);
    }



    下面学习互斥体:

    使用结构 KMUTEX

    VOID 
      KeInitializeMutex(
        IN PRKMUTEX  Mutex,  //获得互斥体对象指针
        IN ULONG  Level      //一般为0
        );
    获得互斥体  KeWaitXX 系列函数

    释放互斥体  KeReleaseMutex 函数

    NTSTATUS 
      ObReferenceObjectByHandle(                                       //得到对象指针
        IN HANDLE  Handle,
        IN ACCESS_MASK  DesiredAccess,                                 //0
        IN POBJECT_TYPE  ObjectType  OPTIONAL,                         //NULL
        IN KPROCESSOR_MODE  AccessMode,                                //KernelMode
        OUT PVOID  *Object,                                            //定义的指针对象组
        OUT POBJECT_HANDLE_INFORMATION  HandleInformation  OPTIONAL    //NULL
        );
    

    如果你需要延迟一段非常短的时间(少于50毫秒),可以调用KeStallExecutionProcessor,在任何IRQL级上:

    VOID 
      KeStallExecutionProcessor(
        IN ULONG  MicroSeconds
        );
    
    下面是驱动   互斥体  应用代码:

    #pragma INITCODE
    VOID MyThread1(IN PVOID pContext)
    {
    	PKMUTEX pkMutex = (PKMUTEX)pContext;
    
    	KdPrint(("Enter Thread1
    "));
    	KeWaitForSingleObject(pkMutex,Executive,KernelMode,FALSE,NULL);	
    	
    		KeStallExecutionProcessor(5000);
    	for (int i = 0;i<10;i++)
    	{
    		KdPrint(("MyThread1
    "));
    	}
    
    
    	KdPrint(("Leave Thread1
    "));
    	KeReleaseMutex(pkMutex,FALSE);
    	PsTerminateSystemThread(STATUS_SUCCESS);
    
    }
    #pragma INITCODE
    VOID MyThread2(IN PVOID pContext)
    {
    	PKMUTEX pkMutex = (PKMUTEX)pContext;
    	KdPrint(("Enter Thread2
    "));
    	KeWaitForSingleObject(pkMutex,Executive,KernelMode,FALSE,NULL);
    	for (int i = 0;i<10;i++)
    	{
    		KdPrint(("MyThread2
    "));
    	}
    //	KeStallExecutionProcessor(50);
    	
    	KdPrint(("Leave Thread2
    "));
    	KeReleaseMutex(pkMutex,FALSE);
    	PsTerminateSystemThread(STATUS_SUCCESS);
    
    	
    }
    #pragma PAGEDCODE
    VOID MyMutex()
    {
    	HANDLE hMyThread1,hMyThread2;
    	KMUTEX hMutex;
    
    	
    	KdPrint(("Enter MyMutex
    "));
    
    	KeInitializeMutex(&hMutex,0);//初始化内核互斥体
    
    	PsCreateSystemThread(&hMyThread1,0,NULL,NtCurrentProcess(),
    		NULL,MyThread1,&hMutex);//创建系统线程,该线程为System进程的线程
    
    	PsCreateSystemThread(&hMyThread2,0,NULL,NtCurrentProcess(),
    		NULL,MyThread2,&hMutex);
    
    	PVOID Pointer_Arry[2];
    	
    	ObReferenceObjectByHandle(hMyThread1,0,NULL,KernelMode,&Pointer_Arry[0],NULL);//得到对象指针
    	ObReferenceObjectByHandle(hMyThread2,0,NULL,KernelMode,&Pointer_Arry[1],NULL);
    	
    	KeWaitForMultipleObjects(2,Pointer_Arry,WaitAll,Executive,KernelMode,FALSE,NULL,NULL);
    	
    	ObfDereferenceObject(Pointer_Arry[0]);//减小引用计数
    	ObfDereferenceObject(Pointer_Arry[1]);
    	KdPrint(("Leave MyMutex
    "));
    }



    下面学习快速互斥体:

    VOID 
      ExInitializeFastMutex(       //初始化快速互斥体
        IN PFAST_MUTEX  FastMutex  
        );
    
    VOID 
      ExAcquireFastMutex(          //获取快速互斥体
        IN PFAST_MUTEX  FastMutex
        );
    
    VOID 
      ExReleaseFastMutex(          //释放快速互斥体
        IN PFAST_MUTEX  FastMutex
        );
    

    使用跟上面差不多

    下面学习自旋锁:

    多用于小段时间

    VOID 
      KeAcquireSpinLock(            //获得自旋锁
        IN PKSPIN_LOCK  SpinLock,
        OUT PKIRQL  OldIrql
        );
    
    VOID 
      KeReleaseSpinLock(            //释放自旋锁
        IN PKSPIN_LOCK  SpinLock,
        IN KIRQL  NewIrql
        );
    
    LONG 
      InterlockedIncrement(
        IN PLONG  Addend            //整数指针++
        );
    
    LONG 
      InterlockedDecrement(
        IN PLONG  Addend            //--
        );
    
    InterlockedXX系列函数 不需要程序员提供自旋锁,内部不会提升IRQL  可以操作非分页的数据,也可以操作分页数据

    而 ExInterlockedXX需要程序员提供一个自旋锁,不能操作分页内存的数据












  • 相关阅读:
    2019-2020-20191201《信息安全专业导论》第4周学习总结
    2019-2020-20191201《信息安全专业导论》第3周学习总结
    2019-2020-191201《信息安全专业导论》第二周学习总结
    计算机概论速读提问
    自我介绍
    20191302第六章学习笔记
    20191302反汇编测试
    20191302mystat
    20191302 第五章学习
    20191302 第四章学习笔记
  • 原文地址:https://www.cnblogs.com/zcc1414/p/3982494.html
Copyright © 2011-2022 走看看