1. 程式人生 > 其它 >HDU作業系統課程設計實驗二

HDU作業系統課程設計實驗二

技術標籤:HDU code作業系統

HDU作業系統課程設計實驗二


這是一個比較簡單、容易的實驗,前提條件是對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/實驗二/