子C程序和父C程序中的SIGSEGV处理

7lrncoxx  于 2022-09-21  发布在  Unix
关注(0)|答案(2)|浏览(237)

下面提到的是我的C++程序。当子进程或父进程中的任何一个内部产生分段故障信号时,我想要终止所有子进程和父进程。

我从Linux内核得到的SigTerm信号正在到达Handle_Signal函数。但我在后面的流程中遇到了问题,在调试时,我甚至看到gSegSignalRcvd=1也被设置了。但是,进程控制没有到达父子节点中的任何for循环。


# include<iostream>

# include<stdio.h>

# include<sys/types.h>

# include<unistd.h>

# include<signal.h>

bool gSignalRcvd = 0;
bool gSegSignalRcvd = 0;

pid_t lCid1;
pid_t lCid2;
pid_t lPid;

void handle_signal(int sig)
{
  switch(sig)
  {
    case SIGSEGV:
    {
        gSegSignalRcvd = 1;
        printf("Reecived Signal:%d SegSignal:%dn", gSignalRcvd, gSegSignalRcvd);
    }
    default:
        printf("Reecived Signal :%dn",sig);
  };
  gSignalRcvd = 1;
  signal(SIGSEGV, handle_signal);
}

int main()
{
  signal(SIGSEGV, handle_signal);

  lCid1 = fork();

  if(lCid1 < 0)
  {
      printf("Error in child Creation Err:%dn", lCid1);
      exit(1);
  }
  else if(lCid1 > 0)
  {
      lCid2 = fork();

      if(lCid2 < 0)
      {
          printf("Error in child Creation Err:%dn", lCid1);
          exit(2);
      }
      else if(lCid2 > 0)
      {
          struct tm * lTimePtr;
          int    lSleepTime=0;
          int    mUploadTime=0;
          int    lCount = 1;
          time_t lTimeObj;

          for(;;)
          {
              lCount = lCount++;
              printf("Received Signal @ Parent Seg:%d Sig%dn", gSegSignalRcvd, gSignalRcvd);
              if(gSignalRcvd)
              {
                  if(gSegSignalRcvd)
                  {
                    printf("Received Signal Inside Parent now killing the Processn");
                    kill(lCid1, SIGTERM);
                    kill(lCid2, SIGTERM);
                    kill(getpid(), SIGTERM);
                  }
              }
              gSignalRcvd = 0;

              printf("Time:%ld tm_min:%d tm_sec:%d UploadTime:%d SleepTime:%dn", lTimeObj, lTimePtr->tm_min, lTimePtr->tm_sec, mUploadTime, lSleepTime);

              sleep(mUploadTime + lCount);
          }
      }
      else
      {
          int lNumb,lResult;

          for(;;)
          {
              printf("Received Signal @ Child2 Seg:%d Sig%dn", gSegSignalRcvd, gSignalRcvd);
              if(gSignalRcvd)
              {
                  if(gSegSignalRcvd)
                  {
                      printf("Received Signal Inside Child2**************n");
                      kill(lCid1, SIGTERM);
                      kill(lCid2, SIGTERM);
                      kill(getpid(), SIGTERM);
                  }
              }
              gSignalRcvd = 0;
              printf("Printing the Child2 Valuen");
              lNumb = rand() / 100;

              lResult = lNumb / 2;
              printf("Number:%s Result:%dn", lNumb, lResult);

              usleep(lNumb);
          }
      }
  }
  else
  {
      for(;;)
      {
          printf("Received Signal @ Child1 Seg:%d Sig%dn", gSegSignalRcvd, gSignalRcvd);
          if(gSignalRcvd)
          {
              if(gSegSignalRcvd)
              {
                  printf("Received Signal Inside Child1 ---------------n");
                  kill(lCid1, SIGTERM);
                  kill(lCid2, SIGTERM);
                  kill(getpid(), SIGTERM);
              }
          }
          gSignalRcvd = 0;

          printf("Printing the Child1 Valuen");
          usleep(rand());
      }
  }
  return 0;
}
----------- Program OutPut ---------
[scuser@Bilx-Congo-Lab ~]$ ./sigHandle
Received Signal @ Child1 Seg:0 Sig0
Printing the Child1 Value
Received Signal @ Child2 Seg:0 Sig0
Printing the Child2 Value
Number:Reecived Signal:0 SegSignal:1
Reecived Signal :11
Reecived Signal:1 SegSignal:1
Reecived Signal :11
Reecived Signal:1 SegSignal:1
Reecived Signal :11
Reecived Signal:1 SegSignal:1
Reecived Signal :11
Reecived Signal:1 SegSignal:1
Reecived Signal :11
Reecived Signal:1 SegSignal:1
Reecived Signal :11
Reecived Signal:1 SegSignal:1
Reecived Signal :11
Reecived Signal:1 SegSignal:1
Reecived Signal :11
Reecived Signal:1 SegSignal:1
Reecived Signal :11
Reecived Signal:1 SegSignal:1
Reecived Signal :11
Reecived Signal:1 SegSignal:1
Reecived Signal :11
Reecived Signal:1 SegSignal:1
Reecived Signal :11
Reecived Signal:1 SegSignal:1
Reecived Signal :11
Reecived Signal:1 SegSignal:1
Reecived Signal :11
Reecived Signal:1 SegSignal:1
Reecived Signal :11
Reecived Signal:1 SegSignal:1
Reecived Signal :11
Reecived Signal:1 SegSignal:1
Reecived Signal :11
Reecived Signal:1 SegSignal:1
Reecived Signal :11
Reecived Signal:1 SegSignal:1
Reecived Signal :11
Reecived Signal:1 SegSignal:1
Reecived Signal :11
Reecived Signal:1 SegSignal:1
Reecived Signal :11
Reecived Signal:1 SegSignal:1
Reecived Signal :11
Reecived Signal:1 SegSignal:1
Reecived Signal :11
Reecived Signal:1 SegSignal:1
Reecived Signal :11
Reecived Signal:1 SegSignal:1
Reecived Signal :11
Reecived Signal:1 SegSignal:1
Reecived Signal :11
Reecived Signal:1 SegSignal:1
Reecived Signal :11
Reecived Signal:1 SegSignal:1
Reecived Signal :11
Reecived Signal:1 SegSignal:1
Reecived Signal :11
Reecived Signal:1 SegSignal:1
Reecived Signal :11
Reecived Signal:1 SegSignal:1
Reecived Signal :11
Reecived Signal:1 SegSignal:1
Reecived Signal :11
Reecived Signal:1 SegSignal:1
Reecived Signal :11
Reecived Signal:1 SegSignal:1
Reecived Signal :11
Reecived Signal:1 SegSignal:1
Reecived Signal :11
Reecived Signal:1 SegSignal:1
Reecived Signal :11
Reecived Signal:1 SegSignal:1
Reecived Signal :11
Reecived Signal:1 SegSignal:1
Reecived Signal :11
Reecived Signal:1 SegSignal:1
Reecived Signal :11
Reecived Signal:1 SegSignal:1
Reecived Signal :11
Reecived Signal:1 SegSignal:1
Reecived Signal :11
Reecived Signal:1 SegSignal:1
Reecived Signal :11
Reecived Signal:1 SegSignal:1
bxjv4tth

