设计一个模块,功能是列出系统中所有内核线程的程序名、PID号和进程状态。

来源:互联网 发布:魔兽对战平台mac版 编辑:程序博客网 时间:2024/04/28 08:47

设计一个模块,功能是列出系统中所有内核线程的程序名、PID号和进程状态。主要步骤:

阅读内核源代码,了解进程描述符task_struct中与本实验有关的成员项,以及访问进程队列的宏for_each_process

分析内核模块实例,掌握内核模块的主要构成;

阅读Makefile文件,理解内核模块编译、加载过程;

以下是hello.c文件

#include <linux/sched.h>
#include<linux/init.h>
#include<linux/module.h>
#include<linux/kernel.h>
//#define for_each_process(p)
static int hello_init(void)
{
        struct task_struct *p;
        printk(KERN_ALERT"名称\t进程号\t状态\t");
//      p=NULL;
        for_each_process(p)
        {
                printk(KERN_ALERT"%d\t%d\t%d\n",p->comm,p->pid, p->state);
        }
        return 0;
}
static void hello_exit(void)
{
        printk(KERN_ALERT "hello world exit\n");
}
module_init(hello_init);//加载函数
module_exit(hello_exit);                //卸载函数
MODULE_LICENSE("GPL");  //许可证申明
MODULE_DESCRIPTION("hello module");

MODULE_AUTHOR("liguangcai");

以下是Makefile文件:

ifneq ($(KERNELRELEASE),)
 obj-m:=readprocess.o
else
 KDIR:= /lib/modules/$(shell uname -r)/build
 PWD:= $(shell pwd)

default://注意,default前面最好不要有空格,刚开始做的时候前面加空格报错了
 $(MAKE) -C $(KDIR) M=$(PWD) modules  
clean:://注意,前面最好不要有空格
 $(MAKE) -C $(KDIR) M=$(PWD) clean
endif://注意,前面最好不要有空格

编写完上述两个文件后回到这两个文件所在的目录键入命令: make

然后:

#insmod hello.ko

查看加载模块是否成功:

 #dmesg

自此实验完成!
 
 
实验参考:

一、Linux的内核模块

内核模块是Linux内核向外部提供的一个插口,其全称为动态可加载内核模块(Loadable Kernel Module,LKM),简称模块。Linux内核之所以提供模块机制,是因为它本身是一个单内核(monolithic kernel)。单内核的最大优点是效率高,因为所有的内容都集成在一起,但其缺点是可扩展性和可维护性相对较差,模块机制就是为了弥补这一缺陷。 

模块是具有独立功能的程序,它可以被单独编译,但不能独立运行。它在运行时被链接到内核作为内核的一部分在内核空间运行,这与运行在用户空间的进程是不同的。模块通常由一组函数和数据结构组成,用来实现一种文件系统、一个驱动程序或其他内核上层的功能。

总之,模块是一个为内核(从某种意义上来说,内核也是一个模块)或其他内核模块提供使用功能的代码块。

1.  利用内核模块的动态装载性的优点: 

将内核映象的尺寸保持在最小,并具有最大的灵活性;便于检验新的内核代码,而不需重新编译内核并重新引导。 

2.  内核模块的缺点:

装入的内核模块和其他内核部分一样,具有相同的访问权限,因此,差的内核模块会导致系统崩溃;为了使内核模块访问所有内核资源,内核必须维护符号表,并在装入和卸载模块时修改这些符号表;有些模块要求利用其他模块的功能,因此,内核要维护模块之间的依赖性。内核必须能够在卸载模块时通知模块,并且要释放分配给模块的内存和中断等资源;内核版本和模块版本的不兼容,也可能导致系统崩溃。

 相关操作说明:

a、必需模块函数

加载函数    module_init(hello_init);  

卸载函数    module_exit(hello_exit);    

b、可选模块函数

MODULE_LICENSE(“*******”);    许可证申明

MODULE_AUTHOR(“********”);    作者申明

MODELE_DESCRIPTION(“***”);    模块描述

MODULE_VERSION(“V1.0”);       模块版本

MODULE_ALIAS("*********");    模块别名

c、加载内核模块

载入模块使用insmod命令:

#insmod hello.ko

卸载内核模块使用rmmod命令:

#rmmod hello

d、查看加载模块是否成功

   dmesg可以看到系统的内核模块信息。

三、与本次试验相关的内核代码:

1.  进程控制块的相关内容:

linux/sched.h文件中:

#define TASK_RUNNING 0

#define TASK_INTERRUPTIBLE 1

#define TASK_UNINTERRUPTIBLE 2

#define __TASK_STOPPED 4

#define __TASK_TRACED 8

#define EXIT_ZOMBIE 16

#define EXIT_DEAD 32

#define TASK_DEAD 64

#define TASK_WAKEKILL 128

#define TASK_WAKING 256

#define TASK_PARKED 512

struct task_struct {

volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */

struct list_head tasks;

struct mm_struct *mm;

pid_t pid;

pid_t tgid;

struct task_struct __rcu *real_parent; /* real parent process */

struct task_struct __rcu *parent; /* recipient of SIGCHLD, wait4() reports */

char comm[TASK_COMM_LEN]; /* executable name excluding path */

}

2.  for_each_process(p)宏:

宏for_each_process(p)的功能是扫描整个进程链表

#define for_each_process(p) \ for (p = &init_task ; (p = next_task(p)) != &init_task ; )

使用方法:

struct task_struct *p;

for_each_process(p){

//p指向的进程描述符进行操作

}


0 0
原创粉丝点击