简体   繁体   English

进程正在等待另一个进程终止时的信号处理

[英]signal handling when process is waiting for another process to terminate

I am just trying to understand the concept of signal handling with respective from kernel and user mode for the running process. 我只是想了解运行过程的内核和用户模式下信号处理的概念。

           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)

I want to know how kernel sends the signal from process-3 to process-1 knowing that process-1 is waiting for process-2 to finish. 我想知道内核是如何等待进程2完成的,所以我想知道内核如何将信号从进程3发送到进程1。 Would like to know more about the user and kernel communication during the signal handling scenario(PCB,resources,open file descriptors etc.). 在信号处理场景(PCB,资源,打开文件描述符等)期间,想了解有关用户和内核通信的更多信息。 Please explain related to this context.. 请说明与此相关的上下文。

Any help given is thankful..!!! 给予的任何帮助都是感激.. !!!

The kernel doesn't really care that process-1 is "waiting for process-2 to finish" (in particular it's not interested in "why" it's in the state it is, merely that it is in some state: in this case, idling in the kernel waiting for some event). 内核并不真正关心的是过程-1是“等待过程2结束”(特别是不感兴趣的“为什么”它在它是国家的,只不过它在一些状态:在这种情况下,在内核中空闲以等待某些事件)。 For typical 1 caught signals, the signal-sender essentially just sets some bit(s) in the signal-receiver's process/thread state, and then if appropriate, schedules that process/thread to run so that it can see those bits. 对于典型的1个捕获信号,信号发送者实际上只是在信号接收器的进程/线程状态中设置一些位,然后在适当的情况下调度该进程/线程运行,以便可以看到这些位。 If the receiver is idling in the kernel waiting for some event, that's one of the "schedule to run" cases. 如果接收器在内核中等待某个事件而处于空闲状态,则这是“计划运行”情况之一。 (Other common situations include: the receiver is in STOP state, where it stays stopped except for SIGCONT signals; or, the receiver is running in user mode, where it is set up to transition to kernel mode so as to notice the pending signals.) (其他常见情况包括:接收器处于STOP状态,除SIGCONT信号外,其保持停止状态;或者,接收器在用户模式下运行,将其设置为过渡到内核模式,以便注意到未决信号。 )

Both SIGKILL and SIGSTOP cannot be caught or ignored, so, no, you cannot provide a handler for these. SIGKILLSIGSTOP都不能被捕获或忽略,因此,不能,您不能为它们提供处理程序。 (Normally processes are put into stop state via SIGTSTP , SIGTTIN , or SIGTTOU , all of which can be caught or ignored.) (通常,可以通过SIGTSTPSIGTTINSIGTTOU将进程置于停止状态,所有这些可以捕获或忽略。)

