接前一篇文章:Linux內核進程管理子系統有什么第三十二回 —— 進程主結構詳解(28)
本文內容參考:
Linux內核進程管理專題報告_linux rseq-CSDN博客
《趣談Linux操作系統 核心原理篇:第三部分 進程管理》—— 劉超
《圖解Linux內核?基于6.x》 —— 姜亞華 機械工業出版社
特此致謝!
進程管理核心結構 —— task_struct
5. 進程定位相關成員
上一回開始解析struct task_struct中進程的定位相關成員,包括以下字段:
/* PID/PID hash table linkage. */struct pid *thread_pid;struct hlist_node pid_links[PIDTYPE_MAX]
這幾個字段的描述如下:
字段 | 類型 | 描述 |
---|---|---|
thread_pid | struct pid * | 進程對應的pid |
pid_links | hlist_node[PIDTYPE_MAX] | link |
上一回給出了struct pid的定義,再來回顧一下,在include/linux/pid.h中,如下:
struct pid
{refcount_t count;unsigned int level;spinlock_t lock;/* lists of tasks that use this pid */struct hlist_head tasks[PIDTYPE_MAX];struct hlist_head inodes;/* wait queue for pidfd notifications */wait_queue_head_t wait_pidfd;struct rcu_head rcu;struct upid numbers[1];
};
struct pid的主要字段見下表:
字段 | 類型 | 描述 |
---|---|---|
count | refcount_t | 引用計數 |
level | unsigned int | pid的層級 |
tasks | struct hlist_head[PIDTYPE_MAX] | 鏈表數組 |
numbers | struct upid[] | 每個層級的upid信息 |
struct upid的定義也在include/linux/pid.h中(就在struct pid定義的上邊),如下:
/** struct upid is used to get the id of the struct pid, as it is* seen in particular namespace. Later the struct pid is found with* find_pid_ns() using the int nr and struct pid_namespace *ns.*/struct upid {int nr;struct pid_namespace *ns;
};
struct upid用于獲取struct pid的id,正如在特定名稱空間中看到的那樣。稍后,使用int nr和struct pid_namespace *ns,通過find_pid_ns()找到struct pid。
struct upid的主要字段見下表:
字段 | 類型 | 描述 |
---|---|---|
nr | int | id |
ns | struct pid_namespace * | 命名空間 |
進程的id是有空間的,不同的空間中相同的id也能表示不同的進程。幸運的是,多數情況下進程都在一個level等于0的命名空間(pid_namespace)中。
假設需要查找的進程就在該命名空間中,那么struct pid的level字段就等于命名空間的層級,也等于0。
struct upid numbers[1]字段是struct upid數組,數組元素的個數為level+1,也就是1。
struct upid的int nr字段的值等于進程的id。pid_namespace結構中定義了類型為struct idr的idr字段,有其維護id和pid之間一對一的關系。struct pid_namespace的定義在include/linux/pid_namespace.h中,如下:
struct pid_namespace {struct idr idr;struct rcu_head rcu;unsigned int pid_allocated;struct task_struct *child_reaper;struct kmem_cache *pid_cachep;unsigned int level;struct pid_namespace *parent;
#ifdef CONFIG_BSD_PROCESS_ACCTstruct fs_pin *bacct;
#endifstruct user_namespace *user_ns;struct ucounts *ucounts;int reboot; /* group exit code if this pidns was rebooted */struct ns_common ns;
} __randomize_layout;
這樣,使用id在struct pid_namespace(對象)內查找,即可得到struct upid(對象)。再通過uipd即可找到pid(利用container_of宏)。這就是上邊struct upid的注釋中講到的:
find_pid_ns函數在kernel/pid.c中,代碼如下:
struct pid *find_pid_ns(int nr, struct pid_namespace *ns)
{return idr_find(&ns->idr, nr);
}
EXPORT_SYMBOL_GPL(find_pid_ns);
idr_find函數實際上在筆者的《DRM專欄》中曾經講到過,當時是用在了Linux圖形子系統中,而這里則是用在了進程管理中。idr_find函數在lib/idr.c中,代碼如下:
/*** idr_find() - Return pointer for given ID.* @idr: IDR handle.* @id: Pointer ID.** Looks up the pointer associated with this ID. A %NULL pointer may* indicate that @id is not allocated or that the %NULL pointer was* associated with this ID.** This function can be called under rcu_read_lock(), given that the leaf* pointers lifetimes are correctly managed.** Return: The pointer associated with this ID.*/
void *idr_find(const struct idr *idr, unsigned long id)
{return radix_tree_lookup(&idr->idr_rt, id - idr->idr_base);
}
EXPORT_SYMBOL_GPL(idr_find);
這樣,從id到struct pid的路就打通了。再來回顧一下這條路徑:
進程id <---> struct upid中的int nr字段 ---> level等于0的命名空間(struct upid numbers[0]的struct pid_namespace *ns)---> struct upid ---> struct pid
下一回解析從struct pid到strucr task_struct。