bxjv4tth1#

将所有进程放在它们自己的进程组中,然后当任何成员获得SEGV时,向整个组发送SIGTERM。

在父级中,在任何分叉之前:

pid_t gPGid;
volatile sig_atomic_t gSegSignalRcvd = 0;

... main() ...
setpgid(0, 0);       // Make new process group, if needed
gPGid = getpgid(0);

然后,在处理程序中,向整个进程组发送信号:

void handler(int sig) {
  if (sig == SIGSEGV) {
    kill(-gPGid, SIGTERM);     // Note the -gPGid here
    _exit(1);                  // We segfaulted - we'd better quit now
  } else if (sig == SIGTERM) {
    gSegSignalRcvd = 1;
  }
  ...
}

实际上,_exit()可能达不到,因为进程组SIGTERM也会中断生成它的程序。

几点备注:不要使用signal()和在处理程序中重新安装处理程序的过时约定-使用sigaction()。不要在处理程序-that's not safe中调用printf()。你的“旗帜”布尔值可能应该是volatile sig_atomic_t类型。

vbkedwbf

vbkedwbf2#

您的问题是,一旦信号得到处理,流程就会返回到有问题的代码,从而再次生成分段错误。

更简单的方法是让您的信号处理程序执行子对象的e1d0d1,然后是exit()abort()

或者,siglongjmp()或将上下文切换到安全位置(如this answer所示,尽管我建议您使用makecontext()而不是处理特定于平台的寄存器)。

相关问题