0

我只是想从内核和用户模式分别了解正在运行的进程的信号处理概念。

           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、资源、打开文件描述符等)期间用户和内核通信的信息。请解释与此上下文相关的内容..

给予任何帮助表示感谢..!!!

4

1 回答 1

1

内核并不真正关心 process-1 是否“等待 process-2 完成”(特别是它对“为什么”它处于当前状态不感兴趣,只是它处于某种状态:在这种情况下,在内核中空闲等待某个事件)。对于典型的1捕获信号,信号发送方基本上只是在信号接收方的进程/线程状态中设置一些位,然后如果合适,安排该进程/线程运行以便它可以看到这些位。如果接收器在内核中空闲等待某个事件,那就是“调度运行”的情况之一。(其他常见情况包括:接收器处于 STOP 状态,除SIGCONT信号;或者,接收器在用户模式下运行,它被设置为转换到内核模式,以便注意待处理的信号。)

两者都不能被捕获或忽略SIGKILLSIGSTOP所以,不,你不能为这些提供处理程序。(通常进程通过SIGTSTPSIGTTIN或进入停止状态SIGTTOU,所有这些都可以被捕获或忽略。)

如果系统调用被设置为在用户信号处理程序返回后重新启动(通过 的SA_RESTART标志sigaction()),这是通过为操作设置“返回地址”来实现的sigreturn(),实际上是重新进行系统调用。也就是说,如果 process-1 在 中,则从初始 的点到接收到捕获的信号,然后返回到更多等待waitpid()的操作序列(从 process-1 的角度来看)是:waitpid()s

  1. 系统调用:waitpid()
  2. 让自己入睡等待事件
  3. 唤醒:检查唤醒事件
  4. 事件是信号并且信号被捕获,所以:
  5. 为每个sigaction()设置设置新的信号掩码(请参阅sigaction()
  6. 将信号帧推入堆栈(参见SA_ONSTACKsigaltstack()
  7. 设置用户代码(程序计数器)进入“信号蹦床”
  8. 返回用户代码(进入蹦床)

(此时 process-1 又回到了用户模式。剩下的步骤没有编号,因为我不能让 SO 从 9 开始。:-))

  • 调用用户处理程序例程(仍在上面选择的堆栈上)
  • 当用户例程返回时sigreturn(),使用设置时存储的帧执行系统调用,可能由用户例程修改

(此时进程进入内核态,执行sigreturn()系统调用)

  • 系统调用::设置参数sigreturn()指定的信号掩码sigreturn()
  • 设置其他寄存器,包括堆栈指针和程序计数器,由sigreturn()参数指定
  • 返回用户代码

(程序现在回到用户模式,寄存器设置为 enter waitpid

  1. 系统调用:waitpid()

此时,进程返回到接收到捕获信号之前的相同状态:waitpid使其进入睡眠状态以等待事件(步骤 2)。一旦被唤醒(步骤 3),它等待的事件已经发生(例如,正在执行的进程waitpid()已完成)并且它可以正常返回,或者另一个捕获的信号已经发生并且它应该重复这个序列,或者它正在被被杀了,它应该清理,或者其他什么。

这个顺序就是为什么一些系统调用(例如一些类似read()的系统调用)如果被信号中断会“提前返回”:它们在“第一次”进入内核和信号处理程序的时间之间做了一些不可逆的事情。运行。在这种情况下,在第 6 步推送的信号帧不得具有导致整个系统调用重新启动的程序计数器值。如果是这样,那么在进程进入睡眠状态之前完成的不可逆转的工作将会丢失。因此,它被设置为返回检测到成功的系统调用的指令,寄存器值设置为返回短read()计数,或其他。

当系统调用设置为重启(SA_RESTART未设置)时,第6步推送的信号帧也不同。它不是返回到执行系统调用的指令,而是返回到检测到失败的系统调用的指令,并设置寄存器值以指示EINTR错误。

(通常,但并非总是如此,这些指令是相同的,例如,用于测试成功/失败的条件分支。在我最初的 SPARC 端口中,我在大多数情况下为它们制作了不同的指令。因为叶例程返回%o6+8时没有寄存器或堆栈操作,我只是设置了一点指示成功返回应该返回叶例程的返回地址。所以大多数系统调用只是“将系统调用号和 ret-on-success 标志放入%g1,然后陷阱到内核,然后跳转到-错误处理,因为如果我们到达这里,系统调用肯定失败了。”)


1排队信号

于 2013-08-22T21:30:34.940 回答