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