2010年10月7日 星期四

砍不掉的pid


最近公司同事碰到了一個問題:

當他的設定檔被變更之後/或者是他的daemon(文後稱為A daemon)被關閉時,

他會叫一個handler起來,

那個handler會根據使用者的設定去啟動一些daemon。

而好巧不巧的,那個handler叫起來的其中一支daemon(文後稱為B daemon),

他會把它自已的previous instance幹掉(送SIGTERM),

然後自己再霸佔那個daemon的位置。

這一切看起來很好,哪邊有差錯呢?

首先呢,我們發現當A daemon被幹掉(SIGTERM)的時候,

他會叫起B daemon,這樣是對的,

接下來我們再把A daemon (SIGTERM)殺掉,

他會再次的叫起B daemon,B daemon應該要把先前的B daemon關掉。

但是實際上,我的device上面有兩支B daemon…

what happens?

# for i in `pidof B`; do grep SigBlk /proc/$i/status; done

發現他們的低bit 15 (0x4000)的位置都被設定了,

也就是說,他們的SIGTERM都被block了… 這是怎麼一回事呢?

首先我們該懷疑的是A daemon,因為他有嫌疑…

# for i in `pidof A`; do grep SigBlk /proc/$i/status; done

這一行的結果你應該只會看到一行,不然就詭異了… ><

發現他的blocked signal一切正常,沒有異樣。

一直到一個高手同事直接打開他的程式碼來看他到底是怎麼做這些事的…

發現他是在atexit的時候去叫handler,

atexit的時候有可能是在SIGTERM發生不久的時候,

所以SIGTERM根本就被block掉了(Linux的機制),

而他生出來的handler跟handler生出來的B daemon也全部繼承了這樣的SigBlk…

所以這樣的程式根本沒辦法經由

# kill `pidof B`

去砍掉它,所以B daemon就不斷的被生出來…