我只是试图从运行过程的内核和用户模式中分别理解信号处理的概念。
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)
我想知道内核如何将进程-3的信号发送到进程-1,知道进程-1正在等待进程2完成。希望在信号处理场景(PCB,资源,打开文件描述符等)中了解有关用户和内核通信的更多信息。请解释与此相关的内容..
任何给予的帮助都很感激.. !!!
答案 0 :(得分:1)
内核并不关心进程-1是否“等待进程2完成”(特别是它对“为什么”处于状态不感兴趣,只是它是在某种状态下:在这种情况下,在内核中空闲等待某个事件)。对于典型的 1 捕获信号,信号发送器实质上只是在信号接收器的进程/线程状态中设置一些位,然后在适当的情况下,调度进程/线程运行以便它可以看到那些位。如果接收器在内核中空闲等待某个事件,那就是“运行计划”案例之一。 (其他常见情况包括:接收器处于STOP状态,除了SIGCONT
信号外,它处于停止状态;或者,接收器在用户模式下运行,设置为转换到内核模式以便注意待处理的信号。)
无法捕获或忽略SIGKILL
和SIGSTOP
,因此,不,您无法为这些提供处理程序。 (通常情况下,流程会通过SIGTSTP
,SIGTTIN
或SIGTTOU
进入停止状态,所有都可以被捕获或忽略。)
如果在用户信号处理程序返回后(通过SA_RESTART
的{{1}}标志)将系统调用设置为重新启动,则可以通过设置{{1}的“返回地址”来实现实际上,操作使系统再次调用。也就是说,如果process-1在sigaction()
中,则从初始sigreturn()
点开始,通过接收捕获信号waitpid()
的操作序列(从进程-1的角度来看) ,并回到更多等待,是:
waitpid()
s
设置设置新的信号掩码(请参阅waitpid()
)sigaction()
和sigaction()
)(此时,进程-1重新进入用户模式。其余步骤未编号,因为我无法在9开始启动。:-))
SA_ONSTACK
系统调用,
使用在设置时存储的帧,可能已修改
按用户例程(此时进程进入内核模式,执行sigaltstack()
系统调用)
sigreturn()
:设置sigreturn()
参数sigreturn()
参数(程序现在回到用户模式,寄存器设置为输入sigreturn()
)
sigreturn()
此时,进程返回到收到捕获信号之前的状态:waitpid
使其等待事件进入休眠状态(步骤2)。一旦被唤醒(步骤3),它正在等待的事件已经发生(例如,进程为waitpid()
- 已完成)并且它可以正常返回,或者已经发生了另一个捕获的信号并且它应该重复该序列,或者它被杀死了它应该清理,或者其他什么。
这个序列就是为什么一些系统调用(比如一些waitpid
- 就像系统调用一样)会在信号中断的情况下“早退”:他们在“第一次”进入内核之间做了一些不可逆转的事情和信号处理程序的运行时间。在这种情况下,在步骤6 推送的信号帧不得具有程序计数器值,该值导致整个系统调用重新启动。如果确实如此,那么在该过程进入睡眠状态之前完成的不可逆转的工作将会丢失。因此,它被设置为返回检测成功系统调用的指令,寄存器值设置为返回短waitpid()
计数,或者其他。
当系统调用设置为而非重启(read()
未设置)时,步骤6中推送的信号帧也不同。它返回到检测系统调用失败的指令,而不是返回执行系统调用的指令,寄存器值设置为表示read()
错误。
(通常,但并非总是如此,这些是相同的指令,例如,测试成功/失败的条件分支。在我原来的SPARC端口中,我在大多数情况下使它们成为不同的指令。因为叶子例程返回到{{没有寄存器或堆栈操作,我只是设置一个位,指示成功返回应该返回叶子例程的返回地址。所以大多数系统调用只是“将系统调用号和成功重新标记放入{{1然后陷阱到内核,然后跳转到错误处理,因为如果我们到达这里,系统调用必定已经失败。“)
1 与queued signals对比。