I have a requirement to call "Program 2" from child process of "Program 1", where Program takes input from user and writes it to FIFO queue. On returning to "Program 1" , the parent process must be able to retrieve data written to queue by "Program 1" and display it. Given below is the minimum reproducible code of both caller program, "Program 1" and called program "Program 2" respectively.
Program 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <pthread.h>
int main() {
const char *fifo_name = "f";
char output[100];
pid_t forkCall =fork();
if(forkCall ==0)
{
printf("Child process \n");
execl("./a.out", "Program2",NULL);
perror("execl failed");
exit(1);
}
else if(forkCall == -1)
{
perror("Error creating child process");
exit(0);
}
else{
printf("Parent process \n");
int fd = open(fifo_name,O_RDONLY);
wait(NULL);
read(fd, output, sizeof(output));
close(fd);
unlink(fifo_name);
printf("Reader process read: %s\n", output);
}
return 0;
}
Program 2
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/stat.h>
#include <pthread.h>
int main() {
const char *fifo_name = "f";
char input[100];
fgets(input, sizeof(input), stdin);
input[strcspn(input, "\n")] = '\0';
printf("Ucer input accepted \n");
if(mkfifo(fifo_name, 0777)==-1)
{
perror("mkfifo");
return 1;
}
printf("FIFO Created \n");//********************************
int fd = open(fifo_name,O_WRONLY);
if (fd == -1) {
perror("Error opening FIFO");
return 1;
}
printf("File descriptor (fd) is %d . \n", fd);
printf("FIFO opened successfully \n");
write(fd, input, sizeof(input));
printf("FIFO content written successfully \n");
printf(" Named pipe created and %s data written \n",input);
close(fd);
return 0;
}
When I run Program 1, it asks for input at the terminal and prints "FIFO CREATED". After that the programs halts without terminating.
When i run the Program 1 in separate terminal, the previous value entered for input is displayed from the parent process in the previous terminal and program halts.
What missing aspect of IPC do I need to provide here, so that after taking input from user and writing it to FIFO queue, it returns control back to calling program. I tried opening fifo for writing using O_NONBLOCK.
int fd = open(fifo_name,O_WRONLY|O_NONBLOCK);
But it terminated the program even before taking input from user.
The parent process is trying to open the FIFO before the child has created it. This fails, but the parent never checks the result of open()
. It then calls wait()
to wait for the child.
Then the child creates the FIFO and tries to open it for writing. This blocks until another process opens it for reading it. But since the parent has already gone past its open()
call, this never happens.
So you have a deadlock -- the parent is waiting for the child to exit, while the child is waiting for the parent to open the FIFO, and neither can proceed.
The solution is to create the FIFO before forking the child. Move that code into Program 1.
Program 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <pthread.h>
int main() {
const char *fifo_name = "f";
char output[100];
if(mkfifo(fifo_name, 0777)==-1)
{
perror("mkfifo");
return 1;
}
printf("FIFO Created \n");//********************************
pid_t forkCall =fork();
if(forkCall ==0)
{
printf("Child process \n");
execl("./a.out", "Program2",NULL);
perror("execl failed");
exit(1);
}
else if(forkCall == -1)
{
perror("Error creating child process");
exit(0);
}
else{
printf("Parent process \n");
int fd = open(fifo_name,O_RDONLY);
if (fd < 0) {
perror("open fifo");
return 1;
}
wait(NULL);
read(fd, output, sizeof(output));
close(fd);
unlink(fifo_name);
printf("Reader process read: %s\n", output);
}
return 0;
}
Program 2
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/stat.h>
#include <pthread.h>
int main() {
const char *fifo_name = "f";
char input[100];
fgets(input, sizeof(input), stdin);
input[strcspn(input, "\n")] = '\0';
printf("Ucer input accepted \n");
int fd = open(fifo_name,O_WRONLY);
if (fd == -1) {
perror("Error opening FIFO");
return 1;
}
printf("File descriptor (fd) is %d . \n", fd);
printf("FIFO opened successfully \n");
write(fd, input, sizeof(input));
printf("FIFO content written successfully \n");
printf(" Named pipe created and %s data written \n",input);
close(fd);
return 0;
}
Result:
$ ./program1
FIFO Created
Parent process
Child process
90
Ucer input accepted
File descriptor (fd) is 3 .
FIFO opened successfully
FIFO content written successfully
Named pipe created and 90 data written
Reader process read: 90