創(chuàng)建屬于自己的系統(tǒng)信息,往proc中留下一個腳印
點擊上方「嵌入式大雜燴」,「星標(biāo)公眾號」第一時間查看嵌入式筆記!
上一篇:《文件系統(tǒng)有很多,但這幾個最為重要》介紹了procfs(進程文件系統(tǒng)的縮寫),包含一個偽文件系統(tǒng)(啟動時動態(tài)生成的文件系統(tǒng)),用于通過內(nèi)核訪問進程信息。這個文件系統(tǒng)通常被掛載到 /proc 目錄, /proc中不僅僅放了進程相關(guān)信息,也存放著很多系統(tǒng)相關(guān)的信息。
這些信息都是內(nèi)核開放給用戶的,/proc 就是用戶與內(nèi)核直接交互的一個入口。從內(nèi)核的角度看,內(nèi)核是通過怎么樣的方式把這些信息暴露給用戶呢?這篇筆記我們來學(xué)習(xí)一下:
內(nèi)核創(chuàng)建proc節(jié)點的例子
我們先來看一個例子(Linux-4.9.88\fs\proc\cpuinfo.c):
這就是創(chuàng)建/proc下cpuinfo這個節(jié)點的相關(guān)代碼,有了cpuinfo節(jié)點,我們就可以通過訪問這個節(jié)點來得到cpu的一些信息:
從以上代碼中,我們可以看到,其用proc_create這個函數(shù)來創(chuàng)造相關(guān)節(jié)點的,這個函數(shù)是一個內(nèi)聯(lián)函數(shù),存放在Linux-4.9.88\include\linux\proc_fs.h下:
static?inline?struct?proc_dir_entry?*proc_create(
?const?char?*name,?umode_t?mode,?struct?proc_dir_entry?*parent,
?const?struct?file_operations?*proc_fops)
{
?return?proc_create_data(name,?mode,?parent,?proc_fops,?NULL);
}
知識點:什么是內(nèi)聯(lián)函數(shù)?
內(nèi)聯(lián)函數(shù)簡單來說就是編譯器將指定的函數(shù)體插入并取代每一處調(diào)用該函數(shù)的地方上下文,從而節(jié)省了每次調(diào)用函數(shù)帶來的額外時間開支。
一般用于能夠快速執(zhí)行的函數(shù),因為在這種情況下函數(shù)調(diào)用的時間消耗顯得更為突出。這種方法對于很小的函數(shù)也有空間上的益處,并且它也使得一些其他的優(yōu)化成為可能。
這么一看,似乎與宏有點相似?與宏有何不同?
宏調(diào)用并不執(zhí)行類型檢查,甚至連正常參數(shù)也不檢查,但是函數(shù)調(diào)用卻要檢查。 C語言的宏使用的是文本替換,可能導(dǎo)致無法預(yù)料的后果,因為需要重新計算參數(shù)和操作順序。 在宏中的編譯錯誤很難發(fā)現(xiàn),因為它們引用的是擴展的代碼,而不是程序員鍵入的。 許多結(jié)構(gòu)體使用宏或者使用不同的語法來表達很難理解。內(nèi)聯(lián)函數(shù)使用與普通函數(shù)相同的語言,可以隨意的內(nèi)聯(lián)和不內(nèi)聯(lián)。 內(nèi)聯(lián)代碼的調(diào)試信息通常比擴展的宏代碼更有用。
以上介紹摘選自百度百科,關(guān)于內(nèi)聯(lián)更詳細的介紹可自行查閱。
接著上面,proc_create函數(shù)有四個參數(shù),分別為:
name:要創(chuàng)建的文件名。
mode:文件的訪問權(quán)限。
parent:父文件夾的proc_dir_entry指針。
proc_fops:改文件的操作函數(shù)。
看到這個函數(shù),有沒有感到很熟悉?我們在學(xué)習(xí)驅(qū)動基礎(chǔ)的時候,有用到了device_create函數(shù)來創(chuàng)建節(jié)點:
device_create創(chuàng)建的設(shè)備節(jié)點存放于/dev目錄下,而proc_create函數(shù)創(chuàng)建的與系統(tǒng)信息相關(guān)的節(jié)點存放于/proc目錄下。既然它們這么相似,下面我們就模仿編寫驅(qū)動的方式來編寫我們關(guān)于proc的測試代碼。
proc實踐
我們模仿字符設(shè)備驅(qū)動的編寫方式,來編寫基于proc的“驅(qū)動”。首先需要創(chuàng)建一個文件操作結(jié)構(gòu)體hello_proc_operations,創(chuàng)建一些hello_proc_open、hello_proc_close、hello_proc_read、hello_proc_write填到這個操作表里:
左右滑動查看全部代碼>>>
#include?
#include?
#include?
#include?
#include?
static?char?kernel_buf[1024];
#define?MIN(a,?b)?(a?
static?int?hello_proc_open(struct?inode?*node,?struct?file?*file)
{
?printk("%s?%s?line?%d\n",?__FILE__,?__FUNCTION__,?__LINE__);
?return?0;
}
static?ssize_t?hello_proc_read(struct?file?*file,?char?__user?*buf,?size_t?size,?loff_t?*offset)
{
?int?err;
?printk("%s?%s?line?%d\n",?__FILE__,?__FUNCTION__,?__LINE__);
?err?=?copy_to_user(buf,?kernel_buf,?MIN(1024,?size));
?return?MIN(1024,?size);
}
static?ssize_t?hello_proc_write(struct?file?*file,?const?char?__user?*buf,?size_t?size,?loff_t?*offset)
{
?int?err;
?printk("%s?%s?line?%d\n",?__FILE__,?__FUNCTION__,?__LINE__);
?err?=?copy_from_user(kernel_buf,?buf,?MIN(1024,?size));
?return?MIN(1024,?size);
}
static?int?hello_proc_close(struct?inode?*node,?struct?file?*file)
{
?printk("%s?%s?line?%d\n",?__FILE__,?__FUNCTION__,?__LINE__);
?return?0;
}
static?const?struct?file_operations?hello_proc_operations?=?
{
?.owner??=?THIS_MODULE,
?.open??=?hello_proc_open,
?.read????=?hello_proc_read,
?.write???=?hello_proc_write,
?.release?=?hello_proc_close,
};
static?int?__init?hello_proc_init(void)
{
?proc_create("hello_proc",?0,?NULL,?&hello_proc_operations);
?return?0;
}
static?void?__exit?hello_proc_exit(void)
{
?remove_proc_entry("hello_proc",?NULL);
}
module_init(hello_proc_init);
module_exit(hello_proc_exit);
MODULE_DESCRIPTION("proc?test");
MODULE_LICENSE("GPL");
最上邊的那個例子中用了一個fs_initcall宏,這與module_init的底層是差不多相同的(有宏參數(shù)不一樣):
① module_init -> _initcall ?-> ?device_initcall -> ?_define_initcall
② fs_initcall-> _define_initcall
為了方便,我們直接用module_init 。
Makefile文件:
左右滑動查看全部代碼>>>
KERN_DIR?=?/home/book/100ask_imx6ull-sdk/Linux-4.9.88
#??-C?表示將當(dāng)前的工作目錄切換到指定目錄中,M?表示模塊源碼目錄,?modules?表示編譯模塊
all:
?make?-C?$(KERN_DIR)?M=`pwd`?modules?
clean:
?make?-C?$(KERN_DIR)?M=`pwd`?modules?clean
?rm?-rf?modules.order
#?obj-m?表示將?proc_test.c?這個文件編譯為?proc_test.ko?模塊
obj-m?+=?proc_test.o
編譯:
傳到板子里測試:
可以看到,我們已經(jīng)成功地在proc中留下了一個hello_proc小腳印??梢钥吹?,我們創(chuàng)建的基于/proc下的“驅(qū)動”與創(chuàng)建基于/dev下的真實的設(shè)備驅(qū)動的思路及套路是很相似的。這些都是屬于內(nèi)核的范疇,都是屬于內(nèi)核的東西,內(nèi)核把想給我們能直接使用的東西(文件)都放于/proc、/dev等目錄下,我們在應(yīng)用端就可以很方便地訪問這些文件開發(fā)我們的應(yīng)用。
如果文章中有錯誤,歡迎指出。
碼字不易,如果覺得文章有用,期待你的點贊、在看與轉(zhuǎn)發(fā),給小編更多的動力分享更多的東西。
猜你喜歡
Linux下應(yīng)用開發(fā)基礎(chǔ)
【Linux筆記】LED驅(qū)動實驗(總線設(shè)備驅(qū)動模型)
【Linux筆記】設(shè)備樹實例分析
學(xué)習(xí)STM32的一些經(jīng)驗分享
我的單片機轉(zhuǎn)嵌入式Linux之路
STM32的map文件學(xué)習(xí)筆記
基于RT-Thread的智慧路燈案例實驗分享
C語言、嵌入式中幾個非常實用的宏技巧
1024G 嵌入式資源大放送!包括但不限于C/C++、單片機、Linux等。在公眾號聊天界面回復(fù)1024,即可免費獲?。?/span>
免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺僅提供信息存儲服務(wù)。文章僅代表作者個人觀點,不代表本平臺立場,如有問題,請聯(lián)系我們,謝謝!