FIXED: Fork() and redirecting STDOUT/STDERR to a pipe
Posted: Tue Nov 11, 2008 4:24 am
Hi,
Ok, I'm stumped.
I'm writing a multi-threaded utility in C (GCC on Linux with POSIX). The idea is to fork a new process to run an external command, and redirect the new process' STDOUT and STDERR to a pipe; where the original/main process does other work then reads anything from the pipe and buffers it (and then displays it even later).
It all works perfectly, except...
When a child process is running; if the original/main process sends something to it's STDOUT, then it'll be sent where it should (to the shell/display, like you'd expect) but it'll also be received from the child process' pipe as if the child process sent it. Nothing changes the original/main process' STDOUT (it's only the child process that's messed with), and I'm having trouble figuring out how the original/main process' STDOUT (which is mostly a normal file descriptor) can point to 2 different streams at the same time.
Note: A previous version of the utility just used the "popen()" function, which is almost exactly what I need, except the "popen()" function only redirects STDOUT and this causes problems because the child sends some text to STDERR (which was displayed at the wrong time because it wasn't redirected/buffered, and makes a mess of the main process' output).
My code does the following:
If I can't find a way to fix this, then I'll need to protect it all with a mutex or something, so that the original/main process can't do "printf()" while any child process is running (and even then, I'm not too sure if the output from one child processes interferes with the output from other child processes). Of course the utility spawns many threads and forks many processes because everything is I/O bound and I'm trying to keep a quad core busy - slapping a huge mutex around the problem is the last thing I want to do...
Thanks,
Brendan
Ok, I'm stumped.
I'm writing a multi-threaded utility in C (GCC on Linux with POSIX). The idea is to fork a new process to run an external command, and redirect the new process' STDOUT and STDERR to a pipe; where the original/main process does other work then reads anything from the pipe and buffers it (and then displays it even later).
It all works perfectly, except...
When a child process is running; if the original/main process sends something to it's STDOUT, then it'll be sent where it should (to the shell/display, like you'd expect) but it'll also be received from the child process' pipe as if the child process sent it. Nothing changes the original/main process' STDOUT (it's only the child process that's messed with), and I'm having trouble figuring out how the original/main process' STDOUT (which is mostly a normal file descriptor) can point to 2 different streams at the same time.
Note: A previous version of the utility just used the "popen()" function, which is almost exactly what I need, except the "popen()" function only redirects STDOUT and this causes problems because the child sends some text to STDERR (which was displayed at the wrong time because it wasn't redirected/buffered, and makes a mess of the main process' output).
My code does the following:
- "pipe()" to create the pipe
- "fork()" to create the child process
- [child] "close()" to close the input side of it's copy of the pipe
- [child]"dup2()" to replace STDOUT and STDERR with the output side of it's copy of the pipe
- [child]"system()" to execute the shell command
- [child] "close()" to close the output side of it's copy of the pipe
- [child]"exit()"
- [main] "close()" to close the output side of it's copy of the pipe
- [main] "fgetc()" in a loop to receive all the data from the pipe (from the child), until EOF (received data placed in a buffer)
- [main] "waitpid()" to make sure the child process has done "exit()"
- [main] "close()" to close the input side of it's copy of the pipe
- [main] Eventually, send the child's output from the buffer to STDOUT
If I can't find a way to fix this, then I'll need to protect it all with a mutex or something, so that the original/main process can't do "printf()" while any child process is running (and even then, I'm not too sure if the output from one child processes interferes with the output from other child processes). Of course the utility spawns many threads and forks many processes because everything is I/O bound and I'm trying to keep a quad core busy - slapping a huge mutex around the problem is the last thing I want to do...
Thanks,
Brendan