If system calls are set to restart after a user signal handler returns (via the SA_RESTART flag of sigaction() ), this is achieved by setting up the "return address" for the sigreturn() operation to, in fact, make the system call over again. 如果将系统调用设置为在用户信号处理程序返回后重新启动(通过sigaction()SA_RESTART标志),则可以通过为sigreturn()操作设置“返回地址”来实现,从而进行系统调用再次。 That is, if process-1 is in waitpid() , the sequence of operations (from process-1's point of view) from the point of the initial waitpid() , through receiving a caught signal s , and back to more waiting, is: 也就是说,如果process-1在waitpid() ,则从初始waitpid()的点开始waitpid()通过接收捕获的信号s并返回到更多等待waitpid()的操作序列(从process-1的角度来看)为:

  1. system call: waitpid() 系统调用: waitpid()
  2. put self to sleep waiting for an event 让自己入睡等待事件
  3. awakened: check for awakening event 唤醒:检查唤醒事件
  4. event is signal and signal is caught, so: 事件是信号,并且捕获了信号,因此:
  5. set new signal mask per sigaction() settings (see sigaction() ) 根据sigaction()设置设置新的信号掩码(请参阅sigaction()
  6. push signal frame on a stack (see SA_ONSTACK and sigaltstack() ) 在堆栈上推送信号帧(请参阅SA_ONSTACKsigaltstack()
  7. set up for user code (program counter) to enter at "signal trampoline" 设置用户代码(程序计数器)以在“信号蹦床”处输入
  8. return to user code (into trampoline) 返回用户代码(进入蹦床)

(At this point process-1 is back in user mode. The remaining steps are not numbered because I can't make SO start at 9. :-) ) (此时,process-1返回到用户模式。剩余的步骤没有编号,因为我无法使SO从9开始。:-)

  • call user handler routine (still on stack chosen above) 调用用户处理程序例程(仍在上面选择的堆栈上)
  • when user routine returns, execute sigreturn() system call, using the frame stored at setup time, possibly modified by user routine 当用户例程返回时,使用设置时存储的帧(可能由用户例程修改sigreturn()执行sigreturn()系统调用

(At this point the process enters kernel mode, to execute sigreturn() system call) (此时,进程进入内核模式,以执行sigreturn()系统调用)

  • system call: sigreturn() : set signal mask specified by sigreturn() argument 系统调用: sigreturn() :设置由sigreturn()参数指定的信号掩码
  • set other registers, including stack pointer(s) and program counter, as specified by sigreturn() arguments 设置其他寄存器,包括sigreturn()参数指定的堆栈指针和程序计数器
  • return to user code 返回用户代码

(the program is now back in user mode, with registers set up to enter waitpid ) (该程序现在返回到用户模式,已设置寄存器以输入waitpid

  1. system call: waitpid() 系统调用: waitpid()

At this point the process returns to the same state it had before it received the caught signal: waitpid puts it to sleep waiting for an event (step 2). 此时,进程返回到接收到捕获信号之前的状态: waitpid将其置于睡眠状态以等待事件(步骤2)。 Once awakened (step 3), either the event it was waiting for has occurred (eg, the process being waitpid() -ed is done) and it can return normally, or another caught signal has occurred and it should repeat this sequence, or it is being killed and it should clean up, or whatever. 一旦唤醒(步骤3),要么发生了它正在等待的事件(例如,完成了被waitpid() ed处理的过程),它可以正常返回,或者另一个捕获到的信号已经发生,并且应该重复此序列,或者它正在被杀死,应该清理,或者其他。

This sequence is why some system calls (such as some read() -like system calls) will "return early" if interrupted by a signal: they've done something irreversible between the "first" entry into the kernel and the time the signal handler is to be run. 这个顺序就是为什么某些系统调用(例如某些类似read()的系统调用)在被信号中断的情况下会“提前返回”的原因:它们在“第一次”进入内核和信号时间之间做了不可逆的操作处理程序将要运行。 In this case, the signal frame pushed at step 6 must not have a program-counter value that causes the entire system call to restart. 在这种情况下,在步骤6推送的信号帧一定不能具有导致整个系统调用重新启动的程序计数器值。 If it did, the irreversible work done before the process went to sleep would be lost. 如果这样做的话,在该过程进入睡眠之前完成的不可逆的工作将会丢失。 So, it is instead set up to return to the instruction that detects a successful system call, with the register values set up to return the short read() count, or whatever. 因此,将其设置为返回到检测到成功的系统调用的指令,并且将寄存器值设置为返回短的read()计数或任何其他值。

When system calls are set up not to restart ( SA_RESTART is not set), the signal frame pushed in step 6 is also different. 当设置了重新启动系统调用(未设置SA_RESTART )时,在步骤6中推送的信号帧也不同。 Instead of returning to the instruction that executes the system call, it returns to the instruction that detects a failed system call, with the register values set up to indicate an EINTR error. 它没有返回执行系统调用的指令,而是返回检测失败的系统调用的指令,并设置了指示EINTR错误的寄存器值。

(Often, but not always, these are the same instruction, eg, a conditional branch to test for success/fail. In my original SPARC port, I made them different instructions in most cases. Since leaf routines return to %o6+8 with no register or stack manipulation, I just set a bit indicating that a successful return should return to the leaf routine's return address. So most system calls were just "put syscall number and ret-on-success flag into %g1 , then trap to kernel, then jump-to-error-handling because the system call must have failed if we got here.") (通常但并非总是如此,这些指令是相同的,例如,条件分支以测试是否成功。在我最初的SPARC端口中,大多数情况下我将它们指定为不同的指令。由于叶子例程使用以下命令返回%o6+8没有寄存器或堆栈操作,我只是设置了一个指示成功返回的位,应该返回到叶例程的返回地址。因此,大多数系统调用只是将“ syscall号和ret-on-success标记放入%g1 ,然后捕获到内核中,然后跳转到错误处理,因为如果到达这里,系统调用肯定失败。”)


1 Versus queued signals . 1排队的信号

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM