我正在寻找一种让子进程知道其父进程(启动程序/监视程序进程)过早死亡的方法,我认为用prctl设置死亡信号是解决我的问题的完美方法。
这是我的启动功能的主要结构。我确实去除了所有额外的管理工作并记录了日志,以使代码简短而不受干扰。
void MonitoredChild::Launch()
{
const std::string PathToExe( (boost::filesystem::current_path() / this->BookOfLife.ExeName ).string() );
pid_t ParentIdBeforeFork = getpid();
pid_t NewChildID = fork();
switch ( NewChildID )
{
case -1: //failed to create child
{
break;
}
case 0: //Child comes here.
{
//Reset SIGCHLD, child process should not handle this signal.
signal( SIGCHLD, SIG_DFL );
//Set things up with the kernel that we want to be signalled
// in case the parent dies.
int ret( prctl( PR_SET_PDEATHSIG, SIGUSR1 ) );
if ( ret == -1 )
{
exit(1);
}
//Check if our parent has not died while setting this up:
if ( getppid() != ParentIdBeforeFork )
{
exit(1);
}
//Ready, steady, go!
execlp( PathToExe.c_str(), PathToExe.c_str(), this->BookOfLife.Arguments.c_str(), (char*)NULL );
//exec() never returns on success and thus should never reach the next line of code!
exit(1);
}
default: //Parent comes here.
{
break;
}
}
}
当我从命令行手动运行启动器程序时,这确实像超级按钮一样工作。如果我强行杀死发射器,信号会发送给孩子们,一切都会按照预期死亡。
但是,当我将程序作为守护程序运行时,这会改变。我使用SUID位来防止程序在使用init脚本启动后以root用户身份运行。现在,每当我从该启动程序中派生一个新孩子时,该孩子将在执行时失去先前配置的死亡信号。现在,问题是为什么? prctl的手册页在SUID程序上指出以下内容:
This value is cleared for the child of a fork(2) and (since Linux 2.4.36 / 2.6.23) when executing a set-user-ID or set-group-ID binary.
execve的页面对此进行了说明:
(Since Linux 2.4.36 / 2.6.23) If a set-user-ID or set-group-ID program is being executed, then the parent death signal set by prctl(2) PR_SET_PDEATHSIG flag is cleared.
但是,孩子不是不是 SUID程序!而且我只在孩子本身中设置了死亡信号,因此fork()无法清除该信号。那么为什么仍然清除死亡信号呢?