如何通過程序id查詢程序的描述符task_struct?在實際的工作中,我的驅動中需要通過讀取寫進記憶體中的程序id值查詢對應的程序是否還在執行,或者是已經退出。通過閱讀核心**,核心中已有相應的api函式來供我們使用。下面是我在使用過程中的一些筆記總結。
linux系統上執行的程序可能成百上千的,或者更多,如何能夠快速的通過pid值反向的查詢task_struct,核心的方法是通過hash雜湊表的方式。下面結合3.16.7核心版本來分析pid hash表的實現。
void
__initpidhash_init(
void
) pidhash_init函式在系統啟動時由start_kernel函式呼叫。pid hash表的大小由執行機器的總記憶體數決定,範圍在16~4096個之間。在之前老的核心(如2.6.12.6)pid hash表包含四個表,分別針對enum pid_type的四種不同型別pid的情況。
程序建立時,是如何將task_struct與pid_hash雜湊表關聯起來的?在copy_process函式中會判斷引數pid指標是否等於init_struct_pid,如果不相等,就會呼叫alloc_pid函式分配乙個新的struct pid型別的pid例項,並初始化。如果相等,說明是idle程序的建立。一般情況下,pid指標為空。下面看下alloc_pid函式的實現:
struct
pid *alloc_pid(struct
pid_namespace *ns)
for
(type = 0
; type
<
pidtype_max
; ++
type
)init_hlist_head(
&pid->tasks
[type
]);
/*初始化每個
id型別的雜湊表頭
*/upid
= pid->numbers +ns->level
;spin_lock_irq(
&pidmap_lock
);for
( ;
upid
>= pid->numbers
; --
upid
)spin_unlock_irq(
&pidmap_lock
); 引數ns引數是建立新程序時父程序task_struct描述符的命名空間指標nsproxy的pid namespace,一般情況下是指向init_pid_ns,如果在clone時候有指定clone_newpid標誌,則會在copy_process中呼叫alloc_pid之前呼叫copy_namespaces建立乙個新的pid namespace。
函式首先呼叫kmem_cache_alloc從slab中分配pid記憶體。上面講到如果clone時有指定標誌clone_newpid的情況下,會建立乙個新的pid namespace,此新建的pid namespace的parent指向父程序的pid namespace,相應的level也加一。這個新建的程序對於新建立的pid namespace和父程序的pid namespace,以及更初始的pid namespace都是可見的
在第乙個for迴圈中,從新建立pid namespace的level(此成員表示可以看到該程序的命名空間的數目)到0,給每個可見此程序的命名空間都分配乙個區域性的pid值。並將新分配的區域性pid值nr賦給pid描述符的對應的命名空間numbers的nr欄位,將pid namespace指標tmp賦給對應的命名空間numbers的ns欄位。
struct pid結構體中成員tasks是乙個陣列,每個陣列成員是乙個雜湊表的表頭,對應於pid_type列舉中的乙個id型別。在第二個for迴圈中,初始化tasks陣列對應的每個id型別的雜湊表頭。
pid結構體的成員numbers,雖然是乙個長度為1的陣列,但是因為它是在結構體的最後,可以根據pid所屬的空間的個數分配更多的空間。numbers陣列的大小由pid->level欄位決定。level值越大的命名空間級別越低,它能夠被此pid的level值更小的命名空間看見,也就是說父命名空間能給看到子命名空間,反之子命名空間不能看見父命名空間。
**這裡首先將upid指向此pid描述符的級別最低的命名空間,然後在for迴圈中遍歷每層的命名空間,以當前pid namespace的程序id值nr和命名空間指標ns為key值,呼叫pid_hashfn函式生成pid_hash全域性陣列中的bucket id值,並將此程序鏈入此bucket id所在的hash雜湊表中。
上面是alloc_pid函式分配乙個新的pid描述符的大致過程,接著回到copy_process函式看看建立新程序的餘下的和pid hash相關的**。
copy_process函式**片段:
if
(likely(
p->pid
))else
attach_pid(p,
pidtype_pid
);/*
把pidtype_pid
型別的pid
插入到相應的鍊錶中
*/}如果前面alloc_pid建立新的pid成功或者本身沒有指定clone_newpid標誌,就會進入上述**片段執行。前面講到列舉型別pid_type的不同id型別,在我分析的新核心(3.16.7)中是三種:
pidtype_pid
對應程序pid
pidtype_pgid
程序組領頭程序pid
pidtype_sid
會話領頭程序pid
首先呼叫函式
init_task_pid
將初始化新建立程序的型別
pidtype_pid
的pid例項,如果此新建立的程序是執行緒組的組長,則初始化此程序的
pidtype_pgid
型別和pidtype_sid
型別的例項,並且呼叫attach_pid函式將此程序進行hash,加入到已經初始化好的pid_hash對應bucket的雜湊表中。
這樣就建立起了乙個雙向鍊錶的關係,程序可以通過task_struct的
task->pids[type]
的成員pid訪問pid例項,pid例項也可以通過遍歷
tasks[
type
]鍊錶來查詢程序task_struct。
經過上面的分析,乙個程序可以屬於多個不同的命名空間,同乙個程序在不同的命名空間中有不同的區域性pid值,多個程序task_struct可以共用乙個pid描述符。
查詢程序的pid
在客戶端的terminal中執行sslocal來使用shadowsocks時,如果在命令末尾加上 讓程序在後台執行。之後如果要對shadowsocks作調整,那麼需要查詢sslocal的pid來kill之前的程序。一種常用的方式為 ps a grep sslocal 7380 pts 1 s 0 1...
awk 的簡單使用 查詢程序pid
在linux下我一般只用grep 和 find工具進行查詢 這些工具雖然強大但是我們平時只會用到幾個常用的,那些什麼什麼詳解,什麼什麼的完全解析的文章我們根本就不適用,只要學會幾條就好了。先說一下我常用的grep 命令 grep color 帶顏色高亮,遠端登陸別人的機器有時候沒有高亮 grep a...
Linux中查詢程序PID並殺死程序的方法
ps命令 使用ps ef命令確定要殺死程序的pid ps ef grep chrome或者 ps aux grep chromekill 命令的執行原理是這樣的,kill 命令會向作業系統核心傳送乙個訊號 多是終止訊號 和目標程序的 pid,然後系統核心根據收到的訊號型別,對指定程序進行相應的操作。...