設計一個模塊,功能是列出系統中所有內核線程的程序名、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指向的進程描述符進行操作
}