当前位置:   article > 正文

Linux系统进程输出与统计模块_统计进程数量

统计进程数量

编写一个内核模块,打印系统中各进程的PID和进程名字,同时统计系统中进程个数。

tip:需要用上list_for_each()和list_entry()内核函数

下面这篇文章也可以进行参考

Linux内核模块编程(列出系统中所有内核线程的程序名、PID 号、进程状态及进程优先级、父进程的PID)-CSDN博客


函数原理

list_for_each() 和 list_entry() 是 Linux 内核中用于遍历和访问链表的常用函数。

list_for_each() 函数是一个宏定义,它使用 C 语言中的 for 循环来遍历链表中的每个节点。该宏的参数包括当前节点指针以及链表头指针
 

  1. struct list_head *pos;
  2. list_for_each(pos, &my_list)
  3. {
  4. // 对当前节点进行操作
  5. }

在每次循环迭代时,pos 指针会自动从链表头开始向后移动,直到遍历完整个链表。你可以使用 list_entry() 函数来获取当前节点的数据结构指针
 

  1. struct my_data *data;
  2. list_for_each(pos, &my_list)
  3. {
  4. data = list_entry(pos, struct my_data, list);
  5. // 使用 data 进行操作
  6. }

在上面的示例中,list_entry() 函数会将 pos 转换为一个指向 struct my_data 数据结构的指针,并返回该指针。其中,struct my_data 是链表中每个节点所包含的数据结构类型,list 则是该数据结构中用于嵌入链表的字段名。

需要注意的是,在使用 list_for_each() 和 list_entry() 函数遍历和访问链表时,必须确保链表头节点不包含任何数据,仅作为链表起点使用。另外,链表的节点结构需要包含一个 list_head 类型的字段,以便在链表中链接不同的节点。


源代码

num.c

  1. #include <linux/kernel.h>
  2. #include <linux/module.h>
  3. #include <linux/sched.h>
  4. #include <linux/init_task.h>
  5. #include <linux/list.h>
  6. int hello_init(void)
  7. {
  8. struct task_struct *task;
  9. int num_process = 0;
  10. printk(KERN_INFO "Printing process information:\n");
  11. list_for_each_entry(task, &init_task.tasks, tasks)
  12. {
  13. printk(KERN_INFO "PID: %d, Name: %s\n", task->pid, task->comm);
  14. num_process++;//进程计数器
  15. }
  16. printk(KERN_INFO "Total number of processes: %d\n", num_process);
  17. return 0;
  18. }
  19. void hello_exit(void)
  20. {
  21. printk(KERN_INFO "Exiting module.\n");
  22. }
  23. module_init(hello_init);
  24. module_exit(hello_exit);
  25. MODULE_LICENSE("GPL");
  26. MODULE_DESCRIPTION("Print process information module");

Makefile

  1. obj-m:=num.o
  2. CURRENT_PATH := $(shell pwd)
  3. LINUX_KERNEL := $(shell uname -r)
  4. LINUX_KERNEL_PATH := /usr/src/linux-headers-$(LINUX_KERNEL)
  5. all:
  6. make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules
  7. clean:
  8. make -C $(LINUX_KERNEL_PATH) M=$ (CURRENT_PATH) clean

实验结果

sudo insmod num.ko

dmesg

打印输出了进程号,以及进程名字,最后一次次遍历,统计进程数量

可能出现的问题

make的时候出现,

make: Nothing to be done for `all'.    

在网上找到的资料都显示是重复编译等问题,但其实还有可能用gpt写Makefile文件的时候,因为没有正确缩进,所以显示错误。和这个错误的原因可能是一样的Makefile:18: *** missing separator. Stop.

第二个问题是

Invalid module format,也就是显示无效的模块格式,以下是几种原因

  1. 模块版本不匹配:模块的编译版本与当前运行的内核版本不兼容。请确保你正在使用的模块是针对当前内核版本编译的。尝试重新编译模块并确保编译过程中没有出现任何错误。

  2. 模块依赖关系问题:模块可能依赖于其他模块或库文件,而这些依赖关系可能出现问题。请检查模块的依赖关系,并确保所有依赖项都已正确安装和配置。

  3. 模块文件损坏:模块文件本身可能已损坏。尝试重新下载或获取正确的模块文件,并再次尝试加载。

  4. 内核配置不正确:内核可能未正确配置以支持加载该模块。请确保你的内核配置包括相关功能和选项,以便正确加载模块。

但我检查了很多遍,模块版本是能对上的,可能就只是我的模块内核损坏了?就重新去make其他的文件,发现也是这个错误。。。后面用的是14.04版本的虚拟机。

番外

sy.c

  1. #include <linux/init.h>
  2. #include <linux/module.h>
  3. #include <linux/kernel.h>
  4. #include <linux/sched.h>
  5. #include <linux/init_task.h>
  6. // 初始化函数
  7. static int hello_init(void)
  8. {
  9. struct task_struct *task;
  10. int num_process=0;//统计进程数量
  11. printk(KERN_ALERT"名称\t进程号\t状态\t优先级\t父进程号\t");
  12. for_each_process(task)
  13. {
  14. if (task->mm == NULL)
  15. {
  16. printk(KERN_INFO "%s\t%d\t%d\t%d\t%d\n", task->comm, task->pid, task->prio, task->normal_prio, task->parent->pid);
  17. num_process++;
  18. }
  19. }
  20. printk("%d\n",num_process);
  21. return 0;
  22. }
  23. // 清理函数
  24. static void hello_exit(void)
  25. {
  26. printk(KERN_ALERT"goodbye!\n");
  27. }
  28. // 函数注册
  29. module_init(hello_init);
  30. module_exit(hello_exit);
  31. // 模块许可申明
  32. MODULE_LICENSE("GPL");

Makefile

  1. obj-m += sy.o
  2. all:
  3. make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
  4. clean:
  5. make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

这两段代码也可以进行进程的输出,但是没有用上对应的内核函数

这两段代码就是参考的最最最前面的文章的,就只是加了一个进程计数器

但存在一个问题,两个程序显示的进程数量不一样

pgrep -l . | wc -l            //列出所有进程的信息

ps aux | grep -v "^USER" | wc -l      //grep -v "^USER" 用于过滤掉 ps 命令输出中的表头信息

ps aux | wc -l      
这三个命令都可以来统计并输出进程数量,wc -I 用来统计行数

所以还是前面的靠谱一点,毕竟数量匹配更相近

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号