kernel hacking. Linux的僵尸進程及其回收處理

UNIX家族的操作系統(tǒng)里面都用進程的概念足画,進程就是一個程序運行的實體(instance)。這個概念當(dāng)年大學(xué)里面學(xué)《操作系統(tǒng)原理》的時候怎么也搞不懂(清華大學(xué)出版社出版结耀,屠立德著)砂竖。

直到后面讀研究生開始做課題么介,寫代碼才知道到底是怎么回事罪治。

Linux延用了UNIX的設(shè)計思想丽声,繼續(xù)使用進程這個概念(后面的線程也是用進程來實現(xiàn)的,所以叫做輕量級進程规阀,LWP)恒序。進程在系統(tǒng)中有不同的狀態(tài),進程就是在各個狀態(tài)之間來回切換谁撼,從而完成設(shè)計的功能。操作系統(tǒng)內(nèi)部為每一個進程提供了一個進程描述符,這個結(jié)構(gòu)龐大而且復(fù)雜厉碟,用來描述進程的信息喊巍,例如打開的文件,調(diào)度信息箍鼓,父子進程關(guān)系等等崭参,是操作系統(tǒng)管理進程的核心數(shù)據(jù)結(jié)構(gòu),Linux里面是struct task_struct款咖。

系統(tǒng)里面的進程因為父子關(guān)系而形成一個樹形結(jié)構(gòu)何暮。整個系統(tǒng)啟動過程中第一個用戶態(tài)的進程是Init進程,叫做1號進程铐殃,它是整個樹形結(jié)構(gòu)的根海洼,所有進程都是它的子孫后代。Init是系統(tǒng)的管理進程富腊,包含很多功能坏逢,其中一個功能就是“垃圾回收”。

在操作系統(tǒng)原理中會提到“僵尸進程”赘被,什么是僵尸進程是整?就是一個進程在結(jié)束運行的時候它的主體已經(jīng)結(jié)束,但是內(nèi)核當(dāng)中的進程描述符還沒有被回收(它的“殼”還在民假,但是“靈魂”沒有了)浮入。為什么它的進程描述符沒有被回收呢?

因為一個進程結(jié)束運行的時候羊异,是需要通知它的父進程對其進程描述符進行回收(它自己都死了事秀,沒法回收自己)。而如果它的父進程忙于別的事情而不去主動回收該進程的描述符球化,就會導(dǎo)致系統(tǒng)出現(xiàn)“僵尸進程”秽晚。而這個通知和回收的過程是通過信號SIGCHLD和wait來完成的。具體可以參考Linux進程編程方面的文章或者書籍筒愚。

下面是一個例子赴蝇。

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <sys/types.h>

#include <string.h>

int main(int argc, char **argv)

{

pid_t pid, ppid = 0;

printf("Argv[0] = %s, length = %ld\n", argv[0], strlen(argv[0]));

strncpy(argv[0], "testaa", strlen(argv[0]));

pid = fork();

if (pid > 0) {

printf("Parent: pid = %d, ppid = %d\n", getpid(), getppid());

while(1) {

sleep(1);

}

} else if (pid == 0) {

strncpy(argv[0], "taowtest", strlen(argv[0]));

printf("Child: pid = %d, ppid = %d\n", getpid(), getppid());

exit(123);

}

return 0;

}

運行結(jié)果為 (運行環(huán)境是Ubuntu 18.04 X86_64, VMware的虛擬機)

Parent: pid = 561, ppid = 31574

Child: pid = 562, ppid = 561

/test/kermod# ps ax | grep -e 'testaa\|taow'

561 pts/0 S 0:00 testaa

562 pts/0 Z 0:00 [taowtest] <defunct>

“僵尸進程”在ps命令下面顯示的狀態(tài)是Z,而且不接受kill -9 pid去退出巢掺。

那么如果一個進程A的父進程P先于它退出句伶,那么A在退出的時候誰來回收A的進程描述符呢?這個就是init進程的工作陆淀。當(dāng)一個進程的父進程(生父)退出之后考余,這個父進程下面的子進程都成為init(養(yǎng)父)的子進程了。init進程會周期的調(diào)用wait()來回收其子進程的進程描述符轧苫。

所以楚堤,要想真正“清除”僵尸進程,需要殺掉(kill)它的父進程(生父,不是養(yǎng)父init進程)身冬。

有沒有別的辦法來做這個事情呢衅胀?有,只要我們能寫和插入kernel module就可以干這個事情酥筝。

下面這個代碼是模擬內(nèi)核當(dāng)中父進程回收子進程資源的邏輯來完成對僵尸進程的“過繼”和“清除”滚躯,而不需要殺死其父進程。簡單來說就是把一個父進程活著的僵尸進程直接交給init進程使其對它進行回收嘿歌。

代碼參考前面掸掏。父進程啟動把自己名字改為testaa,然后啟動子進程宙帝,子進程改名為taowtest丧凤,并把自己變成僵尸進程。最后插入kernel module茄唐,其找到Zombie狀態(tài)息裸,并且名字是taowtest的進程之后對其進行處理,把它交給init進程沪编,并通知init進程對其進行回收呼盆。

下面是找到名為taowtest的僵尸進程的參考代碼。

