Windows驱动开发之线程与同步事件
转载请注明来源:
enjoy5512的博客 : http://blog.csdn.net/enjoy5512
GitHub : https://github.com/whu-enjoy
.1. 使用系统线程
PsCreateSystemThread
NTSTATUS
PsCreateSystemThread(
_Out_PHANDLE ThreadHandle,
_In_ULONG DesiredAccess, //所需访问权限
_In_opt_POBJECT_ATTRIBUTES ObjectAttributes,
_In_opt_HANDLE ProcessHandle,
_Out_opt_PCLIENT_ID ClientId,
_In_PKSTART_ROUTINE StartRoutine,//线程中要执行的函数
_In_opt_PVOID StartContext//传递给上述要执行的函数的参数
);
Parameters
ThreadHandle[out] 线程句柄[输出参数]
指向一个用于接收此句柄的变量。一旦此句柄 不再使用,驱动必须用ZwClose关闭此句柄。此句柄在WindowsVista 及以后版本的Windows系统中是内核句柄。在较早版本的Windows 里,此句柄不可以是内核句柄。
DesiredAccess[in]所需访问权限[输入参数]
指定ACCESS_MASK值用于指明对所创建线程的存取权限要求。
ObjectAttributes[in, optional]对象属性[输入参数,可选]
指向一个结构,它指定对象的属性。OBJ_PERMANENT,OBJ_EXCLUSIVE,和OBJ_OPENIF不是线程对象的有效属性。在Windows XP和更高版本的Windows,如果对方不在系统进程的上下文中运行,它必须为ObjectAttributes设置OBJ_KERNEL_HANDLE属性。对微软的Windows 2000和Windows 98/Me的驱动必须只在系统进程上下文中调用PsCreateSystemThread。对于WindowsVista 及其后版本的WindowsVista,此句柄将是一个内核句柄。
ProcessHandle[in, optional] 进程句柄[输入参数,可选]
指定“在其地址空间中运行线程的那个进程”的一个打开的句柄。调用者的线程必须对这个进程有process_create_thread访问权限。如果不提供此参数,则将在初始系统进程中创建线程。在为一个驱动程序创建的线程里,这个值应该是空的。可使用定义在ntddk.H中的NtCurrentProcess宏,来指定当前进程。
ClientId[out, optional]客户标识[输出参数,可选]
指向用于“接收新线程的客户端标识符”的结构。在为一个驱动程序创建的线程里,这个值应该是空的。
StartRoutine[in]开始例程[输入参数]
新创建的系统线程的入口点。这个参数是一个函数指针,指向能接收一个参数的ThreadStart例程,参数值是由调用者提供的startcontext参数。
StartContext[in, optional]开始语境[输入参数,可选]
当本函数(PsCreateSystemThread)开始执行时,提供一个单独的参数传递给所创建的线程。
返回值
PsCreateSystemThread如果成功创建线程则返回STATUS_SUCCESS.
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
2. 线程中睡眠
NTSTATUS KeDelayExecutionThread(
_In_ KPROCESSOR_MODE WaitMode,
_In_ BOOLEAN Alertable,
_In_ PLARGE_INTEGER Interval
);
Parameters
WaitMode [in]
Specifies the processor mode in which the caller is waiting, which can be either KernelMode or UserMode. Lower-level drivers should specify KernelMode.
Alertable [in]
Specifies TRUE if the wait is alertable. Lower-level drivers should specify FALSE.
Interval [in]
Specifies the absolute or relative time, in units of 100 nanoseconds, for which the wait is to occur. A negative value indicates relative time. Absolute expiration times track any changes in system time; relative expiration times are not affected by system time changes.
Return value
KeDelayExecutionThread returns one of the following values that describes how the delay was completed:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
Return code | Description |
---|---|
STATUS_SUCCESS | The delay completed because the specified interval elapsed. |
STATUS_ALERTED | The delay completed because the thread was alerted. |
STATUS_USER_APC | A user-mode APC was delivered before the specified Interval expired. |
Note that the NT_SUCCESS macro recognizes all of these status values as “success” values.
3. 使用同步事件
VOID
KeInitializeEvent(
IN PRKEVENT Event, // 这个参数是初始化事件对象的指针
IN EVENT_TYPE Type, // 这个参数是事件的类型。一类是“通知事件”对应参数为 NotificationEvent。另一类是“同步事件”,对应参数 SynchronizationEvent
IN BOOLEAN State // TRUE:事件对象初始化状态为激发。FALSE:事件对象初始化状态为未激发
);
- 1
- 2
- 3
- 4
- 5
- 6
LONG KeSetEvent(
_Inout_ PRKEVENT Event,
_In_ KPRIORITY Increment,
_In_ BOOLEAN Wait
);
Parameters
Event [in, out]
A pointer to an initialized event object for which the caller provides the storage.
Increment [in]
Specifies the priority increment to be applied if setting the event causes a wait to be satisfied.
Wait [in]
Specifies whether the call to KeSetEvent is to be followed immediately by a call to one of the KeWaitXxx routines. If TRUE, the KeSetEvent call must be followed by a call to KeWaitForMultipleObjects, KeWaitForMutexObject, or KeWaitForSingleObject. For more information, see the following Remarks section.
Return value
If the previous state of the event object was signaled, a nonzero value is returned.
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
NTSTATUS KeWaitForSingleObject(
_In_ PVOID Object,
_In_ KWAIT_REASON WaitReason,
_In_ KPROCESSOR_MODE WaitMode,
_In_ BOOLEAN Alertable,
_In_opt_ PLARGE_INTEGER Timeout
);
Parameters
Object [in]
Pointer to an initialized dispatcher object (event, mutex, semaphore, thread, or timer) for which the caller supplies the storage.
WaitReason [in]
Specifies the reason for the wait. A driver should set this value to Executive, unless it is doing work on behalf of a user and is running in the context of a user thread, in which case it should set this value to UserRequest.
WaitMode [in]
Specifies whether the caller waits in KernelMode or UserMode. Lowest-level and intermediate drivers should specify KernelMode. If the given Object is a mutex, the caller must specify KernelMode.
Alertable [in]
Specifies a Boolean value that is TRUE if the wait is alertable and FALSE otherwise.
Timeout [in, optional]
Pointer to a time-out value that specifies the absolute or relative time, in 100-nanosecond units, at which the wait is to be completed.
A positive value specifies an absolute time, relative to January 1, 1601. A negative value specifies an interval relative to the current time. Absolute expiration times track any changes in the system time; relative expiration times are not affected by system time changes.
If *Timeout = 0, the routine returns without waiting. If the caller supplies a NULL pointer, the routine waits indefinitely until the dispatcher object is set to the signaled state. For more information, see the following Remarks section.
Return value
KeWaitForSingleObject can return one of the following:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
Return code | Description |
---|---|
STATUS_SUCCESS | The dispatcher object specified by the Object parameter satisfied the wait. |
STATUS_ALERTED | The wait was interrupted to deliver an alert to the calling thread. |
STATUS_USER_APC | The wait was interrupted to deliver a user asynchronous procedure call (APC) to the calling thread. |
STATUS_TIMEOUT | A time-out occurred before the object was set to a signaled state. This value can be returned when the specified set of wait conditions cannot be immediately met and Timeout is set to zero. |
Note that the NT_SUCCESS macro recognizes all of these status values as “success” values.
4. 示例代码
static KEVENT s_Event
//程序说明开始
//==================================================================================
// 功能 : 测试线程函数
// 参数 :
// (入口)
// (出口) 无
// 返回 : VOID
// 主要思路 :
// 调用举例 :
// 日期 : 2016年7月7日 07:24:03 - 2016年7月7日 07:44:41
//==================================================================================
//程序说明结束
NTSTATUS
Thread()
{
static UNICODE_STRING str = RTL_CONSTANT_STRING(L"test thread");
HANDLE ThreadHandle = NULL;
NTSTATUS Status = STATUS_SUCCESS;
KdPrint(("启动线程函数\n"));
//初始化事件
//第二个参数是事件的类型,一类是“通知事件”,对应参数是NotificationEvent。
//另一类是“同步事件”,对应是SynchronizationEvent
//第三个参数如果为真,事件对象的初始化状态为激发状态。
//如果为假,则事件对象的初始化状态为未激发状态
//如果创建的事件对象是“通知事件”,当事件对象变为激发状态时,
//程序员需要手动将其改回未激发
//如果创建的事件对象是“同步事件”,当事件对象为激发状态时,
//如果遇到KeWaitForXXX等内核函数,事件对象则自动变回未激发状态
// 当是TRUE 时初始化事件是有信号状态.,当是FALSE时初始化事件是没信号状态,
//如果此处为TRUE,则为有信号状态,KeWaitForSingleObject会直接通过,
//此时需要调用KeResetEvent来设置为无信号
KeInitializeEvent(&s_Event, SynchronizationEvent, FALSE);
//KeResetEvent(&s_Event);//指定的事件对象设置为无信号状态。
//启动线程
Status = PsCreateSystemThread(
&ThreadHandle,
0,NULL,NULL,NULL,
ThreadProc,
(PVOID)&str);
if (!NT_SUCCESS(Status))
{
DbgPrint("线程启动失败!!-%#X");
return Status;
}
//Do Something
KdPrint(("做一些事!!\n"));
KdPrint(("线程启动函数结束!!\n"));
ZwClose(ThreadHandle);
KeWaitForSingleObject(&s_Event, Executive, KernelMode, 0, 0);
KdPrint(("线程启动函数返回!!\n"));
return Status;
}
//程序说明开始
//==================================================================================
// 功能 : 线程函数
// 参数 :
// (入口)
// (出口) 无
// 返回 : VOID
// 主要思路 :
// 调用举例 :
// 日期 : 2016年7月7日 07:44:29 - 2016年7月7日 08:51:17
//==================================================================================
//程序说明结束
VOID
ThreadProc(__in PVOID Context)
{
PUNICODE_STRING str = (PUNICODE_STRING)Context;
LARGE_INTEGER Interval;
LONG Msec = 3000;
//打印字符串
KdPrint(("进入线程函数 : %wZ\n", str));
//Msec若为1000,则 睡眠的时间为: 1000 * 100 ns * 10 *1000 =1s
Interval.QuadPart = DELAY_ONE_MILLISECOND;
Interval.QuadPart *= Msec;
GetTime();
GetTime();
KeDelayExecutionThread(KernelMode, 0, &Interval);
GetTime();
KdPrint(("线程函数结束\n"));
//设置事件
KeSetEvent(&s_Event, 0, TRUE);
//结束自己
PsTerminateSystemThread(STATUS_SUCCESS);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- jpg 改 rar