Search code examples
c++unixsignals

SIGSEGV handling in child & parent C program


Below Mentioned is my C++ Program. I want to kill all Child's & Parent Process,when Segmentation fault signal is generated internally in any of child or Parent.

I'm getting from linux kernel sigterm signal is reaching handle_signal function. But i'm stuck with in later flow,when debugged i see even gSegSignalRcvd=1 is set. But the process control is not reaching any of the for loops in child r parent.


#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:%d\n", gSignalRcvd, gSegSignalRcvd);
    }
    default:
        printf("Reecived Signal :%d\n",sig);
  };
  gSignalRcvd = 1;
  signal(SIGSEGV, handle_signal);
}

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

  lCid1 = fork();

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

      if(lCid2 < 0)
      {
          printf("Error in child Creation Err:%d\n", 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%d\n", gSegSignalRcvd, gSignalRcvd);
              if(gSignalRcvd)
              {
                  if(gSegSignalRcvd)
                  {
                    printf("Received Signal Inside Parent now killing the Process\n");
                    kill(lCid1, SIGTERM);
                    kill(lCid2, SIGTERM);
                    kill(getpid(), SIGTERM);
                  }
              }
              gSignalRcvd = 0;

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

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

          for(;;)
          {
              printf("Received Signal @ Child2 Seg:%d Sig%d\n", 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 Value\n");
              lNumb = rand() / 100;

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

              usleep(lNumb);
          }
      }
  }
  else
  {
      for(;;)
      {
          printf("Received Signal @ Child1 Seg:%d Sig%d\n", 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 Value\n");
          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

Solution

  • Put all processes in their own process group, then send a SIGTERM to the whole group when any member gets a SEGV.

    In the parent, before any forking:

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

    Then, in the handler, signal the entire process group:

    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;
      }
      ...
    }
    

    In practice, that _exit() may not be reached, since the SIGTERM to the process group will interrupt the program that generated it, too.

    A few remarks: don't use signal() and the dated convention of re-installing handlers within handlers — use sigaction() instead. Don't call printf() within your handler — that's not safe. Your "flag" booleans probably ought to be volatile sig_atomic_t types.