歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux基礎 >> Linux教程

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