1

I am trying to add a child process in the foreground process group. After forking I am calling execve() to spawn a new process(In this case the unix echo program). Before calling execve() i am creating a new process group using child's pid. So the child is becoming process leader of that process group. After that I am calling tcsetpgrp() to add the process group in the foreground process group.

When I run the program it hangs in the tcsetpgrp() call. execve() never executes. If I remove tcsetpgrp() call, execve() executes successfully.

Can't understand why this is happening. Following is the code I wrote:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

void pr_ids(char *name){
    pid_t pid, ppid, pgid, tpgid;

    pid = getpid();
    ppid = getppid();
    pgid = getpgrp(); 
    tpgid = tcgetpgrp(STDIN_FILENO);

    printf("%s: pid = %d ppid = %d"
           " pgid = %d tpgid = %d\n", name, pid, ppid, pgid, tpgid);
}

int main(int argc, char *argv[]){
    pid_t pid;
    int st;
    char *args[] = {"/bin/echo", "hello", NULL};

    pr_ids("parent"); 

    if((pid = fork()) == 0){
        setpgid(0, 0);  // creates its own process group and becomes group leader
        pr_ids("child");
        pid_t cpgrp = getpgrp();
        tcsetpgrp(STDIN_FILENO, cpgrp);     // add the process group to foreground
        pr_ids("child");
        execve(args[0], args, NULL); 
    }
    else if(pid > 0){
        waitpid(pid, &st, 0); 
    }

    exit(0);
}

1 Answers1

3

tcsetpgrp() does not add a process to a process group, but sets the foreground process group of the terminal. If tcsetpgrp() is called from a background process group, the calling process (and all the processes in its process group) will get a SIGTTOU signal from the kernel which, unless caught, will stop them.

That's exactly what happens in your example: you're creating another process group, and then calling tcsetpgrp() from within it.

  • If tcsetpgrp() to work, the process group already have to be in the foreground process group then what's tcsetpgrp()'s purpose. What is its use case?

    Quoting from man "The function tcsetpgrp() makes the process group with process group ID pgrp the foreground process group on the terminal associated to fd, which must be the controlling terminal of the calling process"

    Isn't it saying that it makes a process group foreground process group? Also notices what is man page said about background processes, which is exactly what you said. Aren't these two statements ambiguous?

    – Ashfaqur Rahaman May 21 '19 at 19:08
  • the process calling tcsetpgrp() has to be in the fg pgrp, not the pgrp given as argument. And I don't see how making a pgrp the fg one on the terminal is the same thing as adding a process to a process group (which is what you claim in your Q). I don't see anithing ambiguous either in the manpage or in my answer ;-) –  May 21 '19 at 19:23
  • Oh! Actually I thought there is a group called fg process group, which gets all the I/O and signals from the terminal. And tcsetpgrp() can add any random group to fg group. Now I understood which it can but it have to be called from a process which is in fg group. In that case if I want to achieve something like when a new process spawns it will receive all the I/O and signal. Parent will sit in the background waiting for the child to finish. When the child is finished parent will be back in fg. What should be the procedures? – Ashfaqur Rahaman May 21 '19 at 20:42
  • Got my answer in following threads: [1] [2] – Ashfaqur Rahaman May 22 '19 at 20:29