zoukankan      html  css  js  c++  java
  • 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 codeDescription
    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 codeDescription
    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(("启动线程函数
    "));
        //初始化事件
        //第二个参数是事件的类型,一类是“通知事件”,对应参数是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(("做一些事!!
    "));
    
        KdPrint(("线程启动函数结束!!
    "));
        ZwClose(ThreadHandle);
        KeWaitForSingleObject(&s_Event, Executive, KernelMode, 0, 0);
        KdPrint(("线程启动函数返回!!
    "));
        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
    ", 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(("线程函数结束
    "));
        //设置事件
        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 
  • 相关阅读:
    在Windows7下启动MongoDB服务的解决方案
    Spring MVC之@RequestBody, @ResponseBody 详解
    Spring MVC之@RequestParam @RequestBody @RequestHeader 等详解
    SpringMVC+Shiro权限管理
    Spring中@Async用法总结
    当spring 容器初始化完成后执行某个方法
    Java四种线程池的使用
    JavaWeb动态导出Excel可弹出下载
    kinderEditor + Struts2整合
    请求webservice接口的某方法数据
  • 原文地址:https://www.cnblogs.com/kuangke/p/9397527.html
Copyright © 2011-2022 走看看