Shubs
Shubs

Reputation: 90

Only one child out of the many children die and the rest wait for ctrl + c

I am writing code for a shell in C in Linux, where I have to implement multiple pipes (for eg. A | B | c | D where A, B, C, D are commands). The shell creates an individual process for each command with the same pgid and connects their input and outputs using pipe() syscall. Once all the children are created, the parent makes this pgid to come to the foreground using tcsetpgrp() and goes to the background. Everything works but for the fact that once the children executing A, B, C, D finish, only child1 handling A dies and gets handled by the sigchild handler and the other children just wait and do nothing till I press ctrl + c. Once ctrl + c is pressed, all the other children get reaped by the signal handler and the parent which is in sigsuspend wakes up and comes back to foreground again.

Can anyone please help me in understanding why only Child 1 dies and where the control is while the other children don't finish?

Here is the code for SIGINT handler.

void sigchld_handler(int s) {

int olderrno = errno;
sigset_t mask_all;
sigset_t prev_all;

sigfillset(&mask_all);
while ((pid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) {
    sigprocmask(SIG_BLOCK, &mask_all, &prev_all);
    NoOfChildrenToBeReaped--;
    sigprocmask(SIG_SETMASK, &prev_all, NULL);
}
errno = olderrno;

}

Here is the code for the parent after it creates the required number of children.

//Get the pid of the first child and set it as the pgid of all the sibling children.
if (i == 0) {
    pgid = pid;
}
setpgid(pid, pgid);

And here is the process where the parent goes to the background, keeps a track of how many children are to be reaped yet, and comes back to the foreground after sigsuspend().

if (BGProc) {
    if (tcsetpgrp(STDIN_FILENO, pgid) == -1) {
        printf(EXEC_ERROR, "Error in tcsetpgrp");
    }

    while (NoOfChildrenToBeReaped) {
        sigsuspend(&masknone);
    }

    signal(SIGTTOU, SIG_IGN);
    if (tcsetpgrp(STDIN_FILENO, getpid()) == -1) {
        printf(EXEC_ERROR, "Error in tcsetpgrp");
    }
}

Any help is greatly appreciated.

Thanks.

Upvotes: 1

Views: 79

Answers (1)

Shubs
Shubs

Reputation: 90

This was actually a silly mistake and indeed an issue because the FileDescriptors used for the pipe weren't closed correctly. Thank you @Ctx for pointing it out and giving good suggestions through comments.

for (i = 0; i < 2 * NoOfPipes; i++)
    close(pipefds[j]); //should have been "i".

I guess I overlooked the code inside the "for" and took it for granted.

Upvotes: 0

Related Questions