HDU作業系統課程設計實驗二
HDU作業系統課程設計實驗二
這是一個比較簡單、容易的實驗,前提條件是對Linux核心的父子程序連結串列遍歷、查詢、訪問等有一定的瞭解。注意:實驗時可能因為模組程式碼有問題導致模組無法正常載入,被阻塞在hello_init()函式中,以至於模組無法被rmmod命令解除安裝。重啟虛擬機器,模組自動解除安裝。
一、設計目的
Linux提供的模組機制能動態擴充Linux功能而無需重新編譯核心,已經廣泛應用在Linux核心的許多功能的實現中。在本實驗中將學習模組的基本概念、原理及實現技術,然後利用核心模組程式設計訪問程序的基本資訊,加深對程序概念的理解,掌握基本的模組程式設計技術。
二、內容要求
(1)設計一個模組,要求列出系統中所有核心執行緒的程式名、PID、程序狀態、程序優先順序、父程序的PID,輸出按列對齊。
(2)設計一個帶引數的模組,其引數為某個程序的PID號,模組的功能是列出該程序的家族資訊,包括父程序、兄弟程序和子程序的程式名、PID號及程序狀態,同時實現類似pstree的輸出。
(3)請根據自身情況,進一步閱讀分析程式中用到的相關核心函式的原始碼實現。
三、實驗內容
實驗思路
實驗過程
- 編寫模組程式碼和Makefile檔案。
- 使用
make
命令編譯模組程式碼。 - 使用
insmod
或modprobe
命令將需要載入的模組以目的碼的形式載入到核心中,將自動呼叫init_module巨集。 - 使用
lsmod
命令檢視已載入系統的模組資訊。 - 使用
modinfo
命令檢視指定的模組資訊。 - 使用
rmmod
命令刪除指定的模組。
輸出按列對齊輸出系統中所有核心執行緒的程式名、PID、程序狀態、程序優先順序、父程序的PID
Linux系統中的每個程序都有一個父程序(init程序除外);每個程序還有0個或多個子程序。在程序描述符中parent指標指向其父程序,還有一個名為children的子程序連結串列(父程序task_struct中的children相當於連結串列的表頭)。
參考程式碼(不完整):
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/實驗二/