struct pid 與 struct task_struct 都是全域性的(核心的),struct pid 的 level 為最高的命名空間層次(全域性的命名空間層次為0),
task_struct.pid 為全域性的pid,find_get_pid(pid_t nr);nr 必須為全域性pid_t pid ,因為後續的namespace 是根據current 巨集變數尋找的全域性pid_namespace;
首先給出乙個總圖,其中紅線是結構描述,黑線是指向。其中程序a,b,c是乙個程序組的,a是組長程序,所以b和
c的task_struct
結構體中的
pid_link
成員的node
欄位就被鄰接到程序
a對應的
struct pid
中的tasks[1]。
struct upid
通過pid_hash
和pid
數值關聯了起來,這樣就可以通過
pid數值快速的找到所有命名空間的
upid
結構,numbers
是乙個struct pid
的最後乙個成員,利用可變陣列來表示這個
pid結構當前有多少個命名空間.
struct pid
是程序id
在核心結構的乙個表示。但有可能會出現多個
task_struct
例項共享同乙個程序
id,這就需要將所有共享程序id的
task_struct
都以一種方式和
struct pid
關聯起來,這裡就是
struct pid
結構中的
tasks陣列
pid->tasks[
type]
此圖可以看到第乙個pid(session group) struct pid.tasks[pidtype_pid] 只有乙個struct task_struct 指向,struct pid.tasks[pidtype_sid]有三個,所以可以根據struct pid 和 type 尋找struct task_struct, 而通過namespace 和 nr 可以找到struct pid;
namespace+nr –>struct pid-> struct task_struct
struct pid也可以通過struct hlist_head tasks[pidtype_max]自己作為程序tasks[pidtype_pid], 也就是a,但是在實際測試中,無法找到自己作為會話程序的會話其他程序,也無法找到作為組長程序時其它程序tasks[pidtype_pgid],也就是b或者c,。顯然可以使用type=pidtype_pid,其它兩種情況不能使用。實際測試中,idtype_pid可以通過,idtype_pgid未通過。pidtype_sid未測試
struct task_struct + pid_type -> struct pid;( find_pid_ns函式)
struct pid[numbers] + pid_namespace.level ->upid->nr
task_struct 可以通過pid_link[pidtype_max] 找到組長程序
pid_link[pidtype_pgid],比如通過b的task_struct, pidtype_pgid找到a,自己作為程序pid_link [pidtype_pid], 也就是a,自己作為會話程序的會話其他程序。實際測試中,pidtype_pgid,idtype_pid可以通過,idtype_ssid
未通過。pidtype_sid未測試
組長程序tasks[pidtype_pid] == tasks[pidtype_pgid],
__task_pid_nr_ns(),引數task_struct(b), pidtype_pgid ==引數task_struct(a), pidtype_pid==引數task_struct(a), pidtype_pgid
第乙個等於是因為if (type != pidtype_pid) task = task->group_leader;
第二個等於是因為組長程序tasks[pidtype_pid] == tasks[pidtype_pgid]。
pid_t __task_pid_nr_ns(struct task_struct *task, enum pid_type type,
struct pid_namespace *ns)
task_struct 找自己在全域性的pid,然後通過指向的pid 和命名空間level,找到在命名空間pid(upid->nr)的區域性pid. 將
struct upid
按數字pid
和命名空間對映儲存,當給定數字
pid和命名空間時,可以獲取
struct upid
,然後根據
container_of
獲取struct pid
。struct pid
中的tasks
欄位的第乙個
task_struct。
pid_t pid_nr_ns(struct pid *pid, struct pid_namespace *ns)
struct pid_link pids[pidtype_max];
enum pid_type
;static inline structpid *task_pid(structtask_struct *task)
為2.6.11核心,3.19核心pid_hash沒有 0, 1, 2, 3也就是pid,pgid,sid,tgid.相當於只有乙個pid.《深入理解linux核心》第三版使用的時2.6.11,而《linux核心完全參考手冊》第二是3.19
struct pid *find_pid_ns(int nr, struct pid_namespace *ns)
find_pid_ns()
在pid_hash的雜湊表中根據雜湊函式得到pid所在的鍊錶頭部,然後遍歷得到 id 和 ns 都匹對的pid結構體指標;
void __init pidhash_init(void)
從pidhash_init函式中可以看出,pid_hash至少含有16項,最多4096項,它是系統中所有程序的雜湊表,根據id分配,但此雜湊表與pgid,tgid並無直接關係;
#define get_current() (current_thread_info()->task)
#define current get_current()
find_get_pid()
函式用於通過全域性
pid和其型別找到對應的
task
結構,find_get_pid(current->pid);current
為全域性struct task_struct.
task->pid
為全域性。
find_get_pid()
的引數必須為全域性
task
的pid_t pid. (task->pids[pidtype_pid].pid 也是全域性,pid_namespace.nr 不是全域性)
find_get_pid呼叫struct pid_namespace *task_active_pid_ns(struct task_struct *tsk)
task_active_pid_ns根據形參task獲得對應的pid namespace
其使用的例程如下:
static int acct_on(struct filename *pathname)
本例中就根據當前task current 獲得current對應的pid namespace
其原始碼分析如下:
struct pid_namespace *task_active_pid_ns(struct task_struct *tsk)
可以看到這個函式分為兩步,第一步通過task_pid 拿到當前task的pid,這裡的pid是全域性的。
在已pid 為形參通過ns_of_pid 得到pid 對應的namespace
這裡為什麼說task_pid拿到pid是全域性的呢?
static inline struct pid *task_pid(struct task_struct *task)
可以看到這裡的pid是儲存在task中的pids 這個成員陣列中,根本和namespace不屬於任何的命令空間
而屬於系統啟動期間開始的init程序,即初始的命名空間。屬於task本身的資料結構。因此說task_pid得到的pid是全域性的。
PHP核心 命名空間
在維基百科中,對命名空間的定義是 命名空間 英語 namespace 表示識別符號 identifier 的上下文 context 乙個識別符號可在多個命名空間中定義,它在不同命名空間中的含義是互不相干的。在程式語言中,命名空間是一種特殊的作用域,它包含了處於該作用域內的識別符號,且本身也用乙個識別...
Linux核心之程序位址空間
程序使用的是虛擬記憶體中的位址,也叫線性位址,由作業系統協助相關硬體 如mmu 對映到實體地址。線性位址是通過頁表 page table 對映到物理記憶體,頁表由作業系統維護並被處理器引用。核心空間在頁表中擁有較高特權級,因此使用者態程式試圖訪問這些頁時會導致乙個頁錯誤。在linux中,核心空間是持...
Linux核心之程序位址空間
核心是作業系統中優先順序最高的成分 核心信任自己 核心總是盡量推遲給使用者態程序分配動態記憶體 核心必須能隨時準備捕獲使用者態程序引起的所有定址錯誤 當使用者態程序請求動態記憶體時,並沒有會的請求頁框,而僅僅獲得對乙個新的線性位址區間的使用權,而這一線性位址區間就稱為程序位址空間的一部分,這一區間叫...