HDU操作系统课程设计实验二

这篇博客介绍了如何通过Linux内核模块编程获取系统内核线程信息以及构建进程家族树。实验内容包括设计一个模块列出所有内核线程的程序名、PID、状态、优先级和父PID,并实现类似pstree的功能,展示指定PID进程的家族信息。实验中涉及遍历进程链表、父子进程关系和进程状态的输出。
摘要由CSDN通过智能技术生成


这是一个比较简单、容易的实验,前提条件是对Linux内核的父子进程链表遍历、查找、访问等有一定的了解。注意:实验时可能因为模块代码有问题导致模块无法正常加载,被阻塞在hello_init()函数中,以至于模块无法被rmmod命令卸载。重启虚拟机,模块自动卸载。

一、设计目的

Linux提供的模块机制能动态扩充Linux功能而无需重新编译内核,已经广泛应用在Linux内核的许多功能的实现中。在本实验中将学习模块的基本概念、原理及实现技术,然后利用内核模块编程访问进程的基本信息,加深对进程概念的理解,掌握基本的模块编程技术。

二、内容要求

(1)设计一个模块,要求列出系统中所有内核线程的程序名、PID、进程状态、进程优先级、父进程的PID,输出按列对齐。
(2)设计一个带参数的模块,其参数为某个进程的PID号,模块的功能是列出该进程的家族信息,包括父进程、兄弟进程和子进程的程序名、PID号及进程状态,同时实现类似pstree的输出。
(3)请根据自身情况,进一步阅读分析程序中用到的相关内核函数的源码实现。

三、实验内容

实验思路

要求一思路图(图片出处不详)
要求二思路图(图片出处不详)

实验过程

  1. 编写模块代码和Makefile文件。
  2. 使用make命令编译模块代码。
  3. 使用insmodmodprobe命令将需要载入的模块以目标代码的形式加载到内核中,将自动调用init_module宏。
  4. 使用lsmod命令查看已载入系统的模块信息。
  5. 使用modinfo命令查看指定的模块信息。
  6. 使用rmmod命令删除指定的模块。

输出按列对齐输出系统中所有内核线程的程序名、PID、进程状态、进程优先级、父进程的PID

Linux系统中的每个进程都有一个父进程(init进程除外);每个进程还有0个或多个子进程。在进程描述符中parent指针指向其父进程,还有一个名为children的子进程链表(父进程task_struct中的children相当于链表的表头)。
通过for_each_process(task_struct)函数遍历内核进程对齐输出即可。
参考代码(不完整):

static int myallkt_init(void)
{
	struct task_struct *p;
	p = NULL;
	printk(KERN_ALERT"myallkt begin\n%*s程序名%*s进程号%*s进程状态%*s进程优先级%*s父进程进程号\n",14," ",0," ",0," ",0," ",0," ");
	for_each_process(p)
	{
		if(p->mm == NULL)
		{
			printk(KERN_ALERT"%20s %6d %8ld %10d %12d\n",p->comm,p->pid,p->state,p->prio,p->parent->pid);
		}
	}
	printk(KERN_ALERT"\n");
	return 0;
}

参数为某个进程的PID号,类似pstree的输出该进程的家族信息,包括父进程、兄弟进程和子进程的程序名、PID号及进程状态

通过list_for_each(list_head*,task_struct*)函数遍历,task_struct中的children指针指向其某个子进程的进程描述符task_struct中children的地址而非直接指向某个子进程的地址,也就是说子进程链表中存放的仅仅是各个task_struct成员children的地址。
我们可以用list_entry(ptr,type,member)这个宏来获取task_struct成员的地址,ptr是指向该数据中list_head成员的指针,type是节点的类型,member是节点类型中list_head成员的变量名。
然后按照树状打印即可。
安装模块时传入参数:

module_param(pid, int ,0644); // module_param()宏来修饰要传入的参数变量
insmod 模块名.ko 变量名=值 // 加载模块时出入参数的命令

参考代码(不完整):

void show_it_children(struct task_struct *p,char fout1[100],int fl,int nps)
{
    struct task_struct *pchildren[500];
    struct list_head *L;
    int i = 0,npc = 0,ml = 0;
    char out[100];
    char fout2[100];

    list_for_each(L,&p->children){
        pchildren[npc++]=list_entry(L,struct task_struct,sibling);
    }
    
    //输出当前进程信息
    sprintf(out,"─%s(pid:%d,state:%ld)",p->comm,p->pid,p->state);
    ml = strlen(out) - 1;
    if(npc)
    {
        if(npc != 1)
            sprintf(fout2,"%s%s─┬─",fout1,out);
        else 
            sprintf(fout2,"%s%s───",fout1,out);
    }
    else
    {
        printk("%s%s\n",fout1,out);
        return ;
    }    
    //输出子进程信息
    if(nps - 1 > 0)
        sprintf(fout1,"%*s│%*s",fl,"",ml,"");
    else
	sprintf(fout1,"%*s",fl + ml + 2,"");
    for(i = 0;i < npc;i++)
    {
        sprintf(out,"%s(pid:%d,state:%ld)",pchildren[i]->comm,pchildren[i]->pid,pchildren[i]->state);
        if(i)
        {
            if(i != npc - 1)
                printk("%s├─%s\n",fout1,out);
            else
                printk("%s└─%s\n",fout1,out);
        }
        else
        {
            printk("%s%s\n",fout2,out);
        }
    }
}

static int mypetree_init(void)
{
    struct task_struct *p;
    struct task_struct *psibling[100];
    struct list_head *L;
    int i = 0,nps = 0,fl = 0,tps = 0;
    char out[100];
    char fout1[100];

    p=pid_task(find_vpid(pid),PIDTYPE_PID);

    list_for_each(L,&p->parent->children){
        psibling[nps++]=list_entry(L,struct task_struct,sibling);
    }

    //输出父进程信息
    if(p->parent==NULL)
        sprintf(out,"无父进程─");
    else
        sprintf(out,"%s(pid:%d,state:%ld)─",p->parent->comm,p->parent->pid,p->parent->state);
    fl = strlen(out) - 2;
    if(nps)
        sprintf(fout1,"%s┬",out);
    else
        sprintf(fout1,"%s─",out);

    show_it_children(p,fout1,fl,nps);

    tps = nps - 1;
    //输出兄弟进程信息
    for(i = 0;i < nps;i++)
    {
        if(psibling[i] != p)
        {
            --tps;
            if(tps)
                sprintf(out,"%*s├─",fl,"");
            else
                sprintf(out,"%*s└─",fl,"");
            show_it_children(psibling[i],out,fl,tps);
        }
    }
    return 0;
}

四、实验核心代码

allkt.c:按列对齐输出系统中所有内核线程的程序名、PID、进程状态、进程优先级、父进程的PID。
Makefile1:allkt.c的Makefile文件。
pstree.c:设计一个带参数的模块,其参数为某个进程的PID号,模块的功能是类似pstree的输出该进程的家族信息,包括父进程、兄弟进程和子进程的程序名、PID号及进程状态。
Makefile2:pstree.c的Makefile文件。
完整实验代码详见:HDU-operation-system-course-design-code/实验二/

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值