Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/58.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 进程等待另一进程终止时的信号处理_C++_C_Linux_Process_Signals - Fatal编程技术网

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推送的信号帧不得具有导致整个系统调用重新启动的程序计数器值。如果它真的这样做了,那么在这个过程进入睡眠之前所做的不可逆转的功就会丢失。因此,它被设置为返回到检测成功系统调用的指令,寄存器值被设置为返回short
    read()
    count或其他值

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

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


    1对