UNIX Socket FAQ

A forum for questions and answers about network programming on Linux and all other Unix-like systems

You are not logged in.

#1 2014-04-10 07:40 AM

Tera
Guest

Interprocess Communication (IPC) problem

Hi, all:

Can you please help me with the following problem?

Problem statement: Write an IPC program which passes Linux commands
(such as "ls -l", "cat", or "wc") from parent process to child process via "message queue".
Once commands received, the child process should process those commands and
pass the outputs of those linux commands from the child process back to
the parent process via "shared memory segment".

Issue seen: There is a delay seen on screen.
1. Type "ls test.txt" on screen (Output: nothing seen)
2. Type "cat test.txt" on screen (Output: "ls test.txt" output is now displayed instead of those of "cat")
3. Type "wc test.txt" on screen (Output: "cat test.txt" is now displayed instead of those of "wc")
.....
Thus command outputs are being delayed by 1 step; previous command output
is being displayed instead that of the current one. I have tried various things, but none worked.
Any solution pointers is greatly appreciated. Thanks in advance.

#define BUFSZ 512
#define ERRBUFSZ 512
#define TIMEOUT_TIMEDIO 20
#define SHM_SIZE       5120 
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <setjmp.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/msg.h>

int parse_cmd(char *buf, char **vbuf, char *errbuf);
void process_cmd_ipc(char *argv, int linenum, char *errbuf);

struct my_msgbuf {
	long mtype;
	char mtext[256];
};

void process_cmd_ipc(char *argv, int linenum, char* errbuf) 
{
   struct my_msgbuf buf;
   int msqid, msqid_parent, shmid, str_len;
   key_t key, key_shm;
   char* shared_buf;
   FILE *fd;

   // create key for shared memory segment
   if ((key_shm = ftok("shm_key.txt", 'R')) == -1) {
      perror("ftok");
      exit(1);
   }

   // Connect to shared memory segment 
   if ((shmid = shmget(key_shm, SHM_SIZE, 0644 | IPC_CREAT)) == -1)
   {
      perror("shmget");
      exit(1);
   }

   // Attach to shared memory segment
   shared_buf = shmat(shmid, (void *) 0, 0);
   if (shared_buf == (char *) (-1)) {
      perror("shmat");
      exit(1);
   }
   // End of shared memory section` //

   // Begin: message queue section
   pid_t   cpid=fork();
   if (cpid<0) {
      fprintf(stderr,"ERR: \"fork\" error! (Line=%d)\n", linenum); 
      exit (-1);
   } else if (cpid==0)		// child process
   {  // Begin: message queue 
      if ((key = ftok("mysh.c", 'B')) == -1) {
          perror("ftok");
          exit(1);
      }

      if ((msqid = msgget(key, 0644)) == -1) {
          perror("msgget from child");
          exit(1);
      }

      memset(buf.mtext, 0, sizeof(buf.mtext));    // Clear buffer

      if(msgrcv(msqid, (struct msgbuf*) &buf, sizeof(buf), 0,0) == -1)
      {
          perror("msgrcv");
          exit(1);
      }
      // End: message queue

      // begin: shared memory segment 
      memset(shared_buf, 0, SHM_SIZE);   // zeroize shared_buf
      fd = popen(buf.mtext, "r");

      str_len = 0;
      while(fgets(shared_buf + str_len, SHM_SIZE, fd) != NULL)
      { str_len = strlen(shared_buf); }

      pclose(fd);
      // end: shared memory segment 
   }
   else { // parent 
      // Begin - message queue
      if ((key = ftok("mysh.c", 'B')) == -1) {
         perror("ftok");
         exit(1);
      }

      if ((msqid_parent = msgget(key, 0644 | IPC_CREAT)) == -1) {
         perror("msgget from parent");
         exit(1);
      }

      buf.mtype = 1;
      strncpy(buf.mtext, argv, strlen(argv));

      if(msgsnd(msqid_parent, (struct my_msgbuf*) &buf, strlen(buf.mtext), 0) == -1)
      {
         perror("msgsnd");
      }
      // End - message queue

      // Begin - shared memory
      // usleep(10000);
      fprintf(stderr, "%s", shared_buf);
      // End - shared memory 
   } // fork end
}  

int parse_cmd(char *buf, char **vbuf, char *errbuf) 
{
   int i=0;
   char *delim=" ,\t\n";
   char *tok;

   tok=strtok(buf,delim);

   while (tok) {
      vbuf[i]=(char *)malloc(BUFSZ*sizeof(char));
      strcpy(vbuf[i],tok);
      tok=strtok(NULL,delim);
      i++;
   }
   
   vbuf[i]=0;
   return i;
}

