中断请求: 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\n");
HANDLE *hEvent = (HANDLE*)lpParameter;
Sleep(5000);
printf("准备激活\n");
SetEvent(*hEvent);
printf("激活了\n");
return 0;
}
int main(int argc, char* argv[])
{
HANDLE hEvent;
hEvent = CreateEvent(NULL,FALSE,FALSE,NULL);//自动 初始化 不 激活
printf("hEvent 没有激活\n");
HANDLE handle = (HANDLE)_beginthreadex(NULL,0,ThreadProc,&hEvent,0,NULL);
printf("等待激活\n");
WaitForSingleObject(hEvent,INFINITE);
printf("结束了!\n");
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\n");
HANDLE *hSemaphore = (HANDLE*)lpParameter;
Sleep(5000);
printf("准备增加了信号\n");
ReleaseSemaphore(*hSemaphore,1,NULL);
printf("增加了信号\n");
return 0;
}
int main(int argc, char* argv[])
{
HANDLE hSemaphore;
hSemaphore = CreateSemaphoreA(NULL,2,2,NULL);
printf("信号为2\n");
WaitForSingleObject(hSemaphore,INFINITE);
printf("信号为1\n");
WaitForSingleObject(hSemaphore,INFINITE);
printf("信号为0\n");
HANDLE handle = (HANDLE)_beginthreadex(NULL,0,ThreadProc,&hSemaphore,0,NULL);
printf("等待hSemaphore 激活\n");
WaitForSingleObject(hSemaphore,INFINITE);
printf("结束了!\n");
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\n");
Sleep(1000);
printf("离开ThreadProc1\n");
ReleaseMutex(lpParameter);
return 0;
}
UINT WINAPI ThreadProc2(
LPVOID lpParameter // thread data
)
{
WaitForSingleObject(lpParameter,INFINITE);
printf("进入ThreadProc2\n");
Sleep(1000);
printf("离开ThreadProc2\n");
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("结束了!\n");
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\n");
Sleep(1000);
printf("离开ThreadProc1\n");
return 0;
}
UINT WINAPI ThreadProc2(
LPVOID lpParameter // thread data
)
{
printf("进入ThreadProc2\n");
Sleep(1000);
printf("离开ThreadProc2\n");
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("结束了!\n");
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\n",ProcessName));
下面是创建线程例子:
#pragma INITCODE
VOID MyProcessThread(IN PVOID pContext)
{
KdPrint(("Enter MyProcessThread!\n"));
PEPROCESS PePROCESS = IoGetCurrentProcess();
PTSTR ProcessName = (PTSTR)((ULONG)PePROCESS + 0x174);
KdPrint(("This Thread is in %s process\n",ProcessName));
KdPrint(("leave MyProcessThread\n"));
PsTerminateSystemThread(STATUS_SUCCESS);
}
#pragma INITCODE
VOID SystemThread(IN PVOID pContext)
{
KdPrint(("Enter SystemThread!\n"));
PEPROCESS PePROCESS = IoGetCurrentProcess();
PTSTR ProcessName = (PTSTR)((ULONG)PePROCESS + 0x174);
KdPrint(("This Thread is in %s process\n",ProcessName));
KdPrint(("leave SystemThread\n"));
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!\n"));
PEPROCESS PePROCESS = IoGetCurrentProcess();
PTSTR ProcessName = (PTSTR)((ULONG)PePROCESS + 0x174);
KdPrint(("This Thread is in %s process\n",ProcessName));
KeSetEvent(pEvent,IO_NO_INCREMENT,FALSE);
KdPrint(("leave MyProcessThread\n"));
PsTerminateSystemThread(STATUS_SUCCESS);
}
#pragma PAGEDCODE
VOID CreateThread_Test()
{
KEVENT KEvent;
HANDLE hThread;
KeInitializeEvent(&KEvent,NotificationEvent,FALSE);
KdPrint(("开始创建线程\n"));
NTSTATUS status = PsCreateSystemThread(&hThread,0,NULL,NtCurrentProcess(),NULL,MyProcessThread,&KEvent);
KeWaitForSingleObject(&KEvent,Executive,KernelMode,FALSE,NULL);
KdPrint(("CreateThread_Test结束\n"));
}
驱动程序与应用程序交互事件对象:
将句柄转化为指针: 在使用完 下面这个函数后,需要调用 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\n"));
//设置卸载函数
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\n"));
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\n"));
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\n"));
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\n", type));
else
KdPrint(("\t%s\n", 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\n"));
return status;
}
/
#pragma PAGEDCODE//主要是看这里
NTSTATUS HelloDDKDeviceIOControl(IN PDEVICE_OBJECT pDevObj,
IN PIRP pIrp)
{
NTSTATUS status = STATUS_SUCCESS;
KdPrint(("Enter HelloDDKDeviceIOControl\n"));
//得到当前堆栈
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\n"));
HANDLE hUserEvent = *(HANDLE*)pIrp->AssociatedIrp.SystemBuffer;//用户模式传递过来的值
PKEVENT pEvent;
KdPrint(("句柄转换为指针\n"));
status = ObReferenceObjectByHandle(hUserEvent,
EVENT_MODIFY_STATE,
*ExEventObjectType,
KernelMode,
(PVOID*)&pEvent,NULL);
//设置事件
KdPrint(("设置事件\n"));
KeSetEvent(pEvent,IO_NO_INCREMENT,FALSE);
//减少引用计数
KdPrint(("减少引用计数\n"));
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\n"));
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\n 在此期间不停输出1");
while (1)
{
printf("1\n");
}
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\n",
"MyWDMDevice", GetLastError() );
return 1;
}
DWORD dwOutput;
BOOL bRet;
//创建用户模式同步事件
printf("创建事件对象\n");
HANDLE hEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
//建立辅助线程
printf("创建辅助线程\n");
HANDLE hThread1 = (HANDLE)_beginthreadex(NULL,0,thread1,&hEvent,0,NULL);
printf("将事件句柄传递给驱动程序\n");
bRet = DeviceIoControl(hDevice,IOCTL_TRANSMIT_EVENT,&hEvent,sizeof(hEvent),NULL,0,&dwOutput,NULL);
printf("等待线程0.5S 然后等待事件被激活 \n");
Sleep(500);
WaitForSingleObject(hEvent,INFINITE);
printf("事件被激活了\n");
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\n"));
KeReleaseSemaphore(pkSemaphore,IO_NO_INCREMENT,1,FALSE);
KdPrint(("Leave MyThread\n"));
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\n",count));
KeWaitForSingleObject(&ksemaphore,Executive,KernelMode,FALSE,NULL);
count = KeReadStateSemaphore(&ksemaphore);
KdPrint(("ksemaphore 计数: %d\n",count));
KeWaitForSingleObject(&ksemaphore,Executive,KernelMode,FALSE,NULL);
count = KeReadStateSemaphore(&ksemaphore);
KdPrint(("ksemaphore 计数: %d\n",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\n"));
KeWaitForSingleObject(pkMutex,Executive,KernelMode,FALSE,NULL);
KeStallExecutionProcessor(5000);
for (int i = 0;i<10;i++)
{
KdPrint(("MyThread1\n"));
}
KdPrint(("Leave Thread1\n"));
KeReleaseMutex(pkMutex,FALSE);
PsTerminateSystemThread(STATUS_SUCCESS);
}
#pragma INITCODE
VOID MyThread2(IN PVOID pContext)
{
PKMUTEX pkMutex = (PKMUTEX)pContext;
KdPrint(("Enter Thread2\n"));
KeWaitForSingleObject(pkMutex,Executive,KernelMode,FALSE,NULL);
for (int i = 0;i<10;i++)
{
KdPrint(("MyThread2\n"));
}
// KeStallExecutionProcessor(50);
KdPrint(("Leave Thread2\n"));
KeReleaseMutex(pkMutex,FALSE);
PsTerminateSystemThread(STATUS_SUCCESS);
}
#pragma PAGEDCODE
VOID MyMutex()
{
HANDLE hMyThread1,hMyThread2;
KMUTEX hMutex;
KdPrint(("Enter MyMutex\n"));
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\n"));
}
下面学习快速互斥体:
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需要程序员提供一个自旋锁,不能操作分页内存的数据