for_each_process( task ) {

? ? if ((task->pid == 0) || (task->pid == 1)) {

? ? ? ? pr_info("PID %d, comm = %s\n", task->pid, task->comm);

? ? ? ? p = task;

? ? ? ? continue;

? ? }

? ? if (strstr(task->comm, "taowtest")) {

? ? ? ? pr_info("Got : %d, %s, ppid=%d, exit_state = %d\n",

? ? ? ? ? ? ? ? task->pid, task->comm, task->parent->pid, task->exit_state);

? ? ? ? if (task->exit_state == EXIT_ZOMBIE) {

? ? ? ? ? ? 蚁廓。访圃。。相嵌。腿时。

? ? ? ? ? ? pr_info("Reaped Zombie process %d\n", task->pid);

? ? ? ? ? ? 。饭宾。批糟。。看铆。

? ? ? ? }

? ? }

}

模塊加載之后的內(nèi)核log顯示如下徽鼎,

[250532.186292] LOADING MODULE

[250532.186294] PID 1, comm = systemd

[250532.186380] Got : 561, taowtest, ppid=31574, exit_state = 0

[250532.186382] Got : 562, taowtest, ppid=561, exit_state = 32

[250532.187181] Reaped Zombie process 562

此時,再看ps -ax的輸出弹惦,已經(jīng)找不到taowtest了否淤,而此時testaa仍然還在。

/test/kermod# ps ax | grep 'testaa\|taow'

561 pts/0 S 0:00 testaa

577 pts/0 S+ 0:00 grep --color=auto testaa\|taow

/test/kermod#

以上是一種回收僵尸進程的方法棠隐,還有另一種方法有空再分析吧石抡。

總之,這是個有趣的實驗助泽,有助于搞清楚Linux系統(tǒng)中進程之間關(guān)系啰扛,進程回收嚎京,信號處理,以及init進程等等很多方面侠讯。而且它可以解決不殺死父進程的情況下回收清理大量僵尸進程的場景和需求挖藏。

后續(xù)會陸陸續(xù)續(xù)把一千多篇關(guān)于Linux暑刃,X86厢漩,VT-X,KVM岩臣,服務(wù)器溜嗜,嵌入式系統(tǒng)等有關(guān)的東西整理出來。

歡迎轉(zhuǎn)載架谎,轉(zhuǎn)載請標明出處炸宵。Thanks

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市谷扣,隨后出現(xiàn)的幾起案子土全,更是在濱河造成了極大的恐慌,老刑警劉巖会涎,帶你破解...
    沈念sama閱讀 218,284評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件裹匙,死亡現(xiàn)場離奇詭異,居然都是意外死亡末秃,警方通過查閱死者的電腦和手機概页,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來练慕,“玉大人惰匙,你說我怎么就攤上這事×褰” “怎么了项鬼?”我有些...
    開封第一講書人閱讀 164,614評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長劲阎。 經(jīng)常有香客問我绘盟,道長,這世上最難降的妖魔是什么哪工? 我笑而不...
    開封第一講書人閱讀 58,671評論 1 293
  • 正文 為了忘掉前任奥此,我火速辦了婚禮,結(jié)果婚禮上雁比,老公的妹妹穿的比我還像新娘稚虎。我一直安慰自己,他們只是感情好偎捎,可當(dāng)我...
    茶點故事閱讀 67,699評論 6 392
  • 文/花漫 我一把揭開白布蠢终。 她就那樣靜靜地躺著序攘,像睡著了一般。 火紅的嫁衣襯著肌膚如雪寻拂。 梳的紋絲不亂的頭發(fā)上程奠,一...
    開封第一講書人閱讀 51,562評論 1 305
  • 那天,我揣著相機與錄音祭钉,去河邊找鬼瞄沙。 笑死,一個胖子當(dāng)著我的面吹牛慌核,可吹牛的內(nèi)容都是我干的距境。 我是一名探鬼主播,決...
    沈念sama閱讀 40,309評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼垮卓,長吁一口氣:“原來是場噩夢啊……” “哼垫桂!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起粟按,我...
    開封第一講書人閱讀 39,223評論 0 276
  • 序言:老撾萬榮一對情侶失蹤诬滩,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后灭将,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體疼鸟,經(jīng)...
    沈念sama閱讀 45,668評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,859評論 3 336
  • 正文 我和宋清朗相戀三年宗侦,在試婚紗的時候發(fā)現(xiàn)自己被綠了愚臀。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,981評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡矾利,死狀恐怖姑裂,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情男旗,我是刑警寧澤舶斧,帶...
    沈念sama閱讀 35,705評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站察皇,受9級特大地震影響茴厉,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜什荣,卻給世界環(huán)境...
    茶點故事閱讀 41,310評論 3 330
  • 文/蒙蒙 一矾缓、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧稻爬,春花似錦嗜闻、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽样眠。三九已至,卻和暖如春翠肘,著一層夾襖步出監(jiān)牢的瞬間檐束,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評論 1 270
  • 我被黑心中介騙來泰國打工束倍, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留被丧,地道東北人。 一個月前我還...
    沈念sama閱讀 48,146評論 3 370
  • 正文 我出身青樓肌幽,卻偏偏與公主長得像晚碾,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子喂急,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,933評論 2 355