1
votes

I have implement a scenario which involves two way communication between child and parent processes. The child process uses execvp to launch another c program (say XYZ). Parent writes data at one end of pipe1 and other end of pipe1 is duplicated to child's stdin. so child reads this data, performs some manipulations and writes data back to stdout. This stdout is duplicated to write end of pipe2 and now parent reads from read end of pipe2. The external program XYZ is not to be modified. The sequence to be followed is

1) parent writes data to pipe1 2) child reads data from duplicated end (stdin) of pipe1 3) child does some modifications to data and writes data back to stdout, which is duplicated to read end of pipe2 4) parent tries to read data from read end of pipe2.

The above scenario can be repeated n number of times.

Example of above scenario with example 1) parent writes 1 2) child reads 1 and does modification and writes 1 (after modifcations) to stdout 3) Now parent reads this data and prints back 4) after printing, parent writes 2 to the stdin 5) continues as above.....

The problem i am facing is parent is not able to read data from read end of pipe2. Its literally hanging out.

Imp Note: I have not closed the write handle of pipe1 because, i need to write data again. If i close the handle, i cannot reopen it, as it is not supported by pipes.

The code is as shown below

void Child_write  (pid_t Handle);
void Parent_write (pid_t Handle, char c);
void Child_read  (pid_t Handle);
void Parent_read (pid_t Handle);

void main()
{

  pid_t Pid;
  int   writepipe[2],readpipe [2];  

  pipe(readpipe);               /* Create two file descriptors  */
  pipe(writepipe);              /* Create two file descriptors  */

  Pid = fork();

  if (Pid == 0)         
  {
     close(writepipe[1]);               /* closing writepipe's write end */
     dup2(writepipe[0],0); close(writepipe[0]);     /* duplicating writepipe's read    end to stdin*/
     close(readpipe[0]);                /* closing readpipe's read end*/
     dup2(readpipe[1],1);  close(readpipe[1]);      /* duplicating readpipe's write end to stdout*/    
     Child_read(writepipe[0]);              /* reading data from write pipe read end and then duplicating*/

  }
  else                  
  {
     close(writepipe[0]);               /* closing writepipe's read end */
     Parent_write(writepipe[1],'1');            /* pupming data to the writepipe */
     close(readpipe[1]);                /* closing the readpipes write end */
     Parent_read(readpipe[0]);              /* reading the data which is pumped into readpipe */
     //Parent_write(writepipe[1],'2');          /* pupming data to the writepipe */
     //Parent_read(readpipe[0]);

     //Parent_write(writepipe[1],'3');
     //Parent_read(readpipe[0]);
     puts("***** End of parent process*****");
  }
}

void Child_read(pid_t handle)
{
   static char* command = "./stdoutput";
   execvp(command, NULL);
}

void Parent_write(pid_t handle, char c)
{
   char Buff[] = {'\n','\n'};
   Buff[0] = c;
   int n_written= write(handle, Buff, strlen(Buff)+1);

   printf("write function has written %d no of bytes and the data written is %s",n_written,Buff);

   //close(handle);
}

void Parent_read(pid_t handle)
{
    printf("PARENT PROCESS: In Parent_read function\n");
    int i=0;
    int bytes_read = 0;
    char buffer[1024]= {'\0'};
    while (read(handle, buffer, sizeof(buffer)) > 0)
    {
        printf("PARENT PROCESS:: In while loop\n");
        printf("The character/string read from readend of readpipe (stdout) is %s",buffer);
    }
    close(handle);
}

The external program is as shown below

void printing()
{
  int c;
  do
    {
        c = getchar();
        printf("%c",c);
    } while ((c != EOF) && (c != '\n'));
}

void main()
{
  printing();
  printing();
}

Please help me !!!!!!!!!

2
Unless you're feeling masochistic, just use popen. Though at one time this only allowed unidirectional communication, Linux has supported bidirectional for quite a while, at least if memory serves.Jerry Coffin
@JerryCoffin : i have no knowledge on popen(). Is it possible to solve the problem with unnamed pipes itself!!!chaitu

2 Answers

2
votes

On the first I/O call (using file stream functions) for a given FILE *, the library decides wether the stream should be line buffered, block buffered, or unbuffered. In your case, when stdoutput starts, it's stdoutput is not a terminal, so the stream goes in block buffered mode, and your printf ends in a buffer.

Change your main function to :

void main()
{
  setvbuf(stdout, NULL, _IONBF, 0);
  printing();
  printing();
}

And your printf call will produce writes.

You shoud also look at the setvbuf man page, and learn to use strace :

strace -ff -o test.log ./myprog

will produce two log fil (one for the parent, one for the child) that will let you see what system call are made by each program.

-1
votes

Indeed, as Jerry Coffin commented, you should use popen (some systems also have a p2open for bidirectional piping, one in, another out).

If you really insist on doing it by yourself, you should strongly consider using a multiplexing system call like poll (or perhaps the older select). Then you'll be able to test which file descriptor can be read or written, and act accordingly.