EDIT: THE QUESTION IS ANSWERED IN COMMENTS
So, i'm studying pipes. Long story short, i have two programs:
- first program creates a
pipe
and twofork
s: firstfork
closesread
descriptor and writes some stuff towrite
one (then closes it), secondfork
closeswrite
one,dup2
onread
side of pipe to standard input (end closesread
side itself) andexecl
second program, giving a size of a text the firstfork
writes as an argument; the parent closes both pipe sides andwaitpid
s for child that wasexecl
d (second one). - second program just
read
s from its standard input (pipe side) the stuff andwrite
s it out to standard output, then closes pipe side just in case.
In such a setup everything works as I intended, but when I delete waitpid
in first program (or just wait for the first child that writes instead of the second one), the second one behaves weirdly - it executes till the end, passing through all the IO (that is, the printf
before exit
got executed), and then doesn't give me the prompt back. That is, the terminal looks like the program awaits for an input from standard input. If i execute the first program without execl
, then everything works fine, If I execute just the second one with one argument, then it waits only until input is provided to standard input (as it should as it is not a part of a pipe in this case).
As i know, when parent terminates, the child is "inherited" by init
and got wait
ed. But even if it wasn't, that is, even if it remained as a zombie, then it still would be weird - why i cannot get my prompt back until i wait explicitly?
The code is below (of the setup that works correctly):
First program
/* headers */
int main(void)
{
int fildes[2];
pid_t p1, p2;
int status;
char mess[] = "written from execved program!\n";
int buf = strlen(mess);
if(pipe(fildes) == -1) {
perror("pipe in main");
exit(EXIT_FAILURE);
}
p1 = fork();
if(p1 == -1) {
perror("fork p1 in main");
exit(EXIT_FAILURE);
}
else if (p1 == 0) {
printf("Child 1!\n");
close(fildes[0]);
write(fildes[1], mess, buf);
close(fildes[1]);
printf("Before exit in child 1!\n");
exit(EXIT_SUCCESS);
}
p2 = fork();
if(p2 == -1) {
perror("fork p2 in main");
exit(EXIT_FAILURE);
}
else if (p2 == 0) {
printf("Child 2!\n");
dup2(fildes[0], 0);
close(fildes[0]);
close(fildes[1]);
char s_buf[30];
sprintf(s_buf, "%d", buf);
execl("./pipe2slave", "pipe2slave", s_buf, (char *) 0);
perror("execl have returned");
exit(EXIT_FAILURE);
}
close(fildes[0]);
close(fildes[1]);
/*
below if I wait for, say, p1, or don't wait it all,
the weird behavior described in my question happens
*/
if(waitpid(p2, &status, 0) == -1) {
perror("waitpid in main");
exit(EXIT_FAILURE);
}
if(WIFEXITED(status))
printf("pipe2slave exit status is %d\n", WEXITSTATUS(status));
printf("End of main in pipe2!\n");
exit(EXIT_SUCCESS);
}
Second program
/* headers */
int main(int argc, char **argv)
{
if (argc != 2) {
perror("pipe2slave - not enough args");
exit(EXIT_FAILURE);
}
printf("program name is %s\n", argv[0]);
int buf = atoi(argv[1]);
printf("%d\n", buf);
char mess_in[buf];
read(0, mess_in, buf);
write(1, mess_in, buf);
fsync(1);
close(0);
printf("end of slave!\n");
exit(EXIT_SUCCESS);
}
Thank you in advance!