C++ 进程等待另一进程终止时的信号处理
我只是试图理解信号处理的概念,分别从内核模式和运行进程的用户模式C++ 进程等待另一进程终止时的信号处理,c++,c,linux,process,signals,C++,C,Linux,Process,Signals,我只是试图理解信号处理的概念,分别从内核模式和运行进程的用户模式 PROCESS-1 --------------------> PROCESS-3 (parent process) <------------------- ^ process-3 sending signals(SIGPIPE-for communication) or ||
PROCESS-1 --------------------> PROCESS-3
(parent process) <-------------------
^ process-3 sending signals(SIGPIPE-for communication) or
|| SIGSTOP or SIGKILL to process-1
||
||
||process-1 waiting for child process-2
|| using waitpid command.
||
v
PROCESS-2(waiting for resource, page fault happened, etc)
(child process)
PROCESS-1----------------->PROCESS-3
(父进程)内核并不真正关心进程1是否在“等待进程2完成”(特别是它不关心“为什么”它处于它所处的状态,只关心它处于某种状态:在本例中,它在内核中空闲等待某个事件)。对于典型的1捕获信号,信号发送器基本上只是在信号接收器的进程/线程状态中设置一些位,然后如果合适,安排该进程/线程运行,以便它可以看到这些位。如果接收器在内核中空闲等待某个事件,这就是“调度运行”情况之一。(其他常见情况包括:接收器处于停止状态,除了SIGCONT
信号外,接收器保持停止状态;或者,接收器在用户模式下运行,设置为转换到内核模式,以便注意挂起的信号。)
不能捕获或忽略SIGKILL
和SIGSTOP
,因此,不,您不能为它们提供处理程序。(通常,进程通过SIGTSTP
、SIGTTIN
或SIGTTOU
进入停止状态,所有这些都可以捕获或忽略。)
如果系统调用设置为在用户信号处理程序返回后重新启动(通过sigaction()
的SA_restart
标志),则可以通过设置sigreurn()
操作的“返回地址”来实现,实际上,可以重新进行系统调用。也就是说,如果进程1处于waitpid()
,则从初始的waitpid()
到接收捕获的信号s
,再返回到更多等待的操作顺序(从进程1的角度来看)为:
系统调用:waitpid()
让自己在等待事件时入睡
唤醒:检查唤醒事件
事件是信号,信号被捕获,因此:
根据sigaction()
设置设置新的信号掩码(请参见sigaction()
)
将信号框推到堆栈上(请参见sau ONSTACK
和sigaltstack()
)
设置用户代码(程序计数器)以进入“信号蹦床”
返回用户代码(进入蹦床)
(此时process-1已返回用户模式。其余步骤未编号,因为我无法从9开始进行编号。:-)
- 调用用户处理程序例程(仍在上面选择的堆栈上)
- 当用户例程返回时,执行
sigreurn()
system调用,
使用安装时存储的帧,可能已修改
按用户例程
(此时进程进入内核模式,执行sigreurn()
system调用)
- 系统调用:
sigreurn()
:设置由sigreurn()
参数指定的信号掩码
- 设置其他寄存器,包括堆栈指针和
程序计数器,由
sigreurn()
参数指定
- 返回到用户代码
(程序现在回到用户模式,寄存器设置为进入waitpid
)
系统调用:waitpid()
此时,进程返回到接收到捕获信号之前的状态:waitpid
将其置于睡眠状态,等待事件发生(步骤2)。一旦被唤醒(步骤3),或者它等待的事件已经发生(例如,waitpid()
-ed正在进行的进程已经完成),并且它可以正常返回,或者另一个捕获到的信号已经发生,并且它应该重复这个序列,或者它正在被终止,并且应该清理,或者诸如此类
这就是为什么一些系统调用(例如一些read()
-类似系统调用)在被信号中断时会“提前返回”的原因:它们在“第一次”进入内核和运行信号处理程序之间做了一些不可逆的事。在这种情况下,在步骤6推送的信号帧不得具有导致整个系统调用重新启动的程序计数器值。如果它真的这样做了,那么在这个过程进入睡眠之前所做的不可逆转的功就会丢失。因此,它被设置为返回到检测成功系统调用的指令,寄存器值被设置为返回shortread()
count或其他值
当系统调用设置为不重新启动时(SA_restart
未设置),在步骤6中推送的信号帧也不同。它不返回执行系统调用的指令,而是返回检测失败的系统调用的指令,寄存器值设置为指示EINTR
错误
(通常,但并非总是如此,它们是相同的指令,例如,用于测试成功/失败的条件分支。在我最初的SPARC端口中,我在大多数情况下为它们制作了不同的指令。由于叶例程返回到%o6+8
,而没有寄存器或堆栈操作,我只设置了一个位,指示成功返回到e leaf例程的返回地址。因此大多数系统调用只是“将syscall number和ret on success标志放入%g1
,然后陷阱到内核,然后跳转到错误处理,因为如果我们到达这里,系统调用一定失败了。”)
1对