1.事件对象
可以使用事件对象同步完成IRP,或者驱动线程间同步执行某些操作。
首先调用KeInitializeEvent IoCreateNotificationEvent或IoCreateSynchronizationEvent初始化事件。
流程:
驱动的一个线程调用KeWaitForSingleObject等待已初始化的事件
当操作完成后,该事件被置信号(调用KeSetEvent),等待线程进入准备执行状态。
内核执行线程分发,原本等待时间的线程开始执行。
2.信号灯对象
任何驱动都可以使用信号灯对象在驱动线程和处理例程之间同步I/O操作。
首先调用KeInitializeSemaphore 函数初始化信号灯。
流程:
驱动程序的一个线程调用KeWaitForSingleObject等待信号灯有信号。
当驱动程序接受到一个IRP请求后,相应处理例程将该IRP排入队列,并调用KeReleaseSemaphore函数增加一个信号灯,随后等待线程满足等待条件,准备执行。
线程分发,原等待线程开始执行。
3.互斥体对象
初始化:KeInitializeMutex
用来确保对共享资源互斥访问的同步机制。其中还有快速互斥体Fast Mutex和受限互斥体Guarded Mutex。互斥体可以递归请求(KeWaitForSingleObject)拥有对一个互斥体对象的所属权。只有完全释放 (KeReleaseMutex)所属权,互斥体对象才会有信号。
4.定时器对象
驱动程序可以使用定时器对象执行一个定时的操作。定时器对象包括DPC定时器和I/O定时器。IO定时器固定时间为1s,不可以改变。
首先调用KeInitializeTimer或KeInitializeTimerEx来初始化定时器。Ex函数比普通函数多一个TYPE参数,用 来指定DPC定时器响应类型是NotificationTimer(需要显式的设置为无信号。调用KeSetTimer)或者 SynchronizationTimer(自动变更为无信号状态)。KeInitializeTimer设置的为NotificationTimer。
1 #include "ntddk.h" 2 3 #ifdef __cplusplus 4 extern "C" NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath); 5 #endif 6 7 void DPCDemoUnload(PDRIVER_OBJECT DriverObject); 8 VOID ThreadStart(PVOID StartContext); 9 VOID CustomDpc(struct _KDPC *Dpc, PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2); 10 11 KTIMER Timer; 12 13 NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) 14 { 15 HANDLE hThread; 16 OBJECT_ATTRIBUTES ObjectAttributes; 17 CLIENT_ID CID; 18 NTSTATUS status; 19 20 21 KdPrint(("[DriverEntry]DriverEntry Current Process:%s Current IRQL: %d\n", (char*)((ULONG)IoGetCurrentProcess()+0x174),KeGetCurrentIrql())); 22 23 //初始化定时器 24 KeInitializeTimer(&Timer); 25 26 DriverObject->DriverUnload = DPCDemoUnload; 27 28 InitializeObjectAttributes(&ObjectAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL); 29 30 //创建一个系统线程 31 status = PsCreateSystemThread(&hThread, 32 GENERIC_READ | GENERIC_WRITE, 33 &ObjectAttributes, 34 NtCurrentProcess(), 35 &CID, 36 (PKSTART_ROUTINE)ThreadStart, 37 NULL); 38 if (!NT_SUCCESS(status)) 39 { 40 KdPrint(("PsCreateSystemThread failed!\n")); 41 return 0; 42 } 43 ZwClose(hThread); 44 KdPrint(("Exit DriverEntry!\n")); 45 return STATUS_SUCCESS; 46 } 47 48 VOID ThreadStart(PVOID StartContext) 49 { 50 LARGE_INTEGER DueTime; 51 KDPC Dpc; 52 53 KdPrint(("Current Process: %s IRQL:%d\n", (char*)((ULONG)IoGetCurrentProcess()+0x174), KeGetCurrentIrql())); 54 55 DueTime = RtlConvertLongToLargeInteger(-1000000); 56 57 //初始化一个DPC 58 KeInitializeDpc(&Dpc, (PKDEFERRED_ROUTINE)CustomDpc, NULL); 59 60 //设置DPC定时器 61 KeSetTimer(&Timer, DueTime, &Dpc); 62 63 //等待定时器 64 KeWaitForSingleObject(&Timer, Executive, KernelMode, FALSE, NULL); 65 66 KdPrint(("ThreadStart time expire!\n")); 67 68 return; 69 } 70 71 VOID CustomDpc(struct _KDPC *Dpc, PVOID DefferedContext, PVOID SystemArgument1, PVOID systemArgument2) 72 { 73 KdPrint(("Current Process: %s IRQL:%d\n", (char*)((ULONG)IoGetCurrentProcess()+0x174), KeGetCurrentIrql())); 74 75 return; 76 } 77 78 void DPCDemoUnload(PDRIVER_OBJECT DriverObject) 79 { 80 81 return; 82 }
5.自旋锁
是一种内核模式专用的同步机制,可以在并行访问时保护共享数据。
当某个函数在获取自旋锁的过程中,不可以有如下行为:
触发硬件或者软件异常。
试图访问分页内存
可能造成死锁的递归或者把持自旋锁超过25微秒
调用可能引起以上三条的外部函数
使用KeInitialiezeSpinLock初始化自旋锁
使用KeAcquireSpinLock获取自旋锁
使用KeReleaseSpinLock释放自旋锁
KeAcquireInStackQueuedSpinLock和KeReleaseInStackQueuedSpinLock来获取和释放排队自旋锁。
6.回调对象
当某条件满足时,驱动程序A向驱动程序B通知某一消息。驱动程序A首先要创建一个回调对象,其他的驱动程序可以向该回调对象注册回调函数,当条件满足的时候,驱动程序A将调用所有像其注册的回调函数。
首先使用InitializeObjectAttributes初始化回调对象的属性,必须为回调对象赋名字,且Attributes参数必须设置OBJ_PERMANENT标记,然后调用ExCreateCallback函数创建回调对象。注册回调函数使用的函数是ExRegisterCallback。
转自: http://lightlesshome.diandian.com/post/2014-01-19/40060818737