歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> Linux入門知識:殺死僵屍進程

Linux入門知識:殺死僵屍進程

日期:2017/2/28 16:08:53   编辑:Linux教程

Linux並不把進程的樹形結構導出給普通用戶,然而在內核中,它卻使用樹形結構來管理進程。linux內核使用“子進程退出,父進程收屍,父進程退出,子進程被過繼” 這種方式來管理進程的死亡,然而卻少了一種,那就是父進程不給子進程收屍的情況 ,這就是僵屍進程的原因。

既然知道了僵屍進程為何產生,那麼想干掉它們就簡單了。記住:任何沒有人為因素的純技術問題都是可以解決的!如何操作呢?很簡單,就三步:

1.將僵屍進程從樹形進程組織中摘除;
2.將僵屍進程過繼給一個特定的進程;
3.該特定進程調用wait來回收掉它。

這三步豈不是很麻煩,直接干掉它的父進程不就得了,這樣內核會自己將僵屍進程過繼給別的進程或者init進程,然而有時我們不能這麼做,如果它的父進程是個很重要的進程咋辦,我們不能因為父輩拋棄了過早去世的孩子而責怪父親,如果那樣,linux內核的法律豈不是比我們還嚴重...既然父親不要孩子了,那麼建立一個收容所是必要的,使用上述三個步驟完成子進程空殼的過繼和回收!這個收容所可以在內核空間也可以在用戶空間,這不是最重要的。本文給出了一個預研例子:

1.首先給出一個用戶態進程代碼:

  1. #include <unistd.h>
  2. int main()
  3. {
  4. int pid = 0;
  5. pid = fork();
  6. if (pid == 0) { //子進程將瞬間變成僵屍,因為www.linuxidc.com:1.父進程不回收;2.父進程不忽略
  7. } else {
  8. while (1) {
  9. //I'm VIP,though I am always sleeping!
  10. sleep(1);
  11. }
  12. }
  13. }
  1. #include <unistd.h>
  2. int main()
  3. {
  4. int pid = 0;
  5. pid = fork();
  6. if (pid == 0) { //子進程將瞬間變成僵屍,因為:1.父進程不回收;2.父進程不忽略
  7. } else {
  8. while (1) {
  9. //I'm VIP,though I am always sleeping!
  10. sleep(1);
  11. }
  12. }
  13. }
2.然後給出一個內核模塊代碼:
  1. unsigned long pid; //參數保存結束的僵屍進程的進程號
  2. module_param(pid, long, S_IRUSR);
  3. MODULE_PARM_DESC(pid, "pid");
  4. struct task_struct *(*find)(struct pid *pid, enum pid_type type);
  5. struct pid *(*get)(pid_t nr);
  6. long (*wait1)(pid_t pid, void *v, int options, void *ru);
  7. int __init rm_init(void){
  8. find = 0xc1041aed; //根據pid結構得到task_t函數的地址
  9. get=0xc1041b81; //根據pid得到pid結構體函數的地址
  10. wait1 = 0xc1032e02;
  11. struct pid* spid = (*get)(pid);
  12. struct task_struct *tsk = (*find)(spid, PIDTYPE_PID);
  13. tsk->real_parent = current;
  14. tsk->parent = current;
  15. list_del(&tsk->sibling);
  16. list_add_tail(&tsk->sibling, &tsk->real_parent->children);
  17. (*wait1)(pid, NULL, 0, NULL);
  18. return 0;
  19. }
  20. void __exit rm_exit(void){
  21. }
  22. module_init(rm_init);
  23. module_exit(rm_exit);
  24. MODULE_LICENSE("GPL");
  1. unsigned long pid; //參數保存結束的僵屍���程的進程號
  2. module_param(pid, long, S_IRUSR);
  3. MODULE_PARM_DESC(pid, "pid");
  4. struct task_struct *(*find)(struct pid *pid, enum pid_type type);
  5. struct pid *(*get)(pid_t nr);
  6. long (*wait1)(pid_t pid, void *v, int options, void *ru);
  7. int __init rm_init(void){
  8. find = 0xc1041aed; //根據pid結構得到task_t函數的地址
  9. get=0xc1041b81; //根據pid得到pid結構體函數的地址
  10. wait1 = 0xc1032e02;
  11. struct pid* spid = (*get)(pid);
  12. struct task_struct *tsk = (*find)(spid, PIDTYPE_PID);
  13. tsk->real_parent = current;
  14. tsk->parent = current;
  15. list_del(&tsk->sibling);
  16. list_add_tail(&tsk->sibling, &tsk->real_parent->children);
  17. (*wait1)(pid, NULL, 0, NULL);
  18. return 0;
  19. }
  20. void __exit rm_exit(void){
  21. }
  22. module_init(rm_init);
  23. module_exit(rm_exit);
  24. MODULE_LICENSE("GPL");

上述的模塊實現了僵屍進程的回收,雖然還不是很完美,然而起碼證實了可行性,www.linuxidc.com我們一些函數的地址還是通過procfs得到的。具體在代碼潤色方面,我有四個建議,這四個方式無論哪一個都是可行的,而且花不了太多時間,這裡代碼就從略了,如果寫一下的話,充其量也只能鍛煉一下c語言編程能力:

1.實現一個內核線程,專門實現模塊init函數的邏輯,需要干掉的僵屍進程號通過procfs傳入內核,然後在write例程中喚醒回收僵屍進程的內核線程;

2.實現一個用戶態進程U,掛載一個信號A的處理函數,內部實現waitpid,通過procfs傳入或者通過netlink傳入內核的僵屍進程號代表的進程過繼給用戶態進程U,然後向U發送信號A;

3./dev/mem的機器碼編程或者直接釋放僵屍進程的task_t。

4.在/proc/<pid>/目錄中加入kill-if-jiangshi文件,寫入1如果該進程是僵屍,那麼就調用上述模塊的邏輯殺死它

Copyright © Linux教程網 All Rights Reserved