中断请求: 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需要程序员提供一个自旋锁,不能操作分页内存的数据