开发者

IO streams in fork()'ed process

The followin开发者_Go百科g example code executes, but output from the forked process is not readable: nothing is shown on console until I press enter, and then "Read failed!" shows.

The question is: why is that, and how can I interact with stdin and stdout from the fork()'ed process?

/* example1.c */

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>

int main() {
    pid_t pid = fork();

    if (!pid) {
        // child

        char s[64];
        printf("Enter something: ");
        char *res = fgets(s, 64, stdin);
        if (!res) {
            printf("Read failed!\n");
        } else {
            printf("You entered: %s", s);
        }
    }

    return 0;
}

Update:

Another example of strange behavior of IO streams:

/* example2.c */

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>

int main() {
    pid_t pid = fork();

    if (!pid) {
        // child

        char *argv[] = {
            "-c",
            "/home/user/echo.sh",
            NULL
        };

        execv("/bin/sh", argv);
    }
    return 0;
}

echo.sh script:

#!/bin/sh

read -p "Enter something: " INPUT
echo "You entered $INPUT"

This one returns

Enter something: /home/user/echo.sh: line 3: read: read error: 0: Input/output error
You entered

Update 2:

Looks like this code does exactly what's needed:

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>

int main() {
    pid_t pid = vfork();
    if (!pid) {
        // child
        system("/home/user/echo.sh");
    }
    return 0;
}

The solution was to replace fork with vfork. I just don't know why is this one working...


I think you want wait(2). As in

/* example1.c */

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>

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

    if (!pid) {
        // child

        char s[64];
        printf("Enter something: ");
        char *res = fgets(s, 64, stdin);
        if (!res) {
            printf("Read failed!\n");
        } else {
            printf("You entered: %s", s);
        }
    }
    else
    {
        while (wait(&status) != pid);
    }
    return 0;
}


This is because your child process is now in an orphaned process group, where no process is a direct child of the shell (who is supposed to do job-control).

Orphaned process group: Process group which doesn't have at least a member who has a parent not in the process group but within the same session (~ is a direct child of the shell).

While the parent and child are both running, the situation is like this:

$ ps fax -o pid,pgid,sid,ppid,tty,stat,time,cmd
27177 27177 27177 32170 pts/6    Ss   00:00:00  |   \_ /bin/bash
 4706  4706 27177 27177 pts/6    S+   00:00:00  |       \_ ./ex1
 4707  4706 27177  4706 pts/6    S+   00:00:00  |           \_ ./ex1

There are two processes, 4706 and 4707 on process group 4706. 4706 is a child of 27177, which is in the same session (27177), but different process group (27177): it's the shell that deals with job control for process group 4706.

When the parent dies, the situation is like this:

$ ps fax -o pid,pgid,sid,ppid,tty,stat,time,cmd
27177 27177 27177 32170 pts/6    Ss+  00:00:00  |   \_ /bin/bash
 4664  4663 27177     1 pts/6    S    00:00:00 ./ex1

There is only one process, 4664, in process group 4663, and its parent (init) isn't on the same session. The shell cannot deal with job control for this process group, therefore, read() and write() get EIO.


If you are on UNIX/Linux, when stdout goes into console it is line-buffered. That is, you don't see any output until you do either:

  • fflush(stdout)
  • prinf("\n")
  • stdout buffer overflows.

When stdout goes somewhere else (like pipe of file) it is fully-buffered, that is, printf("\n") does not flush the buffer.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