?
11.2??字符設備驅(qū)動編程
1.字符設備驅(qū)動編寫流程
設備驅(qū)動程序可以使用模塊的方式動態(tài)加載到內(nèi)核中去。加載模塊的方式與以往的應用程序開發(fā)有很大的不同。以往在開發(fā)應用程序時都有一個main()函數(shù)作為程序的入口點,而在驅(qū)動開發(fā)時卻沒有main()函數(shù),模塊在調(diào)用insmod命令時被加載,此時的入口點是init_module()函數(shù),通常在該函數(shù)中完成設備的注冊。同樣,模塊在調(diào)用rmmod命令時被卸載,此時的入口點是cleanup_module()函數(shù),在該函數(shù)中完成設備的卸載。在設備完成注冊加載之后,用戶的應用程序就可以對該設備進行一定的操作,如open()、read()、write()等,而驅(qū)動程序就是用于實現(xiàn)這些操作,在用戶應用程序調(diào)用相應入口函數(shù)時執(zhí)行相關的操作,init_module()入口點函數(shù)則不需要完成其他如read()、write()之類功能。
上述函數(shù)之間的關系如圖11.3所示。
圖11.3??設備驅(qū)動程序流程圖
2.重要數(shù)據(jù)結(jié)構(gòu)
用戶應用程序調(diào)用設備的一些功能是在設備驅(qū)動程序中定義的,也就是設備驅(qū)動程序的入口點,它是一個在<linux/fs.h>中定義的struct?file_operations結(jié)構(gòu),這是一個內(nèi)核結(jié)構(gòu),不會出現(xiàn)在用戶空間的程序中,它定義了常見文件I/O函數(shù)的入口,如下所示:
struct?file_operations
{
????loff_t?(*llseek)?(struct?file?*,?loff_t,?int);
????ssize_t?(*read)?(struct?file?*filp,?
????????????????????????????char?*buff,?size_t?count,?loff_t?*offp);
????ssize_t?(*write)?(struct?file?*filp,?
???????????????????????????????const?char?*buff,?size_t?count,?loff_t?*offp);
????int?(*readdir)?(struct?file?*,?void?*,?filldir_t);
????unsigned?int?(*poll)?(struct?file?*,?struct?poll_table_struct?*);
????int?(*ioctl)?(struct?inode?*,?
????????????????struct?file?*,?unsigned?int,?unsigned?long);
????int?(*mmap)?(struct?file?*,?struct?vm_area_struct?*);
????int?(*open)?(struct?inode?*,?struct?file?*);
????int?(*flush)?(struct?file?*);
????int?(*release)?(struct?inode?*,?struct?file?*);
????int?(*fsync)?(struct?file?*,?struct?dentry?*);
????int?(*fasync)?(int,?struct?file?*,?int);
????int?(*check_media_change)?(kdev_t?dev);
????int?(*revalidate)?(kdev_t?dev);
????int?(*lock)?(struct?file?*,?int,?struct?file_lock?*);
};
這里定義的很多函數(shù)是否跟第6章中的文件I/O系統(tǒng)調(diào)用類似?其實當時的系統(tǒng)調(diào)用函數(shù)通過內(nèi)核,最終調(diào)用對應的struct?file_operations結(jié)構(gòu)的接口函數(shù)(例如,open()文件操作是通過調(diào)用對應文件的file_operations結(jié)構(gòu)的open函數(shù)接口而被實現(xiàn))。當然,每個設備的驅(qū)動程序不一定要實現(xiàn)其中所有的函數(shù)操作,若不需要定義實現(xiàn)時,則只需將其設為NULL即可。
struct?inode結(jié)構(gòu)提供了關于設備文件/dev/driver(假設此設備名為driver)的信息,struct?file結(jié)構(gòu)提供關于被打開的文件信息,主要用于與文件系統(tǒng)對應的設備驅(qū)動程序使用。struct?file結(jié)構(gòu)較為重要,這里列出了它的定義:
struct?file?
{
????mode_t?f_mode;/*標識文件是否可讀或可寫,F(xiàn)MODE_READ或FMODE_WRITE*/
????dev_t?f_rdev;?/*?用于/dev/tty?*/
????off_t?f_pos;?/*?當前文件位移?*/
????unsigned?short?f_flags;?/*?文件標志,如O_RDONLY、O_NONBLOCK和O_SYNC?*/
????unsigned?short?f_count;?/*?打開的文件數(shù)目?*/
????unsigned?short?f_reada;
????struct?inode?*f_inode;?/*指向inode的結(jié)構(gòu)指針?*/
????struct?file_operations?*f_op;/*?文件索引指針?*/
};
?
3.設備驅(qū)動程序主要組成
(1)早期版本的字符設備注冊。
早期版本的設備注冊使用函數(shù)register_chrdev(),調(diào)用該函數(shù)后就可以向系統(tǒng)申請主設備號,如果register_chrdev()操作成功,設備名就會出現(xiàn)在/proc/devices文件里。在關閉設備時,通常需要解除原先的設備注冊,此時可使用函數(shù)unregister_chrdev(),此后該設備就會從/proc/devices里消失。其中主設備號和次設備號不能大于255。
當前不少的字符設備驅(qū)動代碼仍然使用這些早期版本的函數(shù)接口,但在未來內(nèi)核的代碼中,將不會出現(xiàn)這種編程接口機制。因此應該盡量使用后面講述的編程機制。
register_chrdev()函數(shù)格式如表11.1所示。
表11.1 register_chrdev()函數(shù)語法要點
所需頭文件 |
#include?<linux/fs.h> |
函數(shù)原型 |
int?register_chrdev(unsigned?int?major,?const?char?*name,struct?file_operations?*fops) |
函數(shù)傳入值 |
major:設備驅(qū)動程序向系統(tǒng)申請的主設備號,如果為0則系統(tǒng)為此驅(qū)動程序動態(tài)地分配一個主設備號 |
name:設備名 |
|
fops:對各個調(diào)用的入口點 |
|
函數(shù)返回值 |
成功:如果是動態(tài)分配主設備號,此返回所分配的主設備號。且設備名就會出現(xiàn)在/proc/devices文件里 |
出錯:-1 |
unregister_chrdev()函數(shù)格式如下表11.2所示:
表11.2 unregister_chrdev()函數(shù)語法要點
所需頭文件 |
#include?<linux/fs.h> |
函數(shù)原型 |
int?unregister_chrdev(unsigned?int?major,?const?char?*name) |
函數(shù)傳入值 |
major:設備的主設備號,必須和注冊時的主設備號相同 |
name:設備名 |
|
函數(shù)返回值 |
成功:0,且設備名從/proc/devices文件里消失 |
出錯:-1 |
(2)設備號相關函數(shù)。
在前面已經(jīng)提到設備號有主設備號和次設備號,其中主設備號表示設備類型,對應于確定的驅(qū)動程序,具備相同主設備號的設備之間共用同一個驅(qū)動程序,而用次設備號來標識具體物理設備。因此在創(chuàng)建字符設備之前,必須先獲得設備的編號(可能需要分配多個設備號)。
在Linux?2.6的版本中,用dev_t類型來描述設備號(dev_t是32位數(shù)值類型,其中高12位表示主設備號,低20位表示次設備號)。用兩個宏MAJOR和MINOR分別獲得dev_t設備號的主設備號和次設備號,而且用MKDEV宏來實現(xiàn)逆過程,即組合主設備號和次設備號而獲得dev_t類型設備號。
分配設備號有靜態(tài)和動態(tài)的兩種方法。靜態(tài)分配(register_chrdev_region()函數(shù))是指在事先知道設備主設備號的情況下,通過參數(shù)函數(shù)指定第一個設備號(它的次設備號通常為0)而向系統(tǒng)申請分配一定數(shù)目的設備號。動態(tài)分配(alloc_chrdev_region())是指通過參數(shù)僅設置第一個次設備號(通常為0,事先不會知道主設備號)和要分配的設備數(shù)目而系統(tǒng)動態(tài)分配所需的設備號。
通過unregister_chrdev_region()函數(shù)釋放已分配的(無論是靜態(tài)的還是動態(tài)的)設備號。
?
它們的函數(shù)格式如表11.3所示。
表11.3 設備號分配與釋放函數(shù)語法要點
所需頭文件 |
#include?<linux/fs.h> |
函數(shù)原型 |
int?register_chrdev_region?(dev_t?first,?unsigned?int?count,?char?*name) int?alloc_chrdev_region?(dev_t?*dev,?unsigned?int?firstminor,?unsigned?int?count,?char?*name) void?unregister_chrdev_region?(dev_t?first,?unsigned?int?count) |
函數(shù)傳入值 |
first:要分配的設備號的初始值 count:要分配(釋放)的設備號數(shù)目 name:要申請設備號的設備名稱(在/proc/devices和sysfs中顯示) dev:動態(tài)分配的第一個設備號 |
函數(shù)返回值 |
成功:0(只限于兩種注冊函數(shù)) |
出錯:-1(只限于兩種注冊函數(shù)) |
(3)最新版本的字符設備注冊。
在獲得了系統(tǒng)分配的設備號之后,通過注冊設備才能實現(xiàn)設備號和驅(qū)動程序之間的關聯(lián)。這里講解2.6內(nèi)核中的字符設備的注冊和注銷過程。
在Linux內(nèi)核中使用struct?cdev結(jié)構(gòu)來描述字符設備,我們在驅(qū)動程序中必須將已分配到的設備號以及設備操作接口(即為struct?file_operations結(jié)構(gòu))賦予struct?cdev結(jié)構(gòu)變量。首先使用cdev_alloc()函數(shù)向系統(tǒng)申請分配struct?cdev結(jié)構(gòu),再用cdev_init()函數(shù)初始化已分配到的結(jié)構(gòu)并與file_operations結(jié)構(gòu)關聯(lián)起來。最后調(diào)用cdev_add()函數(shù)將設備號與struct?cdev結(jié)構(gòu)進行關聯(lián)并向內(nèi)核正式報告新設備的注冊,這樣新設備可以被用起來了。
如果要從系統(tǒng)中刪除一個設備,則要調(diào)用cdev_del()函數(shù)。具體函數(shù)格式如表11.4所示。
表11.4 最新版本的字符設備注冊
所需頭文件 |
#include?<linux/cdev.h> |
函數(shù)原型 |
sturct?cdev?*cdev_alloc(void) void?cdev_init(struct?cdev?*cdev,?struct?file_operations?*fops) int?cdev_add?(struct?cdev?*cdev,?dev_t?num,?unsigned?int?count) void?cdev_del(struct?cdev?*dev) |
函數(shù)傳入值 |
cdev:需要初始化/注冊/刪除的struct?cdev結(jié)構(gòu) fops:該字符設備的file_operations結(jié)構(gòu) num:系統(tǒng)給該設備分配的第一個設備號 count:該設備對應的設備號數(shù)量 |
函數(shù)返回值 |
成功: cdev_alloc:返回分配到的struct?cdev結(jié)構(gòu)指針 cdev_add:返回0 |
出錯: cdev_alloc:返回NULL cdev_add:返回?-1 |
2.6內(nèi)核仍然保留早期版本的register_chrdev()等字符設備相關函數(shù),其實從內(nèi)核代碼中可以發(fā)現(xiàn),在register_chrdev()函數(shù)的實現(xiàn)中用到cdev_alloc()和cdev_add()函數(shù),而在unregister_chrdev()函數(shù)的實現(xiàn)中調(diào)用cdev_del()函數(shù)。因此很多代碼仍然使用早期版本接口,但這種機制將來會從內(nèi)核中消失。
前面已經(jīng)提到字符設備的實際操作在struct?file_operations結(jié)構(gòu)的一組函數(shù)中定義,并在驅(qū)動程序中需要與字符設備結(jié)構(gòu)關聯(lián)起來。下面討論struct?file_operations結(jié)構(gòu)中最主要的成員函數(shù)和它們的用法。
(4)打開設備。
打開設備的函數(shù)接口是open,根據(jù)設備的不同,open函數(shù)接口完成的功能也有所不同,但通常情況下在open函數(shù)接口中要完成如下工作。
n 遞增計數(shù)器,檢查錯誤。
n 如果未初始化,則進行初始化。
n 識別次設備號,如果必要,更新f_op指針。
n 分配并填寫被置于filp->private_data的數(shù)據(jù)結(jié)構(gòu)。
其中遞增計數(shù)器是用于設備計數(shù)的。由于設備在使用時通常會打開多次,也可以由不同的進程所使用,所以若有一進程想要刪除該設備,則必須保證其他設備沒有使用該設備。因此使用計數(shù)器就可以很好地完成這項功能。
這里,實現(xiàn)計數(shù)器操作的是在2.6內(nèi)核早期版本的<linux/module.h>中定義的3個宏,它們在最新版本里早就消失了,在下面列出只是為了幫讀者理解老版本中的驅(qū)動代碼。
n MOD_INC_USE_COUNT:計數(shù)器加1。
n MOD_DEC_USE_COUNT:計數(shù)器減1。
n MOD_IN_USE:計數(shù)器非零時返回真。
另外,當有多個物理設備時,就需要識別次設備號來對各個不同的設備進行不同的操作,在有些驅(qū)動程序中并不需要用到。
注意 |
雖然這是對設備文件執(zhí)行的第一個操作,但卻不是驅(qū)動程序一定要聲明的操作。若這個函數(shù)的入口為NULL,那么設備的打開操作將永遠成功,但系統(tǒng)不會通知驅(qū)動程序。 |
?
(5)釋放設備。
釋放設備的函數(shù)接口是release()。要注意釋放設備和關閉設備是完全不同的。當一個進程釋放設備時,其他進程還能繼續(xù)使用該設備,只是該進程暫時停止對該設備的使用;而當一個進程關閉設備時,其他進程必須重新打開此設備才能使用它。
釋放設備時要完成的工作如下。
n 遞減計數(shù)器MOD_DEC_USE_COUNT(最新版本已經(jīng)不再使用)。
n 釋放打開設備時系統(tǒng)所分配的內(nèi)存空間(包括filp->private_data指向的內(nèi)存空間)。
n 在最后一次釋放設備操作時關閉設備。
(6)讀寫設備。
讀寫設備的主要任務就是把內(nèi)核空間的數(shù)據(jù)復制到用戶空間,或者從用戶空間復制到內(nèi)核空間,也就是將內(nèi)核空間緩沖區(qū)里的數(shù)據(jù)復制到用戶空間的緩沖區(qū)中或者相反。這里首先解釋一個read()和write()函數(shù)的入口函數(shù),如表11.5所示。
表11.5 read、write函數(shù)接口語法要點
所需頭文件 |
#include?<linux/fs.h> |
函數(shù)原型 |
ssize_t?(*read)?(struct?file?*filp,?char?*buff,?size_t?count,?loff_t?*offp) |
函數(shù)傳入值 |
filp:文件指針 |
buff:指向用戶緩沖區(qū) |
|
count:傳入的數(shù)據(jù)長度 |
|
offp:用戶在文件中的位置 |
|
函數(shù)返回值 |
成功:寫入的數(shù)據(jù)長度 |
雖然這個過程看起來很簡單,但是內(nèi)核空間地址和應用空間地址是有很大區(qū)別的,其中一個區(qū)別是用戶空間的內(nèi)存是可以被換出的,因此可能會出現(xiàn)頁面失效等情況。所以不能使用諸如memcpy()之類的函數(shù)來完成這樣的操作。在這里要使用copy_to_user()或copy_from_user()等函數(shù),它們是用來實現(xiàn)用戶空間和內(nèi)核空間的數(shù)據(jù)交換的。
copy_to_user()和copy_from_user()的格式如表11.6所示。
表11.6 copy_to_user()/copy_from_user()函數(shù)語法要點
所需頭文件 |
#include?<asm/uaccess.h> |
函數(shù)原型 |
unsigned?long?copy_to_user(void?*to,?const?void?*from,?unsigned?long?count) |
函數(shù)傳入值 |
to:數(shù)據(jù)目的緩沖區(qū) |
from:數(shù)據(jù)源緩沖區(qū) |
|
count:數(shù)據(jù)長度 |
|
函數(shù)返回值 |
成功:寫入的數(shù)據(jù)長度 |
要注意,這兩個函數(shù)不僅實現(xiàn)了用戶空間和內(nèi)核空間的數(shù)據(jù)轉(zhuǎn)換,而且還會檢查用戶空間指針的有效性。如果指針無效,那么就不進行復制。
(7)ioctl。
大部分設備除了讀寫操作,還需要硬件配置和控制(例如,設置串口設備的波特率)等很多其他操作。在字符設備驅(qū)動中ioctl函數(shù)接口給用戶提供對設備的非讀寫操作機制。
ioctl函數(shù)接口的具體格式如表11.7所示。
表11.7 ioctl函數(shù)接口語法要點
所需頭文件 |
#include?<linux/fs.h> |
函數(shù)原型 |
int(*ioctl)(struct?inode*?inode,?struct?file*?filp,?unsigned?int?cmd,?unsigned?long?arg) |
函數(shù)傳入值 |
inode:文件的內(nèi)核內(nèi)部結(jié)構(gòu)指針 |
filp:被打開的文件描述符 |
|
cmd:命令類型 |
|
arg:命令相關參數(shù) |
下面列出其他在驅(qū)動程序中常用的內(nèi)核函數(shù)。
(8)獲取內(nèi)存。
在應用程序中獲取內(nèi)存通常使用函數(shù)malloc(),但在設備驅(qū)動程序中動態(tài)開辟內(nèi)存可以以字節(jié)或頁面為單位。其中,以字節(jié)為單位分配內(nèi)存的函數(shù)有kmalloc(),注意的是,kmalloc()函數(shù)返回的是物理地址,而malloc()等返回的是線性虛擬地址,因此在驅(qū)動程序中不能使用malloc()函數(shù)。與malloc()不同,kmalloc()申請空間有大小限制。長度是2的整次方,并且不會對所獲取的內(nèi)存空間清零。
以頁為單位分配內(nèi)存的函數(shù)如下所示。
n get_zeroed_page():獲得一個已清零頁面。
n get_free_page():獲得一個或幾個連續(xù)頁面。
n get_dma_pages():獲得用于DMA傳輸?shù)捻撁妗?/p>
與之相對應的釋放內(nèi)存用也有kfree()或free_page函數(shù)族。
表11.8給出了kmalloc()函數(shù)的語法格式。
表11.8 kmalloc()函數(shù)語法要點
所需頭文件 |
#include?<linux/malloc.h> |
|
函數(shù)原型 |
void?*kmalloc(unsigned?int?len,int?flags) |
|
函數(shù)傳入值 |
len:希望申請的字節(jié)數(shù) |
|
flags |
GFP_KERNEL:內(nèi)核內(nèi)存的通常分配方法,可能引起睡眠 |
|
GFP_BUFFER:用于管理緩沖區(qū)高速緩存 |
||
GFP_ATOMIC:為中斷處理程序或其他運行于進程上下文之外的代碼分配內(nèi)存,且不會引起睡眠 |
||
GFP_USER:用戶分配內(nèi)存,可能引起睡眠 |
||
GFP_HIGHUSER:優(yōu)先高端內(nèi)存分配 |
||
__GFP_DMA:DMA數(shù)據(jù)傳輸請求內(nèi)存 |
||
__GFP_HIGHMEN:請求高端內(nèi)存 |
||
函數(shù)返回值 |
成功:寫入的數(shù)據(jù)長度 |
?
表11.9給出了kfree()函數(shù)的語法格式。
表11.9 kfree()函數(shù)語法要點
所需頭文件 |
#include?<linux/malloc.h> |
函數(shù)原型 |
void?kfree(void?*?obj) |
函數(shù)傳入值 |
obj:要釋放的內(nèi)存指針 |
函數(shù)返回值 |
成功:寫入的數(shù)據(jù)長度 |
表11.10給出了以頁為單位的分配函數(shù)get_free_?page類函數(shù)的語法格式。
表11.10 get_free_?page類函數(shù)語法要點
所需頭文件 |
#include?<linux/malloc.h> |
函數(shù)原型 |
unsigned?long?get_zeroed_page(int?flags) |
函數(shù)傳入值 |
flags:同kmalloc() |
order:要請求的頁面數(shù),以2為底的對數(shù) |
|
函數(shù)返回值 |
成功:返回指向新分配的頁面的指針 |
表11.11給出了基于頁的內(nèi)存釋放函數(shù)free_?page族函數(shù)的語法格式。
表11.11 free_page類函數(shù)語法要點
所需頭文件 |
#include?<linux/malloc.h> |
函數(shù)原型 |
unsigned?long?free_page(unsigned?long?addr) |
函數(shù)傳入值 |
addr:要釋放的內(nèi)存起始地址 |
order:要請求的頁面數(shù),以2為底的對數(shù) |
|
函數(shù)返回值 |
成功:寫入的數(shù)據(jù)長度 |
(9)打印信息。
就如同在編寫用戶空間的應用程序,打印信息有時是很好的調(diào)試手段,也是在代碼中很常用的組成部分。但是與用戶空間不同,在內(nèi)核空間要用函數(shù)printk()而不能用平常的函數(shù)printf()。printk()和printf()很類似,都可以按照一定的格式打印消息,所不同的是,printk()還可以定義打印消息的優(yōu)先級。
表11.12給出了printk()函數(shù)的語法格式。
表11.12 printk類函數(shù)語法要點
所需頭文件 |
#include?<linux/kernel> |
|
函數(shù)原型 |
int?printk(const?char?*?fmt,?…) |
|
函數(shù)傳入值 |
fmt: |
KERN_EMERG:緊急時間消息 |
KERN_ALERT:需要立即采取動作的情況 |
||
KERN_CRIT:臨界狀態(tài),通常涉及嚴重的硬件或軟件操作失敗 |
||
KERN_ERR:錯誤報告 |
||
KERN_WARNING:對可能出現(xiàn)的問題提出警告 |
||
KERN_NOTICE:有必要進行提示的正常情況 |
||
KERN_INFO:提示性信息 |
||
KERN_DEBUG:調(diào)試信息 |
||
…:與printf()相同 |
||
函數(shù)返回值 |
成功:0 |
這些不同優(yōu)先級的信息輸出到系統(tǒng)日志文件(例如:“/var/log/messages”),有時也可以輸出到虛擬控制臺上。其中,對輸出給控制臺的信息有一個特定的優(yōu)先級console_loglevel。只有打印信息的優(yōu)先級小于這個整數(shù)值,信息才能被輸出到虛擬控制臺上,否則,信息僅僅被寫入到系統(tǒng)日志文件中。若不加任何優(yōu)先級選項,則消息默認輸出到系統(tǒng)日志文件中。
注意 |
要開啟klogd和syslogd服務,消息才能正常輸出。 |
?
4.proc文件系統(tǒng)
/proc文件系統(tǒng)是一個偽文件系統(tǒng),它是一種內(nèi)核和內(nèi)核模塊用來向進程發(fā)送信息的機制。這個偽文件系統(tǒng)讓用戶可以和內(nèi)核內(nèi)部數(shù)據(jù)結(jié)構(gòu)進行交互,獲取有關系統(tǒng)和進程的有用信息,在運行時通過改變內(nèi)核參數(shù)來改變設置。與其他文件系統(tǒng)不同,/proc存在于內(nèi)存之中而不是在硬盤上。讀者可以通過“l(fā)s”查看/proc文件系統(tǒng)的內(nèi)容。
表11.13列出了/proc文件系統(tǒng)的主要目錄內(nèi)容。
表11.13 /proc文件系統(tǒng)主要目錄內(nèi)容
目?錄?名?稱 |
目?錄?內(nèi)?容 |
目?錄?名?稱 |
目?錄?內(nèi)?容 |
|
apm |
高級電源管理信息 |
locks |
內(nèi)核鎖 |
|
cmdline |
內(nèi)核命令行 |
meminfo |
內(nèi)存信息 |
|
cpuinfo |
CPU相關信息 |
misc |
雜項 |
|
devices |
設備信息(塊設備/字符設備) |
modules |
加載模塊列表 |
|
dma |
使用的DMA通道信息 |
mounts |
加載的文件系統(tǒng) |
|
filesystems |
支持的文件系統(tǒng)信息 |
partitions |
系統(tǒng)識別的分區(qū)表 |
|
interrupts |
中斷的使用信息 |
rtc |
||
ioports |
I/O端口的使用信息 |
stat |
全面統(tǒng)計狀態(tài)表 |
|
kcore |
內(nèi)核映像 |
swaps |
對換空間的利用情況 |
|
kmsg |
內(nèi)核消息 |
version |
內(nèi)核版本 |
|
ksyms |
內(nèi)核符號表 |
uptime |
系統(tǒng)正常運行時間 |
|
loadavg |
… |
… |
?
除此之外,還有一些是以數(shù)字命名的目錄,它們是進程目錄。系統(tǒng)中當前運行的每一個進程都有對應的一個目錄在/proc下,以進程的PID號為目錄名,它們是讀取進程信息的接口。進程目錄的結(jié)構(gòu)如表11.14所示。
表11.14 /proc中進程目錄結(jié)構(gòu)
目?錄?名?稱 |
目?錄?內(nèi)?容 |
目?錄?名?稱 |
目?錄?內(nèi)?容 |
|
cmdline |
命令行參數(shù) |
cwd |
當前工作目錄的鏈接 |
|
environ |
環(huán)境變量值 |
exe |
指向該進程的執(zhí)行命令文件 |
|
fd |
一個包含所有文件描述符的目錄 |
maps |
內(nèi)存映像 |
|
mem |
進程的內(nèi)存被利用情況 |
statm |
進程內(nèi)存狀態(tài)信息 |
|
stat |
進程狀態(tài) |
root |
鏈接此進程的root目錄 |
|
status |
進程當前狀態(tài),以可讀的方式顯示出來 |
… |
… |
用戶可以使用cat命令來查看其中的內(nèi)容。
可以看到,/proc文件系統(tǒng)體現(xiàn)了內(nèi)核及進程運行的內(nèi)容,在加載模塊成功后,讀者可以通過查看/proc/device文件獲得相關設備的主設備號。