实验7 显示进程列表
一、实验目的
编写一个模块,将其作为Linux
内核空间的扩展来执行。
二、实验内容
设计模块遍历进程描述符链表,打印出系统的进程数目、当前进程,并尽量多地打印每个进程的信息。例如:进程PID
,进程状态等。
进程是任何多道程序设计的操作系统中的基本概念。为了管理进程,内核必须对每个进程所做的事情进行清楚的描述。例如,内核必须知道进程的优先级,它是正在CPU上运行还是因某些事件被阻塞,给它分配什么样的地址空间,允许它访问哪个文件等等。这正是进程描述符的作用进程描述符都是task_struct
类型结构,它的域包含了与一个进程相关的所有信息。因为进程描述符中存放了那么多信息,所以它是相当复杂的。它本身不仅包含了很多域,而且一些域还包括了指向其他数据结构的指针,依此类推。
为了对给定类型的进程(例如,在可运行状态的所有进程)进行有效的搜索,内核建立了几个进程链表。有一个双向循环链表(参见图3.3)把所有现有的进程联系起来,我们叫它为进程链表(process list)。每个进程的prev_task
和next_task
域用来实现链表。init_task
指向描述符链表的头。另外,宏current
总是指向CPU的当前进程。
一旦设计并编写好模块,必须将其编译成一个适合内核装载的对象文件。需要通知编译程序把这个模块作为内核代码而不是普通的用户代码来编译,这可以通过向编译程序传递__KERNEL__
标志来实现(注意在KERNEL
前后各有两个下划线字符)o使用MODULE
编译时标志来通知编译程序该文件是一个模块而不是一个普通文件。使用-W
编译选项来向装载程序(loader),使用-c
开关通知编译程序在编译完这个文件之后无需链接程序。
三、实验步骤
编写代码如下
#define __NO_VERSION=
#define __KERNEL__
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/sched.h>
static int init_module() {
struct task_struct *p = &init_task;
printk("Hello fyw 20182640\n");
printk("name \tPID\tcondition\tprio\ttime_slice\n");
for_each_process(p) { // 直接使用内核提供的函数进行遍历
if (p->mm == NULL) {
printf(KERN_ALTER
"%s\t%-3d\t%-9d\t%-4d\t%-10d\n", p->comm, p->pid, p->state, p->prio, p->time_slice); // 可以调整输出格式
}
}
return 0;
}
static void cleanup_module() {
printk("Goodbye DXH_20182640\n");
}
编译程序
gcc -c -I/usr/src/linux-2.4.22/include -Wall modul.c
将程序加载到内核当中
若加载出现问题(例如警告内核版本不匹配),可以使用-f
开关进行强制加载
insmod modul.o
访问系统日志,查看输出信息
dsmesg
四、实验结论
在日志中将当前系统中各进程的信息输出如下
全部输出完毕后,显示当前运行的进程总数
五、实验心得
通过本次实验,实现了一个功能为显示当前进程、进程状态,进程数目的系统调用。本次实验在编程上的任务量相对较大,且部分内容是过去C
语言课程中未曾设计的内容。
因此,在实验中一定要认真阅读模板代码,弄清楚相关参数的含义和功能,多写代码、多次尝试、举一反三,才能顺利完成本次实验。