2

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
Peter
  • 14,559
  • 35
  • 55
VPK
  • 23
  • 1
  • 4
  • What's with the random sleep durations, and the sleep which increases in length? At least of these has you sleeping for half an hour. Plus a bunch of errors: You don't need to re-run `signal` in the handler. You're trying to kill processes with pid==0, since you're using the return value of fork in the child. Your printf has a string format but an integer argument. Clean it all up and try again. – Peter Sep 12 '13 at 13:40
  • signal removes the handler after it's triggered (see man signal) - so yes, he needs to rerun it (although IMHO it's not good to do this in handler itself (edit: nope, man 7 signal says you can call signal from handler)). – zoska Sep 12 '13 at 14:15
  • Oi. This issue looks very complicated. Whether `signal()` resets the handler or not depends on the system. Original UNIX/SystemV: handler reset. BSD: not reset. Linux: it depends, but recent versions provide BSD semantics. Basically, switch to POSIX `sigaction()` instead for more portable behavior, as recommended by `man 2 signal` on Linux – Peter Sep 12 '13 at 14:26
  • @Peter, Hi, firstly i used sleep using rand just to differentiate the process flow of each child's & parent process. so that debugging bcom's easier,else i need to got thru lot of printf's. And i'm trying to generate Segmentation fault so only i'm trying to print string from integer variable. And More over i know under pid == 0, the child will be kill'd & later the information will be passed onto Parent also,but i wanted to make sure the child & parent both are killed. That's the reason why i used pid's of all Child's & parent within each for loop. – VPK Sep 13 '13 at 04:41

2 Answers2

2

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.

pilcrow
  • 56,591
  • 13
  • 94
  • 135
  • Hi, earlier i had tried by using kill(0, SIGTERM) in each child & parent process. However all child's & parent of this process were killed along with these, some other process's not related to this process where also getting killed bcos of usage of kill(0, SIGTERM) in parent. what i understood from this was due to default assignment of groupId = 1 to all process's running for same user were getting killed. So can u show me an example for generating different Pid for above mentioned process only,so that other process will not be affected. – VPK Sep 13 '13 at 04:50
1

Your problem is that once the signal is handled, flow returns to the offending code which again generates a segmentation fault.

The easier way out of this is to have your signal handler do the kill()ing of the children, then exit() or abort().

Alternately, siglongjmp() or switch context to a safe place (as shown in this answer, though I suggest you use makecontext() instead of dealing with platform specific registers.).

Community
  • 1
  • 1
Hasturkun
  • 35,395
  • 6
  • 71
  • 104