目錄:
概述
◆ /proc/目錄簡介
◆ procfs的實作
後記
————————————————————————–
概述:
程序檔案系統 — procfs — 允許像管理檔案那樣直接管理核心程序。
程序檔案系統,procfs,是一個僞檔案系統,提供了核心程序表的檔案系統接口,
Jim Mauro 在這裡概要介紹了procfs。
翻譯本文的目的在于編寫64-bit下的SLKM,歡迎對此感興趣的朋友交流。
————————————————————————–
◆ /proc/目錄簡介
程序檔案系統,procfs,是一個僞檔案系統,它允許對一些非傳統意義上的檔案
通過标準檔案I/O接口進行通路。procfs将Solaris核心程序架構進行了抽象,比如當
前系統中所有運作着的程序會在/proc/目錄下有所展現。系統中每個程序對應/proc/
目錄下的一個子目錄,子目錄名即相應程序号(PID),所有程序号子目錄構成了
/proc/目錄的全部内容。
許多提供程序資料和控制點的核心資料結構在/proc/ /子目錄下有相應反映,
比如,多線程程序中每個LWP的相關資料和控制結構展現在/proc/ /lwp/
中。 /proc/目錄下的對象不是真實磁盤檔案,這些對象位于核心記憶體中,使用者執行
ls(1)指令顯示/proc/目錄結構時,系統讀取核心記憶體并傳回相應内容。
通過/proc,相對簡便地就可以擷取程序資訊,比如程序執行環境、核心資源利
用率。程序控制和procfs直接相關,procfs最初的設計目的很簡單,就是為編寫調試
器提供一組接口,現在已經有了相當大的改進。
Solaris系統在/usr/proc/bin/目錄下提供了一組工具從/proc中析取程序資訊,
同時可以進行簡單的程序控制。可以參看proc(1)手冊頁。程序狀态指令ps(1)也利用
了procfs接口。
下面列舉可以通過/proc檔案系統擷取的控制和資訊資料,關于這些檔案的詳細
資訊參看proc(4)手冊頁。
/proc — procfs的根目錄
/proc/
— 某一确定程序的根目錄,程序PID正是子目錄名
/proc/
/as — 程序位址空間,即struct proc結構中p_as成員。換句話說,進
程位址空間以/proc/
/as檔案的形式展現出來,通過這個僞檔案系統接口可以訪
問相應程序位址空間。
struct as * p_as;
# ls -l /proc/53/as
-rw——- 1 root root 1458176 2月 8 17:34 /proc/53/as
struct proc結構定義在/usr/include/sys/proc.h檔案中。
/proc/
/ctl — 一個程序控制檔案。可以隻寫打開該檔案,然後給相應程序發
送控制資訊。可以停止、啟動程序,設定程序停止于某一特殊事件。這示範了procfs
的強大和便捷。程序控制、事件跟蹤可以通過打開相應程序的控制檔案完成,隻需要
寫入期待行為的控制資訊。參看proc(4)手冊了解控制資訊和控制函數的詳細介紹。
/proc/
/status — 程序狀态資訊。對應/usr/include/sys/procfs.h檔案裡定
義的struct pstatus結構。proc(4)手冊頁裡也有描述。這個結構中有一個成員
lwpstatus_t pr_lwp;
該成員對應一個有代表性的LWP(輕量級程序)。單線程程序隻有一個LWP,很容易標明
這個有代表性的LWP。那些多線程程序通常有多個LWPs,一個核心函數周遊目前程序
的所有LWPs,根據他們的狀态選取這個有代表性的LWP。首先選取正在執行中的LWP,
如果不存在這樣的LWP,按照可運作、休眠、停止的順序選取LWP。
/proc/
/lstatus — lwpstatus結構數組,程序中每個LWP對應一個lwpstatus結
構。struct lwpstatus結構定義在/usr/include/sys/procfs.h檔案中。
/proc/
/psinfo — 類似ps(1)指令提供的程序資訊。對應struct psinfo結構,
類似struct pstatus結構,struct psinfo結構中有一個成員
lwpsinfo_t pr_lwp;
該成員的對應一個有代表性的LWP。
/proc/
/lpsinfo — lwpsinfo結構數組,程序中每個LWP對應一個lwpsinfo結構
/proc/
/map — 位址空間映射資訊,可以用pmap(1)指令顯示這些資料資訊。
/proc/
/rmap — 程序中保留位址空間段。用pmap -r指令顯示這些資料資訊。
/proc/
/xmap — 擴充位址空間映射資訊。用pmap -x指令顯示這些資料資訊。
/proc/
/cred — 程序身份驗證資訊,對應/usr/include/sys/procfs.h檔案中
定義的struct prcred結構。
/proc/
/sigact — sigaction結構數組,描述和本程序相關的所有信号設定。
struct sigaction結構定義在/usr/include/sys/signal.h檔案中。
/proc/
/auxv — auxv_t結構數組,包含程序執行時傳遞給動态連結器的初始值。
auxv_t結構定義在/usr/include/sys/auxv.h檔案中。
/proc/
/ldt — 局部描述符表(LDT),僅存于Intel x86架構。
/proc/
/usage — 程序資源使用率的相關資料,對應struct prusage結構,該
結構定義在/usr/include/sys/procfs.h檔案中。
/proc/
/lusage — prusage結構數組,對應各個LWP資源利用狀況。
/proc/
/pagedata — 程序位址空間的另外一種表現方式,可以用于跟蹤頁面級
的引用和修改。參看struct prpageheader結構定義。
/proc/
/watch — prwatch結構數組。通過寫控制檔案/proc/
/ctl可以設
置PCWATCH操作,此時建立該檔案。允許監視一個或多個位址空間範圍,當通路這些
被監視頁面時,産生一次陷入。
scz注:這個功能和SoftIce的BPR功能類似,adb支援這種陷入,不知是否利用了
procfs
/proc/
/cwd — 到程序目前工作目錄的符号連結
/proc/
/root — 到程序根目錄的符号連結(和上面那個什麼差別)
/proc/
/fd — 這是一個子目錄,包含程序打開的檔案句柄
/proc/
/fd/nn — 對應程序打開的某個确定的檔案句柄
/proc/
/object — 這是一個子目錄,包含程序相關的可執行檔案以及動态連結
庫。
/proc/
/object/nn — 二進制目标檔案。程序對應的可執行檔案名為a.out,其
餘是程序相關的動态連結庫檔案。
object目錄提供的資訊是程序級的,每個/proc/
/目錄有一個lwp子目錄,提供
了LWP級的資訊:
/proc/
/lwp — 這是一個子目錄,包含程序中所有LWPs的資訊
/proc/
/lwp/ — 這是一個子目錄,包含對應lwpid的LWP資訊
/proc/
/lwp/ /lwpctl — 一個控制檔案,通過它可以在LWP級上針對每
個LWP釋出控制操作
/proc/
/lwp/ /lwpstatus — LWP狀态資訊,對應lwpstatus結構,該結
構定義在/usr/include/sys/procfs.h檔案中
/proc/
/lwp/ /lwpsinfo — 對應lwpsinfo結構,同樣定義在
/usr/include/sys/procfs.h檔案中
/proc/
/lwp/ /lwpusage — LWP資源利用資訊,對應prusage結構
/proc/
/lwp/ /xregs — 這個檔案是處理器架構相關的,某些平台上可
能沒有這個檔案。對于SPARC系統,這個檔案對應/usr/include/sys/procfs_isa.h文
件中定義的prxregset結構。
/proc/
/lwp/ /gwindows — 正常寄存器視窗。這個檔案僅存于SPARC架
構的系統,描述LWP使用的正常寄存器組(硬體上下文的一部分),對應gwindows結構,
該結構定義在/usr/include/sys/regset.h檔案中。
/proc/
/lwp/ /asrs — 輔助寄存器組,僅存于SPARC V9(UltraSPARC)架
構,專為SPARC V9架構定義的一組額外的硬體寄存器,要求sun4u、64-bit核心
(Solaris 7及其後續版本)、64-bit程序。注意,64-bit核心可以運作32-bit程序,
但是32-bit程序沒有這樣一個檔案與之對應。
————————————————————————–
◆ procfs的實作
procfs是通過動态可加載核心子產品的方式實作的。系統啟動時自動加載
/kernel/fs/procfs,/etc/vfstab檔案中存在預設/proc入口,系統啟動過程中/proc
将被mount上來。mount過程中将調用procfs的prinit()和prmount()函數,它們為
procfs初始化vfs(虛拟檔案系統)結構,為根目錄/proc/建立并初始化一個vnode。
vfs結構定義在/usr/include/sys/vfs.h檔案中,vnode結構定義在
/usr/include/sys/vnode.h檔案中。
/proc目錄所涉及的核心記憶體空間絕大部分是動态配置設定的。但是系統支援的最大
程序數(可以通過/etc/system的max_nprocs參數配置)決定了/proc下子目錄插槽數目,
這個是靜态配置設定初始化的。核心變量procdir是一個指向procent結構數組的指針,
每個procent結構對應一個procfs目錄入口,procent結構數組元素數量源自系統啟動
時初始化的v.v_proc變量的值,也就是系統支援的最大程序數。
scz注:在Solaris Kernel Hacking過程中,應該習慣使用下面這兩種指令,很多未
公開核心資料結構在/usr/include下的頭檔案中有相當展現,然後利用nm命
令确認目前核心正在使用這些核心資料結構或者核心函數。
# find /usr/include -name “*” | xargs grep -i “procdir”
# /usr/ccs/bin/nm -x /dev/ksyms | grep -i “|procdir”
[1433] |0×0000104570d0|0×000000000008|OBJT |LOCL |0 |ABS |procdir
# /usr/ccs/bin/nm -x /dev/ksyms | grep -i “|v$”
[8741] |0×00001041e1f4|0×00000000003c|OBJT |GLOB |0 |ABS |v
[6634] |0×00001041e1f4|0×00000000003c|OBJT |GLOB |0 |ABS |v
每個procent結構中pe_proc成員指向對應的proc結構,pe_next成員指向數組的
下一個元素(scz:不但是數組,也形成連結清單)。整個procdir數組由程序PID結構的
pid_prslot成員索引。建立程序時(fork())系統在procdir數組中為之配置設定一個元素,
參看圖1。
————————————————————————–
+——–+ +—->+———+<----procdir(procent結構數組)
| proc |<-----------------------|-----| pe_proc |
| | | | pe_next |–+ 0
| p_pidp |—-> +————+ | +———+ | |
内 +——–+ | pid_prslot |—-+ | pe_proc |<-+ |
| ^ | pid_id | | pe_next |–+ |
核 V | +————+ +———+ | |
+——–+ | pe_proc |<-+ |
進 | proc | | pe_next |–+ |
| | +—->+———+ | |
程 | p_pidp |—-> +————+ | | pe_proc |<-+ |
+——–+ | pid_prslot |—-+ | pe_next |–+ |
表 | ^ | pid_id | +———+ | |
V | +————+ +—–| pe_proc |<-+ |
+——–+ | | pe_next | |
| proc |<-----------------------+ +---------+ |
| | | | |
| p_pidp | | | V
+——–+ | | v.v_proc
圖1. 程序PID結構的pid_prslot成員用于索引procdir數組
————————————————————————–
下面是在我的Sun工作站上找到的相應頭檔案内容:
/usr/include/sys/proc.h
struct proc
{
struct proc * p_next;
struct proc * p_prev;
struct pid * p_pidp;
struct vnode * p_trace;
struct vnode * p_plist;
}
struct pid
{
unsigned int pid_prslot :24;
pid_t pid_id;
};
procfs核心代碼描述了procfs目錄入口的精确格式,這個格式以典型的磁盤檔案
系統為模闆,核心中每個入口對應一個目錄名。目錄入口包含在目錄中的偏移(第幾
個入口)、長度域以及inode号。/proc下檔案對象的inode号源自檔案對象類型和程序
号。注意,/proc目錄入口不會出現在目錄名搜尋緩存中,根據定義,/proc目錄入口
總是位于實體記憶體中(不會被扇出?)。
因為procfs是一個檔案系統,它建構在虛拟檔案系統VFS和Solaris vnode構架之
上,檔案系統執行個體作為一個VFS對象存在,其中的檔案通過vnode描述。procfs建立
VFS和vnode結構,通過它們可以針對procfs進行檔案系統相關操作,比如mount和
umount,可以針對/proc目錄及檔案對象進行open、read和write操作。
除了VFS和vnode結構,procfs實作中主要定義了兩個資料結構用于描述/proc目
錄下檔案對象。第一個是prnode結構(/usr/include/sys/proc/prdata.h),描述那些
最終連結到vnode的檔案系統相關資料。核心UFS實作定義了一個inode做為描述一個
UFS檔案的檔案系統相關資料結構,類似的,核心procfs實作定義了一個prnode描述
一個procfs檔案。/proc目錄下的每個檔案有一個vnode和prnode對應。
第二個是prcommon結構,遍布整個/proc目錄結構,換句話說,每個/proc/
和/proc/
/lwp/ 目錄本身都對應一個prcommon結構,但是這些目錄下的
檔案對象并沒有對應一個prcommon結構,因為通路這些檔案對象時必然與一個确定的
程序或者LWP相關。prcommon結構對這些目錄下的檔案對象共性進行抽象。prnode和
prcommon結構定義在/usr/include/sys/proc/prdata.h檔案中。參看圖2。
————————————————————————–
/proc
/
/ prnode prcommon
+–+ +–+
+———————————+ | | | |
| | +–+ +–+
| |
| +——————————————————+
| prnode prcommon | prnode prnode prnode per-process |
lwp +–+ +–+ | as +–+ cred +–+ psinfo +–+ … file objects |
/ | | | | | | | | | | | |
/ +–+ +–+ | +–+ +–+ +–+ |
/ prnode prcommon +——————————————————+
+–+ +–+
/ | | | |
/ +–+ +–+
/
+——————————————————————————-+
| prnode prnode prnode prnode per-lwp |
| lwpctl +–+ lwpinfo +–+ lwpstatus +–+ lwpusage +–+ … file objects |
| | | | | | | | | |
| +–+ +–+ +–+ +–+ |
+——————————————————————————-+
圖2. prnode和prcommon結構定義
————————————————————————–
每個程序有自己的主/proc vnode(就是說這個vnode對應/proc/
檔案),程序中
每個LWP有自己的vnode對應/proc/
/lwp/ 檔案,參看圖3。
————————————————————————–
回指到proc結構
<-------------+
prnode prcommon |
+————-+ +->+————-+ +->+———-+ procdir |
| proc | | | pr_next —-|–+ | | prc_slot —->+———+ |
| structure | /proc | | pr_common –|–|-+ +———-+ | pe_proc –+
| +———+ | /
| | pr_files —|–|—————-+ | pe_next |
| | | | vnode | | pr_vnode | | | +———+
一 | | p_trace ————–>+———+ | | | | pe_proc |
| | p_plist | | | | |vnode | | | | | pe_next |
個 | | | | | | |structure| | | | +———+
| +———+ | | | | | | | | | pe_proc |
多 | | +–|-|v_data | | | | | pe_next |
| kthread LWP | /proc | +———+ | | | +———+
線 | +———+ | /
+————-+ | | | pe_proc |
| | | | /lwp/ vnode | | | pe_next |
程 | | t_trace —–+ prnode | | +———+
| | | | | +->+————-+<-+ | | pe_proc |
進 | +———+ | | | | pr_next —-|–+ prcommon | | pe_next |
| | | | | pr_common –|–|—>+———-+| +———+
程 | kthread LWP | | | | pr_files | | | prc_slot || | |
| +———+ | | | | pr_vnode | | +———-+| | |
| | | | +——–>+———+ | | | | |
| | t_trace —–+ | | |vnode | | | |
| | | | | | | |structure| | | |
| +———+ | | | | | | | | +–>+—+ array of
+————-+ | +–|-|v_data | | | | | pointers
| | +———+ | | +—+ to vnodes
| +————-+ | | | for all files
/proc/
/lwp | | +—+ within the
/ vnode | prnode | | | directory
| +->+————-+<-+ .....
| | | pr_next | prcommon | |
| | | pr_common –|——>+———-+ +—+
| | | pr_files | | prc_slot | | |
| | | pr_vnode | +———-+ +—+
+——–>+———+ |
| | |vnode | |
| | |structure| |
| | | | |
+–|-|v_data | |
| +———+ |
+————-+
圖3. 一個多線程程序所涉及結構之間的關聯
————————————————————————–
下面是在我的Sun工作站上找到的相應頭檔案内容:
/usr/include/sys/proc/prdata.h
typedef struct prnode
{
vnode_t * pr_next;
prcommon_t * pr_common;
prcommon_t * pr_pcommon;
vnode_t ** pr_files;
vnode_t pr_vnode;
} prnode_t;
typedef struct prcommon
{
int prc_slot;
} prcommon_t;
/usr/include/sys/vnode.h
typedef struct vnode
{
caddr_t v_data;
} vnode_t;
/usr/include/sys/thread.h
typedef struct _kthread
{
struct vnode * t_trace;
} kthread_t;
圖3示範了打開一個procfs檔案進行讀寫時部分相關procfs資料結構和它們之間
的關聯。注意到一個程序相關的所有vnodes通過prnode結構的pr_next成員連結起來。
當引用一個procfs目錄以及目錄下的檔案對象時,核心動态建立必要的資料結構支援
這種檔案I/O請求,同時也是動态銷毀相關資料結構。無論什麼時候針對procfs目錄
或檔案做open(2)請求或者列舉procfs目錄或檔案,它們似乎總是在那裡,類似冰箱
裡的燈,當你打開冰箱的時候它總是亮着的,但是關上冰箱門之後它事實上關閉着。
通過procfs所能通路到的資料顯然總是位于核心proc結構以及其他一些資料結構
中,這些資料結構共同構成了Solaris核心中完整的程序模型。應用程式通過procfs
可以擷取程序資料,控制程序執行。這樣做的好處是隐藏了核心程序模型的底層細節,
以一種相對普通的方式析取感興趣的資料、進行程序控制。請求發生時建立這種動态
抽象,隻要針對特定檔案的通路存在,這種動态抽象就一直保持着。
針對procfs的檔案I/O操作遵循傳統方式,打開檔案擷取檔案句柄,讀寫,關閉
檔案句柄。通過vnode開關表機制進行procfs相關vnode操作時,建立并初始化prnode
和prcommon結構,這通常是應用程式檔案請求導緻的結果。實際的procfs vnode操作
由相關的查找、讀寫函數處理/proc目錄下的對象。
procfs周遊和讀取請求采用一組函數指針實作,這組函數實作procfs檔案類型相
關操作。檔案類型分兩層維護。在vnode的v_type成員中,procfs檔案類型定義成
VPROC。而prnode結構的pr_type成員定義了這個特定procfs檔案的類型。procfs檔案
類型直接描述了/proc目錄結構,參看/usr/include/sys/proc/prdata.h檔案。
typedef enum prnodetype
{
PR_PROCDIR,
PR_PIDDIR,
PR_AS,
PR_CTL,
PR_STATUS,
PR_LSTATUS,
PR_PSINFO,
PR_LPSINFO,
PR_MAP,
} prnodetype_t;
打開一個procfs檔案時的基本流程如圖4所示。
————————————————————————–
open( “/proc/
/ “, O_RDONLY );
| Specific procfs directory object
代| vn_open() lookup functions are invoked
| through the pr_lookup_function[]
碼| +—-> lookupxxx() array
| | VOP_LOOKUP() -> prlookup()
流| | index based on type
| | pr_lookup_function +———————–+
程| | | pr_lookup_piddir() |/
| | Construct full path name, +———————–+ /
| | looking up each element | pr_lookup_lwpdir() | /
| | in the path. +———————–+ prgetnode()
| | | pr_lookup_objectdir() | /
| | +———————–+ /
| | | | |/
| | …… | ……
| | |
| +——————————————-+
| VOP_OPEN() -> propen()
V
圖4. 打開一個procfs檔案時的基本流程
————————————————————————–
圖4中流程從應用程式開始,針對一個procfs檔案做open(2)系統調用。進入
vnode核心層(vn_open()),完成一系列查找以建構目标/proc檔案的完整路徑名。通
過vnode層的宏進入檔案系統相關操作。在上面的圖例中,VOP_LOOKUP()解析成
procfs的pr_lookup()函數。pr_lookup()完成通路權限檢查并根據目錄檔案類型調用
相應的procfs函數,比如pr_lookup_piddir()針對/proc/
目錄進行查找工作。
每個pr_lookup_xxx()目錄查找函數完成某些目錄類型相關的工作,然後調用
prgetnode()擷取prnode。
prgetnode()為/proc檔案建立prnode(其中内嵌了vnode),并初始化prnode和
vnode結構的某些成員。對于/proc/
和/proc/
/lwp/ ,還會建立
prcommon結構,挂接到prnode結構上,并部分初始化。注意,對于/proc下的目錄文
件,為了正确反映目錄檔案類型,vnode類型從VPROC(初始設定)改變成VDIR,表示這
是一個procfs目錄檔案。
一旦完整路徑名建構完畢,通過VOP_OPEN()宏進入檔案系統相關的open()函數。
procfs的propen()函數完成prnode和vnode結構的其餘初始化以及針對特定檔案類型
的通路測試工作。一旦propen()完成,控制傳回到vn_open()。最終一個代表procfs
檔案的檔案句柄傳回給主調者。
讀取一個procfs資料檔案(和目錄檔案相對)類型打開流程,read()系統調用最終
進入procfs的prread()函數。procfs實作為每個可用檔案對象(不同的資料結構)定義
了一個資料檔案對象相關的讀函數,比如pr_read_psinfo()、pr_read_pstatus()、
pr_read_lwpsinfo()等等。這些函數指針構成一個數組,以檔案類型做下标進行索引,
prread()最終調用了它們。整個流程類似lookup操作。
Solaris 7 的procfs實作是基于64-bit核心的,但是同時支援32-bit和64-bit應
用,在/proc層次結構上提供了32-bit版本的可用資料檔案。在64-bit Solaris 7内
核中,描述每個/proc檔案對象内容的資料結構同時擁有32-bit版本和64-bit版本,
比如lwpstatus和lwpstatus32、psinfo和psinfo32等等。針對每個32-bit版本的結構
定義,相應pr_read_xxx()函數做了支援32-bit資料模式的編碼。
procfs使用者并不會意識到64-bit核心中多種資料模式實作。調用到prread()時,
它會檢查主調者使用的資料模式,并激活相應資料模式的函數。這裡有一個例外,讀
取/proc/
/as(位址空間)檔案時,主調者必須擁有與/proc/
/as檔案一樣的
資料模式,換句話說,64-bit核心中32-bit應用程式可以讀取另外一個32-bit程序的
AS(位址空間)檔案,但是不能讀取另外一個64-bit程序的AS檔案。
scz注:我覺得這裡倒不如說,/proc/
/as本身是擁有單一資料模式的,要麼
32-bit,要麼64-bit,不可得兼。而其他/proc資料檔案對象可能同時支援兩
種資料模式。
pr_read_xxxx()函數從核心裡讀取相關資料,然後寫入相應的procfs資料結構,
最終傳回給主調者。例如,pr_read_psinfo()從目标程序的proc結構、cred結構和as
結構讀取資料,寫入psinfo結構中相應成員。通路核心資料時靠proc結構的p_lockp
成員确定的互斥鎖進行同步,這樣確定每次隻有一個客戶線程能夠通路per-process
或per-lwp核心資料。
很少需要寫通路procfs檔案。姑且不考慮寫目錄建立資料檔案,典型的寫操作就
是為了發出某些控制消息寫程序或LWP控制檔案。控制消息(參看proc(1))包括stop/
start消息,信号跟蹤和控制,故障管理,執行控制(比如進入/退出某個系統調用時
暫停)以及位址空間通路監視。
迄今為止,我們讨論的都是用标準系統調用對procfs檔案進行I/O操作,目前從
普通應用級程式員程式設計通路/proc檔案來說這是唯一的辦法。然而另外有一組特定針
對procfs的通路接口,proc(1)中介紹的/usr/proc/bin/下的指令(随Solaris分發)
使用了這組接口。這組接口位于libproc.so動态連結庫,屬于未公開的接口。Sun公
司正在着手準備關于這組接口的文檔,做為标準Solaris APIs提供出來。圖5展示了
以前讨論過的核心中procfs子產品與各層之間的接口關系。
————————————————————————–
+———————+————————–+
| custom /proc code | /usr/proc/bin/ |
+——————+ | +———————–+
| stdio interfaces | | |libproc|
+——————+–+–+————–+|
| system calls || user
—————————————————————–
+—————————————+| kernel
| vnode layer ||
+—————————————+——–+
| procfs |
+————————————————+
圖5. procfs子產品與各層之間的接口關系
————————————————————————–
圖5示範了多條到達procfs核心例程的路徑。開發者通常通過系統調用進入vnode
層,這是前面過介紹的方式。而proc(1)指令更多建構在libproc.so提供的接口上。
為什麼需要這組動态連結庫接口呢,提供一組簡單易用的例程用于應用程式開發,減
少直接使用核心機制帶來的複雜性。控制一個程序的執行,尤其是多線程程序,非常
複雜,需要一組真正屬于API層的編碼接口,而不是核心層的編碼接口。
向控制檔案的頭8個位元組(如果是LP64核心,就是頭16個位元組)寫入一個操作碼和
可選的操作數,完成程序控制。寫程序控制檔案的路徑也要經過vnode層,最終調用
了procfs的prwritectl()函數。允許在一次寫調用中向控制檔案寫入多個控制消息(
操作碼和操作數),prwritectl()會将一次寫入的多個控制消息分成獨立的操作碼/操
作數對,順序送出給核心的pr_control()函數,pr_control()函數将設定程序或LWP
相應的标志,以指明控制機制啟動,比如某一事件發生時暫停。控制函數在proc(4)
手冊頁中介紹。
程序/LWP控制的實作與核心中程序/LWP子系統緊密結合,P區、U區、LWP和核心
線程結構中各種域一起協作完成通過procfs進行的程序管理和控制。建立程序控制包
括設定标志和位掩碼字段,用于跟蹤那些導緻程序、線程進入、離開核心的事件,包
括信号、系統調用、故障情形。對應這些事件的進入、離開核心的點定義得比較充分,
為程序狀态改變提供了自然的控制機制。
系統調用、信号和故障分别對應資料類型sysset_t、sigset_t和fltset_t。如果
指定發生某系統調用時暫停,此時尚未從程序讀取提供給該系統調用的參數。如果指
定離開某系統調用時暫停,此時來自系統調用的傳回值已經送出給程序。可以指定發
生某種故障時進入核心陷門處理程式。可以指定接收到某個信号時暫停或者從系統調
用、核心陷門處理程式傳回,可以通過信号喚醒程序。
可以在程序虛拟位址空間中指定一片區域處在監視中,當針對這片區域進行被監
視類型的操作(比如讀、寫通路),也就是監視事件發生時,産生一次監視點陷入,典
型地導緻程序、LWP暫停,這通過跟蹤FLTWATCH故障或者捕捉非阻塞的SIGTRAP信号實
現。
某些情況下為了析取程序資訊、進行程序控制,控制程序可能需要目标程序臨時
完成某種特殊的操作。例如,pfiles(1)指令可以列出目标程序打開的每個檔案的信
息,這需要目标程序針對每個打開的檔案句柄做stat(2)系統調用。運作在Solaris系
統上的程序典型地花費大量時間阻塞在某個系統調用上,為了獲得目标程序的控制權
完成控制程序送出的任務,需要在目标程序阻塞時搶奪CPU,保護目前系統調用狀态,
當控制程序送出的任務完成後恢複儲存的系統調用狀态繼續執行目标程序原來的任務。
為了達到這個目的,procfs實作了另外一個代理LWP,而不是使用目标程序中現
有LWP,否則狀态儲存、恢複更加複雜。procfs提供了一種機制建立代理LWP(注意
PCAGENT控制消息)。代理LWP建立成功後将是目标程序中唯一可運作LWP,直到它消亡。
目标程序中執行代理LWP以完成控制程序送出的任務,比如在目标程序中執行系統調
用。然後銷毀代理LWP,恢複儲存的程序/LWP狀态。proc結構中有一個成員p_agenttp,
指向建立的代理LWP。核心代碼通過檢查該指針判斷目标程序中是否存在代理LWP。
kthread_t * p_agenttp;
proc(4)手冊頁介紹了程序控制的更多細節。
————————————————————————–
後記:
本篇與< >都是< >的一部分,由于很
多東西缺乏核心Hacking經驗和常用術語約定,翻譯得相當牽強,好在可以對照
/usr/include/下的頭檔案反複了解。<<[805-3024] Solaris裝置驅動程式程式設計指南>>
和<<[805-4038] Solaris流程式設計指南>>是對了解< >很好的補充。
此外可以在comp.unix.programmer和comp.unix.solaris上向Sun開發人員請教。