😘欢迎关注:👍点赞🙌收藏✍️留言
🏇码字不易,你的👍点赞🙌收藏❤️关注对我真的很重要,有问题可在评论区提出,感谢支持!!!
实验七 显示进程列表
一、实验目的
掌握进程结构及进程管理原理
二、实验内容
- 实验名称:显示进程列表
- 实验任务:
编写一个模块,将它作为Linux内核空间的扩展来执行,并报告模块加载时内核的当前进程信息,进一步了解用户空间和内核空间的概念。
三、实验过程记录
部分A
实验任务:查看系统已加载模块。写一个小的模块打印“hello world”。
查看已加载模块,如图所示。
编写小模块打印“hello world”
代码如下:
20191909.c文件
#include<linux/module.h> int hello_init(void) { printk("\nhello world\n"); return 0; } void hello_exit(void){ printk("\n bye bye world\n"); } MODULE_AUTHOR("20191909");//id MODULE_LICENSE("GPL"); module_init(hello_init); module_exit(hello_exit);
Makefile文件
obj-m:=20191909.o KERNELDIR ?= /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) default: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
操作如下:
编译 make 如图1所示
图1
加载模块insmod 20191909.ko 如图2所示
图2
查看日志dmesg如图3所示
图3
4) 删除模块rmmod 20191909.ko 如图4所示
图4
查看日志dmesg如图5所示
图5
部分B
实验任务:设计模块遍历进程描述符链表,打印出系统的进程数目、当前进程,并尽量多地打印每个进程的信息。例如:进程PID,进程状态等。
编写代码如下:
20191909.c文件
#include <linux/init.h> #include <linux/module.h> #include <linux/proc_fs.h> #include <asm/uaccess.h> #include <linux/sched.h> #include <linux/kernel.h> MODULE_LICENSE("GPL"); static int num = -1; module_param(num, int, S_IRUGO); static __init int exp_init(void){ struct task_struct *p = NULL; // for_each_process宏遍历系统中的每个进程,将其赋值给p printk("数量:%d",num); for_each_process(p) { if (num==0 ) break; // 使用printk函数打印当前进程的PID和进程名称,real_parent->pid : 父进程id __state : 状态 printk("pid=%d,name=%s,parent_id=%d,state=%d\n", p->pid, p->comm,p->real_parent->pid,p->__state); num--; } return 0; } static __exit void exp_exit(void){ printk("Good bye.\n"); } module_init(exp_init); module_exit(exp_exit);
Makefile 文件
obj-m:=20191909.o KERNELDIR ?= /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) default: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
操作如下:
编译make 如图6所示
图6
加载模块insmod 20191909.ko 如图7所示
图7
查看日志 dmesg 可以看到进程的PID、进程名称、父进程id、当前状态 如图8所示
图8
删除模块 rmmod 20191909.ko如图9所示
图9
四、实验小结
本次实验旨在通过编写Linux内核模块来了解用户空间和内核空间的概念,并掌握如何显示进程列表。实验分为两部分进行。
在实验的第一部分中,我们成功编写了一个简单的内核模块,用以打印“hello world”信息。通过编译、加载模块、查看日志和删除模块的步骤,我们确认了模块的正确加载和工作。这个过程加深了我们对内核模块生命周期管理的理解。
在实验的第二部分中,我们设计了一个更复杂的内核模块,用于遍历进程描述符链表,打印出系统的进程数目、当前进程以及尽可能多的进程信息(例如:进程PID,进程状态等)。通过这个过程,我们不仅学习了如何访问和操作内核中的进程信息,还加深了对Linux内核进程管理机制的了解。
存在的问题和注意事项:
- 在编写内核模块时,需要确保代码的稳定性和安全性,因为任何错误都可能导致系统崩溃或安全漏洞。
- 在使用
printk
进行调试时,应该注意其输出级别,以免产生大量的日志信息影响系统性能。 - 在遍历进程时,我们使用了
for_each_process
宏,需要了解其工作原理及如何正确使用它。 - 模块参数的使用提供了灵活性,但也需要注意确保传入的参数是合法的,防止模块运行时出现异常。
有待提高的能力: - 对内核编程的熟练度,包括更深入地理解内核API和内核编程的最佳实践。
- 对Linux内核的整体架构和机制的理解,特别是进程管理、内存管理和模块管理等方面。
- 调试技能的提高,包括使用更高级的内核调试工具和技术。
- 编写更加健壮和高效的内核代码的能力。
- 总体而言,本次实验不仅帮助我们实践了内核模块的编写和操作,还增进了我们对Linux内核的理解,为今后深入学习Linux内核打下了良好的基础。