通過pid查詢程序task struct結構體

2021-08-18 16:30:24 字數 3516 閱讀 3580

如何通過程序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,然後系統核心根據收到的訊號型別,對指定程序進行相應的操作。...