Reputation: 6132
I am writing some C code that involves the use of pipes. To make a child process use my pipe instead of STDOUT for output, I used the following lines:
close(STDOUT);
dup2(leftup[1], STDOUT);
However, it seems to go into some sort of infinite loop or hang on those lines. When I get rid of close
, it hangs on dup2
.
Curiously, the same idea works in the immediately preceding line for STDIN:
close(STDIN);
dup2(leftdown[0], STDIN);
What could be causing this behavior?
Edit: Just to be clear...
#define STDIN 0
#define STDOUT 1
Edit 2: Here is a stripped-down example:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#define STDIN 0
#define STDOUT 1
main(){
pid_t child1 = 0;
int leftdown[2];
if (pipe(leftdown) != 0)
printf("ERROR");
int leftup[2];
if (pipe(leftup) != 0)
printf("ERROR");
printf("MADE PIPES");
child1 = fork();
if (child1 == 0){
close(STDOUT);
printf("TEST 1");
dup2(leftup[1], STDOUT);
printf("TEST 2");
exit(0);
}
return(0);
}
The "TEST 1"
line is never reached. The only output is "MADE PIPES"
.
Upvotes: 0
Views: 2589
Reputation: 39
Multiple thing to mention,
When you use fork, it causes almost a complete copy of parent process. That also includes the buffer that is set up for stdout
standard output stream as well. The stdout
stream will hold the data till buffer is full or explicitly requested to flush the data from buffer/stream. Now because of this , now you have "MADE PIPES"
sitting in buffer. When you close the STDOUT
fd and use printf
for writing data out to terminal, it does nothing but transfers your "TEST 1"
and "TEST 2"
into the stdout
buffer and doesn't cause any error or crash (due to enough buffer). Thus even after duplicating pipe
fd on STDOUT
, due to buffered output printf
hasn't even touched pipe write end. Most important, please use only one set of APIs i.e. either *NIX or standard C lib functions. Make sure you understand the libraries well, as they often play tricks for some sort of optimization.
Now, another thing to mention, make sure that you close the appropriate ends of pipe in appropriate process. Meaning that if say, pipe-1 is used to communicate from parent to child then make sure that you close the read end in parent and write end in child. Otherwise, your program may hung, due to reference counts associated with file descriptors you may think that closing read end in child means pipe-read end is closed. But as when you don't close the read end in parent, then you have extra reference count for read end of pipe and ultimately the pipe will never close.
There are many other things about your coding style, better you should get hold on it :) Sooner you learn it better it will save your time. :)
Error checking is absolutely important, use at least assert to ensure that your assumptions are correct.
While using printf
statements to log the error or as method of debugging and you are changing terminal FD's (STDOUT / STDIN / STDERR)
its better you open a log file with *NIX
open and write errors/ log entries to it.
At last, using strace
utility will be a great help for you. This utility will allow you to track the system calls executed while executing your code. It is very straight forward and simple. You can even attach this to executing process, provided you have right permissions.
Upvotes: 0
Reputation: 881263
At a minimum, you should ensure that the dup2
function returns the new file descriptor rather than -1
.
There's always a possibility that it will give you an error (for example, if the pipe()
call failed previously). In addition, be absolutely certain that you're using the right indexes (0 and 1) - I've been bitten by that before and it depends on whether you're in the parent or child process.
Based on your edit, I'm not the least bit surprised that MADE PIPES
is the last thing printed.
When you try to print TEST 1
, you have already closed the STDOUT
descriptor so that will go nowhere.
When you try to print TEST 2
, you have dup
ed the STDOUT
descriptor so that will go to the parent but your parent doesn't read it.
If you change your forking code to:
child1 = fork();
if (child1 == 0){
int count;
close(STDOUT);
count = printf("TEST 1\n");
dup2(leftup[1], STDOUT);
printf("TEST 2 (%d)\n", count);
exit(0);
} else {
char buff[80];
read (leftup[0], buff, 80);
printf ("%s\n", buff);
sleep (2);
}
you'll see that the TEST 2 (-1)
line is output by the parent because it read it via the pipe. The -1
in there is the return code from the printf
you attempted in the child after you closed the STDOUT
descriptor (but before you dup
ed it), meaning that it failed.
From ISO C11 7.20.6.3 The printf function
:
The
printf
function returns the number of characters transmitted, or a negative value if an output or encoding error occurred.
Upvotes: 1