0

I'm trying to figure out if i can get the signal that terminated a child process using a custom SIGCHLD handler passed to a sigaction with flag set to SA_SIGINFO. From what i understood the si_status should report an exit value or a signal value depending on si_code value.

This is the code for the SIGCHLD handler:

static void sigchdl (int sig, siginfo_t *siginfo, void *context)
{

  int code = siginfo -> si_code, status = siginfo -> si_status;

      if(code == CLD_EXITED) 
      if(WIFEXITED(status)) printf("the background command with PID: %ld                               has been successfull\n,(long)siginfo>si_pid);

      else if(code == CLD_KILLED) {

       //2 = SIGINT, 9 = SIGKILL, 15 = SIGTERM (man signal)

      if(WTERMSIG(status) == 2 || WTERMSIG(status) == 9 || WTERMSIG(status) == 15)

      printf("Il comando in background con PID: %ld e' stato terminato dal segnale %d, chiamato           da: %d\n", (long)siginfo->si_pid, siginfo -> si_status, getpid());

      else

       perror("Command terminated abnormally\n"); 
       
      } 
   
}

Now my question is, first: is it possibile to do it?

Second: if yes, can i do it using si_status and si_code?

  • Does it have to be through the `SIGCHLD` handler? If you use [one of the `wait` functions](https://man7.org/linux/man-pages/man2/wait.2.html) to get the exit status that way, you can use the `WIFSIGNALED` and `WTERMSIG` macros on the exit code. – Some programmer dude Sep 08 '20 at 09:38
  • 2
    I think in general it should work, but you should make sure that you call only signal-safe functions in the signal handler. `printf` is not signal-safe. Why do you treat signals other than 2, 9 and 15 as "abnormal termination"? Instead of using hard coded signal numbers you should use the corresponding macros like `SIGTERM`, `SIGKILL` etc. (Usingsing `waitpid` etc. would be easier.) – Bodo Sep 08 '20 at 09:47
  • If you have multiple child processes, you may not receive signals for all of them as SIGCHLD can be merged if raised a second time before the handler is started. – Simon Richter Sep 08 '20 at 10:13
  • To: Some programmer dude, i prefer using it as i don't need to check the termination trough a cycle, even with WNOHANG. In my newbie opinion using a SIGCHLD handler is a cleaner and better idea. To Bodo, yeah i'll edit the answer using a flag instead of printf as suggested, the var will be checked while the parent inserts the args in prompt, the only problem will be with fg processes because parent waits for the child to end and can't check prompt. I'll figure out a solution. To Simon Richter, i'll take a look about that. Ty all. –  Sep 08 '20 at 12:06

1 Answers1

0

Question resolved.

New snippet:

static void sigchdl (int sig, siginfo_t *siginfo, void *context)
{


  int code = siginfo -> si_code, status = siginfo -> si_status;

      printf("si_code: %d\n", code);
      printf("si_status: %d\n", status);


      if(code == CLD_EXITED) { if(WIFEXITED(status)) printf("Il comando in background con PID: %ld e' terminato normalmente\n",
            (long)siginfo->si_pid); }

      else if(code == CLD_KILLED) {

       //2 = SIGINT, 9 = SIGKILL, 15 = SIGTERM

      if(status == 2 || status == 9 || status == 15)

      printf("Il comando in background con PID: %ld e' stato terminato dal segnale %d, chiamato da: %d\n",
            (long)siginfo->si_pid, siginfo -> si_status, getpid());


      }

      else if(code == CLD_DUMPED) perror("il comando è terminato in modo anormale \n"); 

}

The problem was with the WTERMSIG that resulted to be useless in the contest. Status already hold the signal constant value. si_code check is still necessary to recognize the "terminated by signal" case.

Added CLD_DUMPED code too to recognize the abnormal interrupt of a process.

  • 1
    Do not use `printf()` in signal handlers. See manpage printf(3) - ATTRIBUTES and https://www.gnu.org/software/libc/manual/html_node/POSIX-Safety-Concepts.html – 12431234123412341234123 Sep 08 '20 at 11:29
  • Suggestion on how to inform the user of the ended process? –  Sep 08 '20 at 11:39
  • Set a flag in the signal handler and check the flag before you sleep with `pselect()` or `poll()`. Or use `write()`, which can be called in a signal handler but that mixes up with the buffer from the `` functions. (AFAIK It is allowed and does not cause UB but you may get a result you do not expect.) – 12431234123412341234123 Sep 08 '20 at 11:43
  • I was looking at write(), but yeah i think i'll fire an alarm and set a flag. Ty! –  Sep 08 '20 at 11:48