Windows操作系统多核CPU内核线程管理方法
inity 域。然而Windows 内核结构被放在虚拟内存线性地址的高2G(不同版本Windows 下也可能是1G)地址空间,用户模式下的应用程序是无法访问这段内存空间的,所以必须编写Windows 驱动程序,来访问Windows 内核内存空间, 这也是本文将要描述的重点。
3 线程管理服务系统
整个系统的结构如图3 所示。该系统由两大部分组成,分别是内核模式下的管理服务系统设备驱动程序,和用户模式下的管理服务系统应用程序。管理服务系统应用程序通过调用Win32 子系统API,向内核下的管理服务系统驱动程序传递IRP,内核收到IRP 后,跟据收到的IRP 的内部信息,执行相应的派遣函数,对相应内存进行读写,从而给管理服务系统应用程序提供可用的系统信息。
图3 管理系统总体结构图。
3.1 内核模式下读取系统信息
线程管理服务系统驱动程序中,读取系统信息的方法用到了微软没有公开文档的内核服务函数,ZwQuerySystemInformATIon,这个函数被封装在ntdll.dll模块中,通过链接ntdll.lib 可得到此函数地址。通过一个枚举量SystemProcessInformaTIon 来得到进程线程相关信息,填入到第二个输入参数SYSTEM_PROCESS_INFORMATION结构中, 这样就获得了当前系统关于进程线程的信息。
3.2 内核模式下枚举系统进程线程
SYSTEM_PROCESS_INFORMATION结构中存储了进程及其线程的所有相关信息,表1 列出了它的具体内容,包括结构内域的地址偏移, 数据类型和描述。
SYSTEM_PROCESS_INFORMATION的第一个DWORD型是下一个进程 SYSTEM_PROCESS_INFORMATION相对于当前结构地址的偏移量,可以通过地址偏移来遍历所有的进程结构,当遇到某一个进程结构的0 x 0 0 0 0 处的DWORD 型值为0 时,说明这个结构体是系统内最后一个结构体。线程管理服务在它的派遣函数中通过这种方式遍历所有进程,从中提取有用的信息,填入两个自定义结构体中。如图 4 所示,描述了一个具有两个线程的进程的数据结构,首先在MY_PROCESS_INFO 结构中填入进程的相关信息,然后根据此进程所有的线程数,向系统申请足够大的分页内存空间,PVOID 型指针指向的是第一个线程结构所在的地址空间,然后向线程结构体中_MY_THREAD_INFO 中填入线程信息,再由线程结构体中的PVOID 型指针指向第二个线程结构体所在的地址空间,以此类推,最后一个线程结构体的PVOID型指针指向NULL。这样一个过程描述了一个进程及其所属的所有线程的枚举过程,通过对所有进程的遍历,可以得到系统中的一个完整的进程线程表,存在一段分页内存中,这样在应用程序中便可以得到这些信息。
表1 SYSTEM_PROCESS_INFORMATION 结构
图4 进程线程的两种数据结构。
3.3 线程管理服务系统应用程序设计
进程管理服务系统应用程序是要通过调用Win 32子系统的API 函数DeviceIoControl 来向线程管理服务系统驱动程序发送IRP 的,然后在IRP 结束之后把驱动程序中读出的所有有用进程线程信息填入到指定的内存中。这样线程管理服务系统应用程序就可以根据所获得的系统信息句柄来对线程CPU 亲缘性属性进行设置。首先为DeviceIoControl 中的InputBuffer 申请一段内存空间传入给驱动程序,驱动程序读取内核空间进程线程信息写入到这段内存中,应用程序读到信息并显示给用户。
在系统中应用程序为每一个CPU 维护一个结构体,内容包括该CPU 是否运行实时线程,该CPU 上运行的线程数(如果是实时线程CPU线程数为1),以及在此CPU上运行的线程结构数组的首地址。系统通过对此CPU 结构数组的解析来对线程进行管理。并通过DeviceIoControl函数把设置后的CPU 结构交给驱动程序内核。
3.4 修改Windows 内核结构体
在驱动程序读回应用程序下用户的设置结果后,就需要按照用户的设定修改KTHREAD 下的Affinity 域的掩码值了。首先要找到KTHREAD 的线性内存空间,PsGetCurrentProcess()内核函数可以返回内核下当前进程空间的E P R O C E S S 结构。E P R O C E S S 结构下的ActiveProcessLinks 域是LIST_ENTRY 结构,通过它可以遍历所有的ETHREAD 结构,那么那到KTHREAD 下的Affinity 域就不难了,可以使用两个循环嵌套来得到所有线程的Affinity 域并将其值设为应用程序中用户的设定值。线程CPU 掩码就被成功的修改了。当CPU 被设定为运行实时线程的CPU 时,在它上面运行的线程只能是一个实时线程,这时的运行线程数被设定为1; 当CPU被设定为非实时线程的时候,上面有可能除了任务线程运行之外,还有Windows 系统进程下的线程。
4 软件使用及性能测试
4.1 驱动的加载及软件的使用
首先需要把本系统的驱动sys 文件加载到Windows的服务管理器
- uClinux进程调度器的实现分析(04-13)
- Linux进程调度策略(09-12)
- Linux在嵌入式系统中有关进程调度算法的实时性改进(04-06)
- FPGA与多核CPU如何改变嵌入式设计(06-04)