Progear
Progear

Reputation: 167

Why when i use dup2() before fork() it doesn't work?

I want to make a shell and i want to handle multiple pipe. I tried to understand how works dup2() and fork. Normally, fork(), create a new child process who is exactly the same as the father. But when i use dup2 before the fork it doesn't seem to works how i things it should do. But when i use dup2() in the child process it works... I don't understand because normally fork create a copy of the calling process...

Can someone explain why?

This does not work:

int fd = open("toto.txt", O_RDONLY);
char str[10] = {0};
int test[2] = {0, 0};
char *av[] = {"/bin/ls", NULL};

pipe(test);
dup2(test[1], 1);
if (fork() == 0) {
    execve(av[0], av, env);
}
else {
    wait(NULL);
    read(test[0], str, 10);
    write(1, str, 10);
}

but this works :

int fd = open("toto.txt", O_RDONLY);
char str[10] = {0};
int test[2] = {0, 0};
char *av[] = {"/bin/ls", NULL};

pipe(test);
if (fork() == 0) {
    dup2(test[1], 1);
    execve(av[0], av, env);
}
else {
    wait(NULL);
    read(test[0], str, 10);
    write(1, str, 10);
}

Upvotes: 2

Views: 953

Answers (1)

Michael Veksler
Michael Veksler

Reputation: 8475

The original does not work correctly because:

dup2(test[1], 1);
if (fork() == 0) {
    execve(av[0], av, env);
}
else {
    wait(NULL);
    read(test[0], str, 10);
    write(1, str, 10);
}

After the dup2 stdout is redirected to the pipe. This redirection applies both to the parent and the child. Due to that, the line:

    write(1, str, 10);

writes its data back to the pipe, not the original stdout (which is lost).

By moving the dup2 to after the fork(), and only to the child process, the original stdout of the parent is left alone. In that case only the child's stdout gets redirected.

Note: calling wait before reading the pipe will work for small pipe traffic like in the example, but won't work for big traffic. The issue is that the pipe has a limited buffer. Once the buffer is full, the pipe starts to block writes. The wait will wait on the child to finish, but the child will wait on the pipe to be read by the parent. This can become a deadlock when the traffic is big enough.

Upvotes: 2

Related Questions