Linux内核学习4——打印进程描述符task_struct中的字段
我们来动手实践打印进程描述符task_struct中的字段这里采用的方式是:插入内核模块,使用的方法是:遍历进程链表一、task_struct初步解读首先要下载自己的源代码,可以参考我之前的博客https://blog.csdn.net/weixin_45730790/article/details/121294180?spm=1001.2014.3001.5501可以使用bootlin在线查看源
我们来动手实践打印进程描述符task_struct中的字段
这里采用的方式是:插入内核模块,使用的方法是:遍历进程链表
一、task_struct初步解读
首先要下载自己的源代码,可以参考我之前的博客https://blog.csdn.net/weixin_45730790/article/details/121294180?spm=1001.2014.3001.5501
可以使用bootlin在线查看源代码
在include文件的目录下打开头文件。task_struct结构位于sched.h头文件中。/include/linux/sched.h
schde.h就显示了pcb在内核中的全貌。涉及的字段非常多。这里只关注pcb本身,并且一些能反映器其结构的字段。
首先看第一个字段state,也就是它的状态信息,
再往下是它的内核栈*stack
flags是进程的标志
ptrace字段是用来实现断点调试的
再往下我们可以看到一些优先级信息
prio是动态优先级,static_prio是静态优先级,rt_priority是实时优先级
再往下可以看到policy字段,这是它的进程调度策略
再往下可以看到调度器统计进程的运行信息 sched_info ,它也是一个结构体
接下来就是tasks字段,这是一个双向链表。正是这个字段把所有的进程连到了一块,我们才能对进程进行遍历。
接下来是它的线性地址的所有信息了
active_mm是最后访问的地址空间指针
这里是进程的亲属关系
打印pcb的重要信息,比如状态信息,优先级信息,亲属关系,文件系统信息以及内存方面的信息。
这两个信息是用来反映上下文切换的次数的,nvcsw反映主动上下文切换的次数,nivcsw反映被动上下文切换的次数
这两个字段用来记录缺页统计
这个数组是相应程序的名字
这两个字段负责相应进程间的通信
这里是非常重要的,它的文件信息。fs保存一个指向文件系统信息的指针,files保存一个指向进程文件描述符表的指针
再往下是它的命名空间
再往下我们可以看到,这是它的信号描述符了
再往下我们可以看到,IRQ都是它的中断信息
内存回收
记录进程的IO计数
后面的字段还有很多,更详细的可以查看博客https://blog.csdn.net/gatieme/article/details/51383272
二、编写内核模块打印task_struct重要字段
我们这里打印pcb的重要属性信息,比如状态信息,进程标识符,优先级信息,亲属关系,文件系统信息以及内存方面的信息。
task_struct.c:
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/sched.h> //task结构体
#include <linux/fdtable.h> //files
#include <linux/fs_struct.h> //fs
#include <linux/mm_types.h> //打印内存信息
#include <linux/init_task.h>
#include <linux/types.h>
#include <linux/atomic.h>
MODULE_LICENSE("GPL"); //许可证
//入口函数
static int __init print_pcb(void) //init宏是由init.h文件所支持
{
struct task_struct *task,*p;
struct list_head *pos; //双向链表
int count=0; //统计当前系统进程一共有多少个
printk("begin...\n");
//对链表遍历时,希望从第一个开始
task=&init_task; //指向0号进程pcb
list_for_each(pos,&task->tasks) //遍历操作,使用pos指向,传入的参数task指向tasks字段.0号进程的tasks进行遍历。tasks将所有的进程连在一块。
{
p=list_entry(pos,struct task_struct,tasks); //找到一个节点,就可以用这个节点的tasks字段,找到这个结构体的地址.对应的字段tasks
//此时的p指针已经指向task_struct结构体的首部,后面就可以通过p指针进行操作
count++; //找到一个进程,自加
printk("\n\n");
printk("pid: %d; state: %d; prior: %d; static_pri: %d; parent_pid: %d; count: %d; umask: %d",p->pid,p->__state,p->prio,p->static_prio,(p->parent)->pid,atomic_read(&(p->files)->count),(p->fs)->umask);
//linux中内核线程的mm是空的,要对它进行打印,就会出错,指针错误
if((p->mm)!=NULL)
printk("Total_vm: %ld",(p->mm)->total_vm); //线性区总的页数
}
printk("进程的个数:%d\n",count);
return 0;
}
static void __exit exit_pcb(void) //出口函数
{
printk("Exiting...\n");
}
// 指明入口点与出口点,入口/出口点是由module.h支持的
module_init(print_pcb);
module_exit(exit_pcb);
Makefile文件如下:
#Makefile文件注意:假如前面的.c文件起名为first.c,那么这里的Makefile文件中的.o文
#件就要起名为first.o 只有root用户才能加载和卸载模块
obj-m:=task_struct.o #产生task_struct模块的目标文件
#目标文件 文件 要与模块名字相同
CURRENT_PATH:=$(shell pwd) #模块所在的当前路径
LINUX_KERNEL:=$(shell uname -r) #linux内核代码的当前版本
LINUX_KERNEL_PATH:=/home/shupeiyao/linux-5.14.17
all:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules #编译模块
#[Tab] 内核的路径 当前目录编译完放哪 表明编译的是内核模块
clean:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean #清理模块
make编译
sudo insmod task_struct.ko 加载内核模块
dmesg 查看内核打印信息
有的没有打印total_vm,说明它的mm字段为空,是内核线程
线程共有361个
以上就是打印Linux内核中的task_struct结构中的重要字段的内容啦
如果对您有帮助麻烦点赞关注或者收藏哦~
更多推荐
所有评论(0)