很多時候,我們要監控系統狀態,即監控系統cpu負載、進程狀態等情況,如果我們在 Linux 應用層,我們有很多方式,命令行中常用 top、ps 命令,代碼中,我們可以使用 popen 函數去執行一個 top 命令,獲取返回值。或者我們直接讀寫 /proc下面的文件,都可以達到目的。
但如果要你在內核(驅動)中去獲取這些信息,你無法執行 top 命令。即便可以使用 flip_open 函數和加 vfs_read 內核函數去讀寫 /proc 節點文件,但 Linux 本身不建議這樣做,這會破壞節點(驅動)之間的獨立性,如果產生依賴關系,很可能產生各種各樣的問題:如果你在一個節點驅動中讀寫另外一個節點的內容,而另外一個掛載出了問題,系統就會不穩定。
所以我們一般直接從 Linux 內核本身獲取信息,去分析 Linux 內核源碼,從他本身的數據結構(結構體、變量、鏈表)中獲取信息。
今天教大家如何在驅動中直接獲取 linux 系統中所有進程信息。進程有很多信息,在 /proc/[pid] 目錄中中只放了很少一部分,我們訪問內核數據結構可以獲取全部所有信息。
我們知道Linux系統管理進程是使用PCB(process control block),進程控制塊,內核使用一個結構體描述它,這個結構體現在有600多行,叫 task_struct 結構體,這個結構體在 linux 內核源碼 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 >
//內核模塊初始化函數
static int __init traverse_pcb(void)
{
struct task_struct *task, *p;//定義指向task_struct類型的指針
struct list_head *pos;//定義雙向鏈表指針
int count=0;//定義統計系統進程個數的變量
printk("Printf process'message begin:n");//提示模塊開始運行
task = &init_task;//指向0號進程的PCB
list_for_each(pos,&task- >tasks)//使用list_for_each宏來遍歷進程鏈表
{
p = list_entry(pos,struct task_struct,tasks);//指向當前進程的task_struct結構
count++;//統計系統進程個數
printk("nn");//方便查看后續打印信息
/*
打印task_struct中的字段.comm:name.pid:進程的pid號;state:進程的狀態;
prio:動態優先級;static_prio:靜態優先級; parent'pid:父進程的pid號;
count:文件系統信息,文件被使用的次數; umask:進程權限位的默認設置;
使用atomic_read原子操作是為了(p- >files)- >count字段計數不被打斷
*/
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);
//打印進程地址空間的信息
if((p- >mm)!=NULL)
printk("total_vm:%ld;",(p- >mm)- >total_vm);//total_vm:線性區總的頁數
}
printk("進程的個數:%dn",count);//打印進程個數
return 0;
}
//內核模塊退出函數
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
編譯
我們會編譯出一個task.ko內核模塊,把它拷貝到板子中,進行掛載。
掛載上以后就會觸發 _init 函數,就會打印。當然我們也可以把這段代碼放在 xxx_read 函數中,在 _init 函數中創建節點,訪問一次節點就打印一次,都可以。
博主這個系統進程很少,只有 70-80 個,是 buildroot 自己編譯的文件系統,沒有什么功能。
我們通過定義的p結構體指針,可以訪問系統中所有進程的 io、運行時間、內存信息、進程被調用次數,任何和進程有關的信息都存在于 task_struct 中。
Linux 內核采用 task_struct 來描述一個進程。當系統起來以后,隨著 init(pid=1)進程 fork 出其他進程,會有一個雙向鏈表,將所有的由 init 創建的進程串起來,我們通過遍歷這個雙向鏈表,進而獲取所有進程的 task_struct 結構體,把信息取出來。在驅動中這樣做,遠比訪問 /proc 文件方便多了。
note:編譯之前記得準備好你的 Linux 內核源碼,因為編譯需要引用頭文件,所以我們在 Makefile 中寫明 Linux 內核源碼目錄(源碼必須是編譯過的源碼,編譯 Linux 大概需要半個多小時)。另外需要注意,你編譯驅動所引用的內核和你板子中真正運行的 Linux 內核要需要是同一個版本,否則掛載不上去。
-
內核
+關注
關注
3文章
1382瀏覽量
40427 -
Linux
+關注
關注
87文章
11345瀏覽量
210402 -
監控系統
+關注
關注
21文章
3941瀏覽量
176875 -
系統
+關注
關注
1文章
1019瀏覽量
21431
發布評論請先 登錄
相關推薦
評論