I'm practicing with fork() and pipes and I have a question: why does the second child process get stuck reading the pipe if I don't close the first pipe (first child - second child) in the parent process?
#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<errno.h>
#include<sys/wait.h>
#include<stdlib.h>
#include<stdio.h>
#include<unistd.h>
void checkArgs(int n){
if(n!=1){
perror("Wrong parameters number");
exit(-1);
}
}
int isAConsonant(char c){
char vowels[5]={'a','e','i','o','u'};
int i=0,toRet=1;
for(i=0;i<5 && toRet;i++){
if(c==vowels[i]){
toRet=0;
}
}
return toRet;
}
int main(int argc,char** argv){
checkArgs(argc-1);
int pipe1[2],pipe2[2],sync[2];
int pid1,pid2;
if(pipe(pipe1)<0 || pipe(pipe2)<0 || pipe(sync)<0){
perror("Error opening pipes");
exit(-1);
}
if((pid1=fork())<0){
perror("error during fork");
exit(-1);
}
if(pid1==0){ //first child
close(pipe1[0]);
close(sync[0]);
char buf[3];
int fDes=open(argv[1],O_RDONLY);
if(fDes<0){
perror("Error opening file");
exit(-1);
}
write(sync[1],"N",1);
while(read(fDes,buf,3)==3){
write(sync[1],"N",1);
write(pipe1[1],buf,3);
}
write(sync[1],"S",1);
close(sync[1]);
close(fDes);
close(pipe1[1]);
}
else{
if((pid2=fork())<0){
perror("error during fork");
exit(-1);
}
if(pid2==0){ //second child
close(pipe2[0]);
close(pipe1[1]);
char buf[3];
while(read(pipe1[0],buf,3)==3){
if(isAConsonant(buf[0])){
write(pipe2[1],buf,3);
}
}
close(pipe2[1]);
close(pipe1[0]);
}
else{ //parent
close(pipe2[1]);
close(sync[1]);
//it does not work if not executed
//close(pipe1[1]);
//close(pipe1[0]);
char toStart;
read(sync[0],&toStart,1);
while(toStart!='S'){
read(sync[0],&toStart,1);
}
int fDes=open(argv[1],O_RDWR|O_APPEND,S_IRUSR|S_IWUSR);
if(fDes<0){
perror("Error opening file");
exit(-1);
}
char buf[3];
while(read(pipe2[0],buf,3)==3){
write(fDes,buf,3);
write(fDes," ",1);
}
close(pipe2[0]);
close(sync[0]);
close(fDes);
}
}
}
These calls terminate the program correctly
close(pipe1[1]);
close(pipe1[0]);
inputF file:
abcdefghilmnopqrstuvz
Strace screen for executing code without close(pipe1[0]) and close(pipe1[1]) in the parent process:
strace for the parent process
execve("./pipe", ["./pipe", "inputF"], 0x7ffc458bc820 /* 54 vars */) = 0
brk(NULL) = 0x55ed3c675000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (File o directory non esistente)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=71886, ...}) = 0
mmap(NULL, 71886, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f7d0b895000
close(3) = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\200l\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=2000480, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f7d0b893000
mmap(NULL, 2008696, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f7d0b6a8000
mmap(0x7f7d0b6cd000, 1519616, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x25000) = 0x7f7d0b6cd000
mmap(0x7f7d0b840000, 299008, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x198000) = 0x7f7d0b840000
mmap(0x7f7d0b889000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1e0000) = 0x7f7d0b889000
mmap(0x7f7d0b88f000, 13944, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f7d0b88f000
close(3) = 0
arch_prctl(ARCH_SET_FS, 0x7f7d0b894500) = 0
mprotect(0x7f7d0b889000, 12288, PROT_READ) = 0
mprotect(0x55ed3a7d0000, 4096, PROT_READ) = 0
mprotect(0x7f7d0b8d1000, 4096, PROT_READ) = 0
munmap(0x7f7d0b895000, 71886) = 0
pipe([3, 4]) = 0
pipe([5, 6]) = 0
pipe([7, 8]) = 0
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f7d0b8947d0) = 11194
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f7d0b8947d0) = 11195
close(6) = 0
close(8) = 0
read(7, "N", 1) = 1
read(7, "N", 1) = 1
read(7, "N", 1) = 1
read(7, "N", 1) = 1
read(7, "N", 1) = 1
read(7, "N", 1) = 1
read(7, "N", 1) = 1
read(7, "N", 1) = 1
read(7, "S", 1) = 1
openat(AT_FDCWD, "inputF", O_RDWR|O_APPEND) = 6
read(5, "def", 3) = 3
write(6, "def", 3) = 3
write(6, " ", 1) = 1
read(5, "ghi", 3) = 3
write(6, "ghi", 3) = 3
write(6, " ", 1) = 1
read(5, "lmn", 3) = 3
write(6, "lmn", 3) = 3
write(6, " ", 1) = 1
read(5, "rst", 3) = 3
write(6, "rst", 3) = 3
write(6, " ", 1) = 1
read(5, 0x7ffffab4a6a5, 3) = ? ERESTARTSYS (To be restarted if SA_RESTART is set)
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=11194, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
read(5, 0x7ffffab4a6a5, 3) = ? ERESTARTSYS (To be restarted if SA_RESTART is set)
--- SIGINT {si_signo=SIGINT, si_code=SI_KERNEL} ---
+++ killed by SIGINT +++
strace for the first child process
execve("./pipe", ["./pipe", "inputF"], 0x7ffc458bc820 /* 54 vars */) = 0
brk(NULL) = 0x55ed3c675000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (File o directory non esistente)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=71886, ...}) = 0
mmap(NULL, 71886, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f7d0b895000
close(3) = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\200l\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=2000480, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f7d0b893000
mmap(NULL, 2008696, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f7d0b6a8000
mmap(0x7f7d0b6cd000, 1519616, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x25000) = 0x7f7d0b6cd000
mmap(0x7f7d0b840000, 299008, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x198000) = 0x7f7d0b840000
mmap(0x7f7d0b889000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1e0000) = 0x7f7d0b889000
mmap(0x7f7d0b88f000, 13944, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f7d0b88f000
close(3) = 0
arch_prctl(ARCH_SET_FS, 0x7f7d0b894500) = 0
mprotect(0x7f7d0b889000, 12288, PROT_READ) = 0
mprotect(0x55ed3a7d0000, 4096, PROT_READ) = 0
mprotect(0x7f7d0b8d1000, 4096, PROT_READ) = 0
munmap(0x7f7d0b895000, 71886) = 0
pipe([3, 4]) = 0
pipe([5, 6]) = 0
pipe([7, 8]) = 0
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f7d0b8947d0) = 11194
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f7d0b8947d0) = 11195
close(6) = 0
close(8) = 0
read(7, "N", 1) = 1
read(7, "N", 1) = 1
read(7, "N", 1) = 1
read(7, "N", 1) = 1
read(7, "N", 1) = 1
read(7, "N", 1) = 1
read(7, "N", 1) = 1
read(7, "N", 1) = 1
read(7, "S", 1) = 1
openat(AT_FDCWD, "inputF", O_RDWR|O_APPEND) = 6
read(5, "def", 3) = 3
write(6, "def", 3) = 3
write(6, " ", 1) = 1
read(5, "ghi", 3) = 3
write(6, "ghi", 3) = 3
write(6, " ", 1) = 1
read(5, "lmn", 3) = 3
write(6, "lmn", 3) = 3
write(6, " ", 1) = 1
read(5, "rst", 3) = 3
write(6, "rst", 3) = 3
write(6, " ", 1) = 1
read(5, 0x7ffffab4a6a5, 3) = ? ERESTARTSYS (To be restarted if SA_RESTART is set)
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=11194, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
read(5, 0x7ffffab4a6a5, 3) = ? ERESTARTSYS (To be restarted if SA_RESTART is set)
--- SIGINT {si_signo=SIGINT, si_code=SI_KERNEL} ---
+++ killed by SIGINT +++
pepys@pepys:~/Scrivania/lso/C/pipe/prova strana$ ^C
pepys@pepys:~/Scrivania/lso/C/pipe/prova strana$ ls
es es.c inputF pipe pipe.c trace.11193 trace.11194 trace.11195
pepys@pepys:~/Scrivania/lso/C/pipe/prova strana$ cat trace.11194
close(3) = 0
close(7) = 0
openat(AT_FDCWD, "inputF", O_RDONLY) = 3
write(8, "N", 1) = 1
read(3, "abc", 3) = 3
write(8, "N", 1) = 1
write(4, "abc", 3) = 3
read(3, "def", 3) = 3
write(8, "N", 1) = 1
write(4, "def", 3) = 3
read(3, "ghi", 3) = 3
write(8, "N", 1) = 1
write(4, "ghi", 3) = 3
read(3, "lmn", 3) = 3
write(8, "N", 1) = 1
write(4, "lmn", 3) = 3
read(3, "opq", 3) = 3
write(8, "N", 1) = 1
write(4, "opq", 3) = 3
read(3, "rst", 3) = 3
write(8, "N", 1) = 1
write(4, "rst", 3) = 3
read(3, "uvz", 3) = 3
write(8, "N", 1) = 1
write(4, "uvz", 3) = 3
read(3, "", 3) = 0
write(8, "S", 1) = 1
close(8) = 0
close(3) = 0
close(4) = 0
exit_group(0) = ?
+++ exited with 0 +++
strace for the second child process
close(5) = 0
close(4) = 0
read(3, "abc", 3) = 3
read(3, "def", 3) = 3
write(6, "def", 3) = 3
read(3, "ghi", 3) = 3
write(6, "ghi", 3) = 3
read(3, "lmn", 3) = 3
write(6, "lmn", 3) = 3
read(3, "opq", 3) = 3
read(3, "rst", 3) = 3
write(6, "rst", 3) = 3
read(3, "uvz", 3) = 3
read(3, 0x7ffffab4a6a5, 3) = ? ERESTARTSYS (To be restarted if SA_RESTART is set)
--- SIGINT {si_signo=SIGINT, si_code=SI_KERNEL} ---
+++ killed by SIGINT +++