0

I have user read/write permissions on a pipe. Group has read. Other has read. But program gets "stuck" when I run it. Program 1 is the "parent". Program 2 is the "child".

Program 1:

int main(int argc, char * argv[])
{
FILE *fptr; //for opening and closing input file
 int fdw;// write to pipe;
 int fdr; //read to pipe;
pid_t pid;
int inputarray[500]; 
int arraylength = 0; int j =0;
char *mypipe = "mypipe";


if (argc < 2)
{
  printf("Need to provide the file's name. \n");
  return EXIT_FAILURE;
}
//open input file
fptr = fopen(argv[1], "r");
if (fptr==NULL)
{
  printf("fopen fail.\n");
  return EXIT_FAILURE;
}

//read input file and fill array with integers
while (!feof(fptr))
{
  fscanf(fptr,"%d",&inputarray[arraylength]);
  arraylength = arraylength + 1;

}

fclose(fptr); //close input file



pid = fork();

mkfifo(mypipe, 0666);
fdw = open("mypipe",O_WRONLY);
if (fdw < 0)
{
  perror("File can't open to write.");
  return;
}
int b;
b=3;
write(fdw,&b,sizeof(b));
close(fdw);




if ( pid ==-1)
{
 perror("fork");
 exit(1);
}
int status; //exit status of child

if(pid==0)//if child process
{
   execl("program2", (char*) NULL);
}

else //if parent process
{
wait(&status);}
if((WIFEXITED(status)))
{
 printf("Child's exit code %d", WEXITSTATUS(status));
}
else{
printf("Child did not terminate with exit");}



}

Program 2:

int fdl;
int data;
fdl = open("mypipe",O_RDONLY);
if ( fdl < 0)
{
  perror("File can't open to read.");
  return;
}
read(fdl,&data,sizeof(data));
close(fdl);
Alex
  • 119
  • 3
  • 9
  • Which program gets stuck when? – thrig Apr 15 '17 at 14:09
  • Program 1 gets stuck. It's the parent. Program 2 is the child. – Alex Apr 15 '17 at 14:14
  • Did you know that you can do this all in one program: The exec, in program 1, can be replaced with content of program2. – ctrl-alt-delor Apr 15 '17 at 15:35
  • Did you know that because you are using fork, both child and parent come from the same context. Therefore you can use a (anonymous) pipe (`pipe`). Program2 already has the pipe open, when it starts, but it is hard to tell which file descriptor it is on, if you had inlined the code, then you would have access to `fdl`, if you had `dup`ed it to a specific fd (eg fd0) then you would know. – ctrl-alt-delor Apr 15 '17 at 15:37
  • http://stackoverflow.com/questions/5431941/why-is-while-feof-file-always-wrong – William Pursell Apr 15 '17 at 22:17

1 Answers1

2

The program will block on writing to the fifo until what it's writing is being read. The reading in the child process won't happen since the execl() doesn't happen until after the writing.

Also, it looks like both processes will actually attempt to write to the fifo since you fork() and then immediately start writing.

You should fork(), then test on the returned PID. The parent should then write to the fifo while the child should call execl(). The fifo should be created by the parent before the fork() call.

You should also consider using indent or clang-format to properly format your code, which eases reading it and may expose bugs (forgotten curly braces etc.).


A simple complete example program. The parent writes a string to the child and the child reads it character by character and outputs it to standard output:

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>

void parent(void);
void child(void);

int main(void) {
  pid_t pid;

  mkfifo("myfifo", 0666); /* fails if exists, but we don't care here */

  if ((pid = fork()) < 0)
    abort();

  if (pid == 0)
    child(); /* will not return */
  else
    parent();

  return EXIT_SUCCESS;
}

void parent(void) {
  int fd;
  int len;
  int ret;
  int stat;

  char *ptr;
  char *msg = "Hello World!";

  if ((fd = open("myfifo", O_WRONLY)) < 0)
    abort();

  len = strlen(msg) + 1;
  ptr = msg;

  puts("Parent: About to write to child");

  while ((ret = write(fd, ptr, len)) != 0) {
    if (ret > 0) {
      len -= ret;
      ptr += ret;
    } else
      abort();
  }

  close(fd);

  puts("Parent: Waiting for child to exit");
  wait(&stat);

  printf("Parent: Child exited with status %d\n", stat);
}

void child(void) {
  int fd;
  int ret;

  char ch;

  if ((fd = open("myfifo", O_RDONLY)) < 0)
    abort();

  puts("Child: About to read from parent");

  while ((ret = read(fd, &ch, 1)) != 0) {
    if (ret > 0)
      putchar(ch);
    else
      abort();
  }
  putchar('\n');

  close(fd);

  puts("Child: I'm done here");
  exit(EXIT_SUCCESS);
}

In this case, since both child and parent processes are in the same context, I could have used an anonymous pipe pair created with pipe(), but this illustrates the flow, including the creation of the named pipe.

Kusalananda
  • 14,885
  • 3
  • 41
  • 52
  • So the parent should write to the pipe after the wait call or before? – Alex Apr 15 '17 at 14:37
  • @Alex Before. The `wait()` will return when the child exits. The `write()` will block until the child `read()` it. – Kusalananda Apr 15 '17 at 14:40
  • I've created pipe before fork() and write() is after wait() but still getting stuck. – Alex Apr 15 '17 at 15:07
  • @Alex The child will read in its call to `read()`, the parent will write by calling `write()`. The parent will be blocked in the `write()` until the child reads. Likewise, the child will block until the parent closes the file descriptor. Before that, you `fork()` and decide what process do the reading and which process do the writing. The `write()` should be before the `wait()` since the `wait()` won't return until the child exits (when it's done reading). – Kusalananda Apr 15 '17 at 15:07
  • I've tried opening and writing it in the else block but before the wait call. It was still getting stuck. – Alex Apr 15 '17 at 15:13
  • Thank you I'll try that. – Alex Apr 15 '17 at 15:25
  • Create pipe before fork (at this time before fork process is parent and child). After fork do parents stuff (write then wait) in parent branch, and child stuff (read) in child branch. – ctrl-alt-delor Apr 15 '17 at 15:33