微信
投稿

手把手教你获取Linux所有进程信息

2021-09-03 14:55 来源:嵌入式Linux系统开发 作者:

很多时候,我们要监控系统状态,即监控系统cpu负载、进程状态等情况,如果我们在 Linux 应用层,我们有很多方式,命令行中常用 top、ps 命令,代码中,我们可以使用 popen 函数去执行一个 top 命令,获取返回值。或者我们直接读写 /proc下面的文件,都可以达到目的。

但如果要你在内核(驱动)中去获取这些信息,你无法执行 top 命令。即便可以使用 flip_open 函数和加 vfs_read 内核函数去读写 /proc 节点文件,但 Linux 本身不建议这样做,这会破坏节点(驱动)之间的独立性,如果产生依赖关系,很可能产生各种各样的问题:如果你在一个节点驱动中读写另外一个节点的内容,而另外一个挂载出了问题,系统就会不稳定。

所以我们一般直接从 Linux 内核本身获取信息,去分析 Linux 内核源码,从他本身的数据结构(结构体、变量、链表)中获取信息。

今天教大家如何在驱动中直接获取 linux 系统中所有进程信息。进程有很多信息,在 /proc/[pid] 目录中中只放了很少一部分,我们访问内核数据结构可以获取全部所有信息。

我们知道Linux系统管理进程是使用PCB(process control block),进程控制块,内核使用一个结构体描述它,这个结构体现在有600多行,叫 task_struct 结构体,这个结构体在 linux 内核源码 linux/include/linux/sched.h 中。

task.c

# include

# include

# include

# include

# include

# include

# include

# include

//内核模块初始化函数

static int __init traverse_pcb(void)

{

struct task_struct *task, *p;//定义指向task_struct类型的指针

struct list_head *pos;//定义双向链表指针

int count=0;//定义统计系统进程个数的变量

printk("Printf process'message begin:\n");//提示模块开始运行

task = &init_task;//指向0号进程的PCB

list_for_each(pos,&task->tasks)//使用list_for_each宏来遍历进程链表

{

p = list_entry(pos,struct task_struct,tasks);//指向当前进程的task_struct结构

count++;//统计系统进程个数

printk("\n\n");//方便查看后续打印信息

/*

打印task_struct中的字段.comm:name.pid:进程的pid号;state:进程的状态;

prio:动态优先级;static_prio:静态优先级; parent'pid:父进程的pid号;

count:文件系统信息,文件被使用的次数; umask:进程权限位的默认设置;

使用atomic_read原子操作是为了(p->files)->count字段计数不被打断

*/

printk("comm:%s; pid:%d; state:%lx; prio:%d; static_prio:%d; parent'pid:%d; count:%d; umask:%d;", \

p->comm,p->pid,p->state,p->prio,p->static_prio,(p->parent)->pid, \

atomic_read((&(p->files)->count)),(p->fs)->umask);

//打印进程地址空间的信息

if((p->mm)!=NULL)

printk("total_vm:%ld;",(p->mm)->total_vm);//total_vm:线性区总的页数

}

printk("进程的个数:%d\n",count);//打印进程个数

return 0;

}

//内核模块退出函数

static void __exit end_pcb(void)

{

printk("traverse pcb is end.");

}

module_init(traverse_pcb);//入口

module_exit(end_pcb);//出口

MODULE_LICENSE("GPL");//许可证

Makefile

KERNELDIR := /home/book/linux/tool/kernel/linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek

CURRENT_PATH := $(shell pwd)

obj-m := task.o

build: kernel_modules

kernel_modules:

$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules

clean:

$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean

编译


手把手教你获取Linux所有进程信息


我们会编译出一个task.ko内核模块,把它拷贝到板子中,进行挂载。


手把手教你获取Linux所有进程信息


挂载上以后就会触发 _init 函数,就会打印。当然我们也可以把这段代码放在 xxx_read 函数中,在 _init 函数中创建节点,访问一次节点就打印一次,都可以。

博主这个系统进程很少,只有 70-80 个,是 buildroot 自己编译的文件系统,没有什么功能。

我们通过定义的p结构体指针,可以访问系统中所有进程的 io、运行时间、内存信息、进程被调用次数,任何和进程有关的信息都存在于 task_struct 中。

Linux 内核采用 task_struct 来描述一个进程。当系统起来以后,随着 init(pid=1)进程 fork 出其他进程,会有一个双向链表,将所有的由 init 创建的进程串起来,我们通过遍历这个双向链表,进而获取所有进程的 task_struct 结构体,把信息取出来。在驱动中这样做,远比访问 /proc 文件方便多了。

note:编译之前记得准备好你的 Linux 内核源码,因为编译需要引用头文件,所以我们在 Makefile 中写明 Linux 内核源码目录(源码必须是编译过的源码,编译 Linux 大概需要半个多小时)。另外需要注意,你编译驱动所引用的内核和你板子中真正运行的 Linux 内核要需要是同一个版本,否则挂载不上去。


免责声明: 凡注明来源本网的所有作品,均为本网合法拥有版权或有权使用的作品,欢迎转载,注明出处。非本网作品均来自互联网,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。

精彩评论

暂无评论...
验证码 换一张
取 消

热门作者

东方

简介: 天马行空的文字之旅。

邮箱: liutingting03@hczyw.com

简介: 保持期待,奔赴山海。

邮箱: zhuangjiaxin@hczyw.com

松月

简介: 脚踏实地,仰望星空。

邮箱: wuxiaqing@hczyw.com

合作咨询:15889679808               媒体咨询:13650668942

广州地址: 广州市越秀区东风东路745号紫园商务大厦19楼

深圳地址: 广东省深圳市龙华区五和大道星河WORDC座5F506

北京地址: 北京市朝阳区小关东里10号院润宇大厦2层

慧聪电子网微信公众号
慧聪电子网微信视频号

Copyright?2000-2020 hczyw.com. All Rights Reserved
慧聪电子网    粤ICP备2021157007号