int main(int argc, char **argv) 
{
   int linenum=0;
   char *buf=(char *)malloc(BUFSZ*sizeof(char)); 
   char *errbuf=(char *)malloc(ERRBUFSZ*sizeof(char)); 
   char *mysh = "";
   FILE *rfp=stdin;

   if (isatty(fileno(rfp))) {
      mysh = "mysh (Ctrl-C to exit)>";
      fprintf(stderr,"%s",mysh);
   }

   while(1)
   {
        if (fgets(buf, BUFSZ, rfp) == NULL)
        { fprintf(stderr, "fgets error\n"); }

        linenum++;

        if (*buf)
        {  
	   int i=0; int numargs;
           char *vbuf[128];

           char* copy = (char *) malloc(strlen(buf) + 1);

   	   strcpy(copy, buf);
           numargs = parse_cmd(copy,vbuf,errbuf);
           process_cmd_ipc(buf,linenum, errbuf);

           for (i=0;i<numargs; i++) { free(vbuf[i]); }
           free(copy);
           copy = NULL;
	}
   
        if (mysh) 
            fprintf(stderr,"%s",mysh);
   }
}

Make command:
==================

gcc -Wall -o ./mysh ./mysh.c

#2 2014-04-10 01:08 PM

RobSeace
Administrator
From: Boston, MA
Registered: 2002-06-12
Posts: 3,826
Website

Re: Interprocess Communication (IPC) problem

Ugh, I hate the ugly old SysV IPC interfaces...  I can't believe they're still teaching those instead of the Posix versions (which, while still ugly, are much less so, at least)...

Your basic problem is that the parent is trying to print out "shared_buf" before the child has had a chance to fill it in with the command output yet...  You need some further synchronization between parent and child, so the parent can wait until the child has finished processing the command's output before trying to display it...  How you want to do that is up to you (or whoever wrote your obvious homework assignment)...  If you want to stick with SysV IPC stuff, you could use semaphores (semget(), semop(), etc.); start with it at one, have the parent wait for it to become zero, and the child decrement it down to zero after it finishes...  Or, you could just send a signal from child to parent, or send a message through a pipe or whatever...  In fact, the easiest thing to do would probably just have the parent do a waitpid() on the child, and wait for it to die, and then it will know that it's done...  However, in your code you never have the child exit(), which is a problem, so you'll have to add that to the child code after the pclose()...

Offline

#3 2014-04-14 05:01 PM

Tera
Guest

Re: Interprocess Communication (IPC) problem

RobSeace wrote:

Ugh, I hate the ugly old SysV IPC interfaces...  I can't believe they're still teaching those instead of the Posix versions (which, while still ugly, are much less so, at least)...

Your basic problem is that the parent is trying to print out "shared_buf" before the child has had a chance to fill it in with the command output yet...  You need some further synchronization between parent and child, so the parent can wait until the child has finished processing the command's output before trying to display it...  How you want to do that is up to you (or whoever wrote your obvious homework assignment)...  If you want to stick with SysV IPC stuff, you could use semaphores (semget(), semop(), etc.); start with it at one, have the parent wait for it to become zero, and the child decrement it down to zero after it finishes...  Or, you could just send a signal from child to parent, or send a message through a pipe or whatever...  In fact, the easiest thing to do would probably just have the parent do a waitpid() on the child, and wait for it to die, and then it will know that it's done...  However, in your code you never have the child exit(), which is a problem, so you'll have to add that to the child code after the pclose()...

Thank you very much for the reply.
Yes, wait(&status) and the exit() in child process solved the problem nicely.
Why does the lack of exit() in the child process cause a problem?

Regards,

#4 2014-04-14 08:29 PM

RobSeace
Administrator
From: Boston, MA
Registered: 2002-06-12
Posts: 3,826
Website

Re: Interprocess Communication (IPC) problem

Why does the lack of exit() in the child process cause a problem?

Because, without it the child continues running...  Which means it will return from your process_cmd_ipc() function back into main(), at which point IT will start reading from stdin via the fgets() loop there, competing with the parent for input, and THEN possibly fork()'ing children of its own by calling process_cmd_ipc() itself!

Also, you probably want to do shmdt() at least in the parent to detach the shared memory before returning...  Otherwise, you'll reattach to it again every time you enter the function, creating an unnecessary new mapping to the same shared memory...

Offline

Board footer

Powered by FluxBB