3

I have the following program where I set the parent's process group and the child's process group, as well as giving the terminal control to the parent. Then, I run "cat" in the "background" child, which is supposed to generate SIGTTIN. However, the printf line in sighandler is not printed. Any ideas how to properly detect SIGTTIN in this case?

void sighandler(int signo){
  printf("SIGTTIN detected\n");
}

int main() {


  int status;
  pid_t pid;
  pid = fork ();

  setpgid(0,0);

  tcsetpgrp (STDIN_FILENO, 0);

  signal(SIGTTIN, sighandler);


  if (pid == 0)
    {
      setpgid(0,0);
      execl ("cat", NULL);
      _exit (EXIT_FAILURE);
    }
  else{
    int status;
    setpgid(pid,pid);
    waitpid(-1, &status, 0);
  }
  return status;
}
Mariska
  • 1,913
  • 5
  • 26
  • 43

1 Answers1

3

Mariska,

For Parent Processes

As explained in the Stack Overflow post titled, "Catch Ctrl-C in C,":

The behavior of signal() varies across UNIX versions, and has also 
varied historically across different versions of Linux. Avoid its use: 
use sigaction(2) instead.

As described in the Linux Programmer's Manual, you should use sigaction():

The sigaction() system call is used to change the action taken by a
process on receipt of a specific signal. 

Try this:

#include<stdio.h>
#include <signal.h>


static void handler(int signum)
{
    /* Take appropriate actions for signal delivery */
    printf("SIGTTIN detected\n");
}


int main()
{
    struct sigaction sa;


    sa.sa_handler = handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART; /* Restart functions if
                                 interrupted by handler */
    if (sigaction(SIGINT, &sa, NULL) == -1)
        /* Handle error */;


    /* Further code */
}

For Child Processes

There are a couple of points you should know when dealing with signal handlers for the child processes:

  1. A forked child inherits the signal handlers from the parent
  2. Because of the above, you need to implement some sort of signal handler for the parent and then change the signal handler before and after executing a child.
  3. As explained in the Linux Programmer's Manual:

    All process attributes are preserved during an execve(), except the following:
                 a. The set of pending signals is cleared (sigpending(2)).
                 b. The dispositions of any signals that are being caught are 
                    reset to being ignored.
                 c. Any alternate signal stack is not preserved (sigaltstack(2)).
    

    Thus, the exec() functions do not preserve signal handlers.

From the above, I am trying to show you that pressing Ctrl-C sends the signal to the parent process (unless you use exec()), and then the signals are automatically propagated to children. This is why we need to change the signal handler. Even when the child is currently "active", the parent will still receive signals before the child will.

Please let me know if you have any questions!

Community
  • 1
  • 1
Devarsh Desai
  • 5,984
  • 3
  • 19
  • 21
  • How about detecting SIGTTIN in a child process that tries to read STDIN from a background process per my program above? I cannot seem to detect it even using sigaction.. – Mariska Oct 27 '14 at 11:17
  • hey Mariska, updated! please let me know if you have any questions! – Devarsh Desai Oct 27 '14 at 16:33