记一次打印内核进程信息

设计一个模块,列出所有内核线程的程序名、PID号和进程状态

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

  1. 阅读内核源代码,了解进程描述符task_struct中与本实验有关的成员项,以及访问进程队列的宏for_each_process;
  2. 分析内核模块实例,掌握内核模块的主要构成;
  3. 阅读Makefile文件,理解内核模块编译、加载过程;

实验过程

  • 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 = NULL;
        printk(KERN_ALERT"名称\t 进程号\t 状态\t \r\n");
    
        for_each_process(p)
            printk(KERN_ALERT "%d\t%d\t%d\n \r\n",p->comm,p->pid, p->state);
    
        return 0;
    }
    static void hello_exit(void)
    {
        printk(KERN_ALERT "hello world exit \r\n");
    }
    
    module_init(hello_init);//加载函数
    module_exit(hello_exit);        //卸载函数
    MODULE_LICENSE("GPL"); //许可证申明
    MODULE_DESCRIPTION("list taskinfo module");
    
    MODULE_AUTHOR("thirty14");
    
  • Makefile文件:

    ifneq ($(KERNELRELEASE),)
        obj-m:=readprocess.o
    else
        KDIR:= /lib/modules/$(shell uname -r)/build
        PWD:= $(shell pwd)
    
    default:
        $(MAKE) -C $(KDIR) M=$(PWD) modules  
    clean:
        $(MAKE) -C $(KDIR) M=$(PWD) clean
    endif
    
  • 验证一下

    $ make				# 编译
    $ insmod hello.ko	# 插入内科
    $ dmesg				# 查看内核 debug message
    

img

  • 试验结束

实验参考:

一、Linux的内核模块

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

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

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

  1. 利用内核模块的动态装载性的优点
    将内核映象的尺寸保持在最小,并具有最大的灵活性;便于检验新的内核代码,而不需重新编译内核并重新引导。

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

  • 相关操作说明:

    • 必需模块函数
      module_init(hello_init); 	// 载入入口函数
      module_exit(hello_exit);  	// 卸载模块退出函数
      
    • 可选模块函数
      MODULE_LICENSE(*******);	// 许可证申明
      MODULE_AUTHOR(********);	// 作者申明
      MODELE_DESCRIPTION(***);	// 模块描述
      MODULE_VERSION(“V1.0);		// 模块版本
      MODULE_ALIAS("*********");	// 模块别名
      
    • 加载内核模块
      $ insmod hello.ko	# 载入模块
      $ rmmod hello		# 卸载模块
      
    • 查看加载模块是否成功
      $ 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§

    // 宏for_each_process(p)的功能是扫描整个进程链表
    #define for_each_process(p)	\
    	for (p = &init_task ; (p = next_task(p)) != &init_task ; )
    
    // 使用方法 先定义一个task_struct结构的指针
    struct task_struct *p;	
    for_each_process(p){
    	// 使用for遍历链表,查找所有任务
    }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值