很多時(shí)候,我們要監(jiān)控系統(tǒng)狀態(tài),即監(jiān)控系統(tǒng)cpu負(fù)載、進(jìn)程狀態(tài)等情況,如果我們在 Linux 應(yīng)用層,我們有很多方式,命令行中常用 top、ps 命令,代碼中,我們可以使用 popen 函數(shù)去執(zhí)行一個(gè) top 命令,獲取返回值。或者我們直接讀寫 /proc下面的文件,都可以達(dá)到目的。
但如果要你在內(nèi)核(驅(qū)動(dòng))中去獲取這些信息,你無法執(zhí)行 top 命令。即便可以使用 flip_open 函數(shù)和加 vfs_read 內(nèi)核函數(shù)去讀寫 /proc 節(jié)點(diǎn)文件,但 Linux 本身不建議這樣做,這會(huì)破壞節(jié)點(diǎn)(驅(qū)動(dòng))之間的獨(dú)立性,如果產(chǎn)生依賴關(guān)系,很可能產(chǎn)生各種各樣的問題:如果你在一個(gè)節(jié)點(diǎn)驅(qū)動(dòng)中讀寫另外一個(gè)節(jié)點(diǎn)的內(nèi)容,而另外一個(gè)掛載出了問題,系統(tǒng)就會(huì)不穩(wěn)定。
所以我們一般直接從 Linux 內(nèi)核本身獲取信息,去分析 Linux 內(nèi)核源碼,從他本身的數(shù)據(jù)結(jié)構(gòu)(結(jié)構(gòu)體、變量、鏈表)中獲取信息。
今天教大家如何在驅(qū)動(dòng)中直接獲取 linux 系統(tǒng)中所有進(jìn)程信息。進(jìn)程有很多信息,在 /proc/[pid] 目錄中中只放了很少一部分,我們訪問內(nèi)核數(shù)據(jù)結(jié)構(gòu)可以獲取全部所有信息。
我們知道Linux系統(tǒng)管理進(jìn)程是使用PCB(process control block),進(jìn)程控制塊,內(nèi)核使用一個(gè)結(jié)構(gòu)體描述它,這個(gè)結(jié)構(gòu)體現(xiàn)在有600多行,叫 task_struct 結(jié)構(gòu)體,這個(gè)結(jié)構(gòu)體在 linux 內(nèi)核源碼 linux/include/linux/sched.h 中。
task.c
# include < linux/kernel.h >
# include < linux/module.h >
# include < uapi/linux/sched.h >
# include < linux/init_task.h >
# include < linux/init.h >
# include < linux/fdtable.h >
# include < linux/fs_struct.h >
# include < linux/mm_types.h >
//內(nèi)核模塊初始化函數(shù)
static int __init traverse_pcb(void)
{
struct task_struct *task, *p;//定義指向task_struct類型的指針
struct list_head *pos;//定義雙向鏈表指針
int count=0;//定義統(tǒng)計(jì)系統(tǒng)進(jìn)程個(gè)數(shù)的變量
printk("Printf process'message begin:n");//提示模塊開始運(yùn)行
task = &init_task;//指向0號(hào)進(jìn)程的PCB
list_for_each(pos,&task- >tasks)//使用list_for_each宏來遍歷進(jìn)程鏈表
{
p = list_entry(pos,struct task_struct,tasks);//指向當(dāng)前進(jìn)程的task_struct結(jié)構(gòu)
count++;//統(tǒng)計(jì)系統(tǒng)進(jìn)程個(gè)數(shù)
printk("nn");//方便查看后續(xù)打印信息
/*
打印task_struct中的字段.comm:name.pid:進(jìn)程的pid號(hào);state:進(jìn)程的狀態(tài);
prio:動(dòng)態(tài)優(yōu)先級(jí);static_prio:靜態(tài)優(yōu)先級(jí); parent'pid:父進(jìn)程的pid號(hào);
count:文件系統(tǒng)信息,文件被使用的次數(shù); umask:進(jìn)程權(quán)限位的默認(rèn)設(shè)置;
使用atomic_read原子操作是為了(p- >files)- >count字段計(jì)數(shù)不被打斷
*/
printk("comm:%s; pid:%d; state:%lx; prio:%d; static_prio:%d; parent'pid:%d; count:%d; umask:%d;",
p- >comm,p- >pid,p- >state,p- >prio,p- >static_prio,(p- >parent)- >pid,
atomic_read((&(p- >files)- >count)),(p- >fs)- >umask);
//打印進(jìn)程地址空間的信息
if((p- >mm)!=NULL)
printk("total_vm:%ld;",(p- >mm)- >total_vm);//total_vm:線性區(qū)總的頁數(shù)
}
printk("進(jìn)程的個(gè)數(shù):%dn",count);//打印進(jìn)程個(gè)數(shù)
return 0;
}
//內(nèi)核模塊退出函數(shù)
static void __exit end_pcb(void)
{
printk("traverse pcb is end.");
}
module_init(traverse_pcb);//入口
module_exit(end_pcb);//出口
MODULE_LICENSE("GPL");//許可證
Makefile
KERNELDIR := /home/book/linux/tool/kernel/linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek
CURRENT_PATH := $(shell pwd)
obj-m := task.o
build: kernel_modules
kernel_modules:
$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules
clean:
$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean
編譯
我們會(huì)編譯出一個(gè)task.ko內(nèi)核模塊,把它拷貝到板子中,進(jìn)行掛載。
掛載上以后就會(huì)觸發(fā) _init 函數(shù),就會(huì)打印。當(dāng)然我們也可以把這段代碼放在 xxx_read 函數(shù)中,在 _init 函數(shù)中創(chuàng)建節(jié)點(diǎn),訪問一次節(jié)點(diǎn)就打印一次,都可以。
博主這個(gè)系統(tǒng)進(jìn)程很少,只有 70-80 個(gè),是 buildroot 自己編譯的文件系統(tǒng),沒有什么功能。
我們通過定義的p結(jié)構(gòu)體指針,可以訪問系統(tǒng)中所有進(jìn)程的 io、運(yùn)行時(shí)間、內(nèi)存信息、進(jìn)程被調(diào)用次數(shù),任何和進(jìn)程有關(guān)的信息都存在于 task_struct 中。
Linux 內(nèi)核采用 task_struct 來描述一個(gè)進(jìn)程。當(dāng)系統(tǒng)起來以后,隨著 init(pid=1)進(jìn)程 fork 出其他進(jìn)程,會(huì)有一個(gè)雙向鏈表,將所有的由 init 創(chuàng)建的進(jìn)程串起來,我們通過遍歷這個(gè)雙向鏈表,進(jìn)而獲取所有進(jìn)程的 task_struct 結(jié)構(gòu)體,把信息取出來。在驅(qū)動(dòng)中這樣做,遠(yuǎn)比訪問 /proc 文件方便多了。
note:編譯之前記得準(zhǔn)備好你的 Linux 內(nèi)核源碼,因?yàn)榫幾g需要引用頭文件,所以我們在 Makefile 中寫明 Linux 內(nèi)核源碼目錄(源碼必須是編譯過的源碼,編譯 Linux 大概需要半個(gè)多小時(shí))。另外需要注意,你編譯驅(qū)動(dòng)所引用的內(nèi)核和你板子中真正運(yùn)行的 Linux 內(nèi)核要需要是同一個(gè)版本,否則掛載不上去。
-
內(nèi)核
+關(guān)注
關(guān)注
3文章
1382瀏覽量
40427 -
Linux
+關(guān)注
關(guān)注
87文章
11345瀏覽量
210403 -
監(jiān)控系統(tǒng)
+關(guān)注
關(guān)注
21文章
3941瀏覽量
176885 -
系統(tǒng)
+關(guān)注
關(guān)注
1文章
1019瀏覽量
21431
發(fā)布評論請先 登錄
相關(guān)推薦
評論