理解Linux内核模块的思想、方法,实现以下任意一个内核模块
通过内核模块显示进程控制块信息:遍历进程树,输出进程PID和进程的可执行文件名
编写makefile,编译内核模块
加载内核模块、测试命令
卸载内核模块
1.target.c文件
#include<linux/init.h>
#include<linux/module.h>
#include<linux/sched.h>
#include<linux/kernel.h>
#include<linux/proc_fs.h>
#include<linux/list.h>
MODULE_LICENSE("GPL");//模块许可声明
static int num=0;
module_param(num,int,S_IRUGO);//module_param()函数接受用户传来的参数num
static int target_init(void){//初始化函数
int i;
struct task_struct *p=&init_task;//获取进程init_task的地址
struct list_head *ptr;//利用list_head数据结构 *ptr,遍历进程控制块
//用户没有输入数字或者输入的数字<=0,遍历所有进程控制块
if(num<=0){
for_each_process(p){//遍历所有的进程控制块
printk(KERN_ALERT"%d\t%s\n",p->pid,p->comm);
}
}
//用户输入的参数为>0的数字,遍历制定数目的进程控制块
else if(num>0){
for(i=0;i<num;i++){
ptr=&p->tasks;
printk(KERN_ALERT"%d\t%s\n",p->pid,p->comm);
//获取ptr当前所指PCB的下一块PCB的地址
p=list_entry(ptr->next,struct task_struct,tasks);
if(p==&init_task){
printk(KERN_ALERT"only %d\n",i);
break;
}
}
}
return 0;
}
static void target_exit(void){//清理函数
printk(KERN_ALERT"exit\n");
}
module_init(target_init);//注册初始化函数
module_exit(target_exit);//注册清理函数
2.Makefile文件
ifneq ($(KERNELRELEASE),)
obj-m := target.o #obj-m指编译成外部模块
else
KERNELDIR := /lib/modules/$(shell uname -r)/build #定义一个变量,指向内核目录
PWD := $(shell pwd)
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules #编译内核模块
endif
3.程序执行结果
make命令编译,产生内核模块target.ko
第一种情况:不输入参数num
第二种情况:输入参数num=200