On Linux, why does this print 0 and hang rather than printing 0 up to 999?
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main() {
int n = 1000;
int fromparent[2];
int fromchild[2];
int *x = 0;
pipe(fromparent);
pipe(fromchild);
if (fork() == 0) {
/* child */
while (1) {
read(fromparent[0], x, 1);
write(fromchild[1], x, 1);
}
} else {
/* parent */
for (int i = 0; i < n; i++) {
printf("%d\n", i);
write(fromparent[1], x, 1);
read(fromchild[0], x, 1);
}
exit(0);
}
}
The problem is simple: you pass a null pointer to read and write.
Change the definition of x from int *x = 0; to:
char x[1] = { 0 };
As posted, the behavior is somewhat counterintuitive:
passing a null pointer to write causes it to return -1 immediately, setting errno to EINVAL.
conversely, passing a null pointer to read causes it to wait for input and only return -1 and set errno to EINVAL once input is available. This is causing both processes to block on the read calls.
Here is a simple test to illustrate this behavior:
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
int main() {
int n;
errno = 0;
n = read(0, NULL, 1);
printf("n=%d, errno=%d\n", n, errno);
return 0;
}
This program waits for input if run from the console and prints n=-1, errno=14 after the user hits enter.
Conversely, it prints n=0, errno=0 when standard input is redirected from /dev/null.