前言
在本系列的上一篇博文里,我已經介紹了行程/執行緒的基本含義以及一些相關資料結構,現在我們來看看Linux中行程的管理,
行程鏈表
Linux內核定義了一個list_head結構,資料結構定義
struct list_head {
struct list_head *next;
struct list_head *prev;
};
欄位next 和 prev 分別表示通用雙向鏈表向前和向后的指標元素!list_head欄位的指標中存放的是另一個list_head欄位的元素,而不是本身的資料結構地址,如圖

在我們上一篇博客介紹到的行程描述符(task_struct)也有這個結構體,稱為行程鏈表,行程鏈表是一個雙向回圈鏈表,它把所有行程的描述符鏈接起來,每個task_struct結構都包含一個list_head型別的欄位tasks,這個結構的prev和next分別指向前面和后面的task_struct元素,

這個鏈表是一個回圈的雙向鏈表,開始的時候只有init_task這一個行程,它是內核的第一個行程,它的初始化是通過靜態分配記憶體,"手動"(其它的行程初始化都是通過動態分配記憶體初始化的)進行的,每新建一個行程,就通過SET_LINKS宏將該行程的task_struct結構加入到這條雙向鏈表中,不過要注意的是如果一個行程新建一個執行緒(不包括主執行緒),也就是輕量級行程,它是不會加入該鏈表的,通過宏for_each_process可以從init_task開始遍歷所有的行程,
#define for_each_task(p)
for (p = &init_task ; (p = p->next_task) != &init_task ; )
可運行佇列(runqueue)
當內核尋找一個新行程在CPU上運行時,必須只考慮可運行行程(即處在TASK_RUNNING狀態的行程),把可運行狀態的行程組成一個雙向回圈鏈表,也叫可運行佇列(runqueue),
在task_struct結構中定義了兩個指標,
struct task_struct *next_run, *prev_run;
由正在運行或是可以運行的,其行程狀態均為TASK_RUNNING的行程所組成的一個雙向回圈鏈表,即run_queue就緒佇列,該鏈表的前后向指標用next_run和prev_run,鏈表的頭和尾都是init_task(即0號
行程),
但是,為了實作在固定的時間內選出“最佳”的可運行程式,內核將可運行行程的優先級劃分為0-139,并為此建立了140個可運行行程鏈表,用以組織處于TASK_RUNNING狀態的行程,每個行程優先權對應一個不同的鏈表
linux內核定義了一個prio_array_t型別的結構體來管理這140個鏈表,每個可運行的行程都在這140個鏈表中的一個,通過行程描述符結構中的run_list來實作,它也是一個list_head型別,enqueue_task是把行程描述符插入到某個可運行鏈表中,dequeue_task則從某個可運行鏈表中洗掉該行程描述符,TASK_RUNNING狀態的prio_array_t型別的結構體是runqueue結構的arrays[1]成員,


pidhash鏈表
為了通過pid找到行程的描述符,如果直接遍歷行程間互聯的鏈表來查找行程id為pid的行程描述符顯然是低效的,所以為了更為高效的查找,linux內核使用了4個hash散串列來加快查找,之所以使用4個散串列,是為了能根據不同的pid型別來查找行程描述符,它們分別是行程的pid,執行緒組領頭行程的pid,行程組領頭行程的pid,會話領頭行程的pid,每個型別的散串列中是通過宏pid_hashfn(x)來進行散列值的計算的,每個行程都可能同時處于這是個散串列中,所以在行程描述符中有一個型別為pid結構的pids成員,通過它可以將行程加入散串列中,pid結構中包含解決散列沖突的pid_chain成員,它是hlist_node型別的,還有一個是將相同pid鏈起來的pid_list,它是list_head型別,

struct pid_link {
int nr; // pid的數值
struct hlist_node pid_chain;
struct list_head pid_list;
}
struct task_struct {
…
struct pid_link pids[4];
…
}

Linux 行程安全背景關系 struct cred
95 *
96 * The parts of the context break down into two categories:
97 *
98 * (1) The objective context of a task. These parts are used when some other
99 * task is attempting to affect this one.
100 *
101 * (2) The subjective context. These details are used when the task is acting
102 * upon another object, be that a file, a task, a key or whatever.
103 *
104 * Note that some members of this structure belong to both categories - the
105 * LSM security pointer for instance.
106 *
107 * A task has two security pointers. task->real_cred points to the objective
108 * context that defines that task's actual details. The objective part of this
109 * context is used whenever that task is acted upon.
110 *
111 * task->cred points to the subjective context that defines the details of how
112 * that task is going to act upon another object. This may be overridden
113 * temporarily to point to another security context, but normally points to the
114 * same context as task->real_cred.
115 */
116 struct cred {
117 atomic_t usage;
118 #ifdef CONFIG_DEBUG_CREDENTIALS
119 atomic_t subscribers; /* number of processes subscribed */
120 void *put_addr;
121 unsigned magic;
122 #define CRED_MAGIC 0x43736564
123 #define CRED_MAGIC_DEAD 0x44656144
124 #endif
125 uid_t uid; /* real UID of the task */
126 gid_t gid; /* real GID of the task */
127 uid_t suid; /* saved UID of the task */
128 gid_t sgid; /* saved GID of the task */
129 uid_t euid; /* effective UID of the task */
130 gid_t egid; /* effective GID of the task */
131 uid_t fsuid; /* UID for VFS ops */
132 gid_t fsgid; /* GID for VFS ops */
133 unsigned securebits; /* SUID-less security management */
134 kernel_cap_t cap_inheritable; /* caps our children can inherit */
135 kernel_cap_t cap_permitted; /* caps we're permitted */
136 kernel_cap_t cap_effective; /* caps we can actually use */
137 kernel_cap_t cap_bset; /* capability bounding set */
138 #ifdef CONFIG_KEYS
139 unsigned char jit_keyring; /* default keyring to attach requested
140 * keys to */
141 struct key *thread_keyring; /* keyring private to this thread */
142 struct key *request_key_auth; /* assumed request_key authority */
143 struct thread_group_cred *tgcred; /* thread-group shared credentials */
144 #endif
145 #ifdef CONFIG_SECURITY
146 void *security; /* subjective LSM security */
147 #endif
148 struct user_struct *user; /* real user ID subscription */
149 struct user_namespace *user_ns; /* cached user->user_ns */
150 struct group_info *group_info; /* supplementary groups for euid/fsgid */
151 struct rcu_head rcu; /* RCU deletion hook */
152 };
正如uid,euid的關系一樣,task_struct也有兩種身份cred
struct task_struct{
...
/* process credentials */
const struct cred __rcu *real_cred; /* objective and real subjective task credentials (COW) */
const struct cred __rcu *cred; /* effective (overridable) subjective task credentials (COW) */
...
}
各種id
uid 和 gid 都是成雙成對的,這里就拿uid說明其作用:
- uid 是創建行程的用戶的id,不是創建可執行程式的用戶id
- euid 是行程運行程序中實時的ID(或者說動態獲取的ID)
- suid 是保存的euid切換之前的id,用于euid切換回來
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/19523.html
標籤:訊息安全
上一篇:地信
下一篇:Jquery 選擇器
