我們都知道在Linux上孤兒進程和殭屍進程都會被進程號爲1的init進程收養,收屍,但這在使用Systemd來管理系統的發行版上比如Ubuntu上就不是那麼靠譜了
首先我們寫一個簡單的孤兒進程的例子
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
int
main(void)
{
switch(fork()){
case 0:
printf("Child process\n");
printf("child process: %d\n", getpid());
printf("father pid:%d\n", getppid());
sleep(5);
printf("\nnow pid: %d\t ppid:%d \n",getpid(),getppid());
break;
case -1:
printf("Fork failed");
exit(-1);
default:
printf("Father Process\n");
sleep(1);
printf("Father exit\n");
break;
}
return 0;
}
首先我們在圖像界面上僞終端中運行
發現孤兒進程會被進程號爲1391的systemd進程收養,而不是pid爲1的systemd進程
然後我們在終端中運行該例子,發現成功父進程成功變爲1
很顯然問題應該時出在systemd上面,查看源碼可以發現在systemd中調用了prctl()系統調用
systemd源碼src/core/main.c
現在看一下Linux中特有的系統調用prctl( )
#include <sys/prctl.h>
int prctl(int option, unsigned long arg2, unsigned long arg3,
unsigned long arg4, unsigned long arg5);
option參數指示prctl如何操作進程
PR_SET_CHILD_SUBREAPER爲內核3.4版本中新增的選項
第二個參數若爲非零時,調用進程設置'child subreaper'屬性
第二個參數若爲零則取消該屬性
詳細參數可以查看The Linux man-pages project
孤兒進程成會被祖先中距離最近的supreaper進程收養
現在我們使用自己的進程來收養他後代的孤兒進程
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<linux/prctl.h>
void descendant_process(void);
int
main(void)
{
prctl(PR_SET_CHILD_SUBREAPER,1);
//設置的child subreaper不會被繼承
switch(fork()){
case 0:
descendant_process();
break;
case -1:
printf("Fork failed");
exit(-1);
default:
printf("Subreaper Process:%d\n",getpid());
sleep(1);
for(;;);
}
return 0;
}
void
descendant_process(void)
{
switch(fork()){
case 0:
printf("Child process\n");
printf("child process: %d\n", getpid());
printf("father pid:%d\n", getppid());
sleep(5);
printf("now pid: %d\t ppid:%d \n",getpid(),getppid());
break;
case -1:
printf("Fork failed");
exit(-1);
default:
printf("Father Process\n");
sleep(1);
printf("Father exit\n");
break;
}
return;
}
成功收養~