3
votes

I have a specific question regarding the parent process reading the stdout from child. My problem is that when I run the program, the child program should execute a new program multiple times in a loop but it runs it only once and exits to the parent process. The child process is running a simple program that prints a message to stdout. Thanks in advance.

#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <assert.h>
#include <time.h>
#include <sys/wait.h>

#define ssec 1
#define fsec 0
#define secBuf 5
#define decbase 10
#define fgbuf 60

volatile sig_atomic_t aborting = 0;


void chld_handler(int sig) {
   if (sig == SIGINT) {
      aborting++;
   }
}


int rand_start(int low, int high) {
   int s;
   int r = 0;
   srand(time(NULL));

   s = rand();

   r = s % high + low;

   return r;
}


void Usage() {
   printf("Usage :schedule [-s<seconds>] [-f<seconds>] <program> <emergency> <logfile>\n");
   exit(1);
}


int main(int argc, char *argv[]) {
   /* getopt variablen */
   int opt;
   int index;

   int sflag = 0;
   int fflag = 0;

   char *svalue;
   char *fvalue;

   int sseconds = ssec;
   int fseconds = fsec;

   char *reactor;
   char *emergency;
   char *logfile;

   /* */
   char *endptr;
   /* Pipe and child */

   int pipepc1[2];
   int pipepc2[2];

   int child1_fd;
   int child2_fd;

   FILE *log;
   FILE *pipe_reader;

   char *p;
   char *buf;
   int waitFc;
   int status;

   /* prgm */
   int prg_r;
   int prg_e;

   /* termination */
   int cnt = 0;
   int start_period;
   p = malloc(fgbuf * sizeof(char));
   buf = malloc(fgbuf * sizeof(char));

   (void)signal(SIGINT, chld_handler);

   if (argc < 4) {
      Usage();
   }
   else if (argc == 4) {
      reactor = argv[1];
      emergency = argv[2];
      logfile = argv[3];
   }
   else if (argc > 4) {
      /* argumentenbehandlung*/
      while((opt = getopt(argc, argv, ":s:f:")) != -1) {
         printf("sflag %d fflag %d \n", sflag, fflag);
         printf("opt  %c \n", opt);
         printf("optind %d \n ", optind);
         switch (opt) {

         case 's':
            if (sflag == 0) {
               sflag++;
               svalue = optarg;
            }
            else {
               fprintf(stderr, "Widerholung der option -s\n");
           Usage();
            }
            break;

         case 'f':
            if (fflag == 0) {
               fflag++;
           fvalue = optarg;
            }
            else {
               fprintf(stderr, "Widerholung der option -f\n");
           Usage();
            }
            break;

         case ':' :
            fprintf(stderr, "Option -%c brauch ein argument\n", optopt);
            Usage();
            break;

         case '?' :
            fprintf(stderr, "Nicht bekannte option -%c \n", optopt);
            Usage();
            break;

         default :
            assert(0);
         }/* switch */
      }/* while getopt */

      for (index = optind; index < argc; index++) {
         if ((argc - index) == 3) {
            reactor = argv[index];
         }
         else if ((argc - index) == 2) {
            emergency = argv[index];
         }
         else if ((argc - index) == 1) {
            logfile = argv[index];
         }
      } /* for schleife*/

      /*  */
      if (sflag) {
         sseconds = (int)strtol(svalue, &endptr, decbase);
         printf("%d ssec\n", sseconds);
      }

      if (fflag) {
         fseconds = (int)strtol(fvalue, &endptr, decbase);
         printf("%d fsec\n", fseconds);
      }
   }

   /* pipeing*/
   if (pipe(pipepc1) == -1) {
      fprintf(stderr, "Fehler bei der Erzeugung der pipe\n");
      exit(1);
   }
   else {
      printf("Pipe created\n");
   }

   /* erzeuge child1*/
   child1_fd = fork();

   if (child1_fd < 0) {
      fprintf(stderr, "Fehler beim asfuehren von fork\n");
      exit(0);
   }

   if (child1_fd == 0) {
      printf("**CHILD**\n");
      /* close pipe read*/
      if (close(pipepc1[0]) == -1) {
         fprintf(stderr, "Konnte nicht das Read-Ende vom pipepc1 schliessen\n");
         exit(1);
      }

      if (close(1) == -1) {
         fprintf(stderr, "Konnte nicht das Read-Ende vom pipepc1 schliessen\n");
         exit(1);
      }

      if (dup(pipepc1[1]) !=STDOUT_FILENO) {
         fprintf(stderr, "Das setzen des Read-Endes als stdout is Fehlgeschlagen\n");
         exit(1);
      }

      if (fseconds == 0) {
         start_period = sseconds;
      }
      else
         start_period = rand_start(sseconds, (sseconds + fseconds));

      for (cnt = 0; cnt < 5; cnt++) {
         sleep(start_period);
         fflush(stdout);
         prg_r = execl(reactor, "", NULL);
         //printf("prg_r ist %d  \n", prg_r);                                                                                                                
      }

      if (close(pipepc1[1]) == -1) {
         fprintf(stderr, "Das neue stdout konnte nich geschlossen werden\n");
         exit(1);
      }
   }
   else {
      printf("**PARENT**\n");

      log = fopen(logfile, "w");

      /* schliesse pipe read*/
      close(pipepc1[1]);

      pipe_reader = fdopen(pipepc1[0], "r");

      while ((buf = fgets(p, fgbuf, pipe_reader)) != NULL) {
         printf("from Child : %s \n", buf);
         fflush(pipe_reader);
      }

      fclose(log);

      waitFc = waitpid(child1_fd, &status, 0);

      if (waitFc == -1) {
         fprintf(stderr, "Das Warten ist fehlgeschlagen\n");
         exit(1);
      }

      printf("child is done\n und waitFc = %d\n und satus %d", waitFc, status);
      fclose(pipe_reader);
      close(pipepc1[1]);
   }

   printf("argc = %d \n", argc);
   exit(0);
}

and the reactor program :

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main() {
   srand(time(NULL));
   int i;
   int s;

   s = rand() % 7;
   /* printf("%d \n", s);*/

   if (s != 6) {
      printf("OK\n");
      fflush(stdout);
   }
   else {
      printf("PRESSURE TOO HIGH - IMMEDIATE SHUTDOWN REQUIRED");
      exit(EXIT_FAILURE);
   }
}
3
You really need to trim this code down and explain what it's supposed to do and what it's doing if you want someone to help you debug it.R.. GitHub STOP HELPING ICE
OK, I apologize. The parent process forks a child process which runs a new program provided by the argument <reactor> and it should be executed in a loop. The parent and child communicate over a pipe whereas the child's stdout is the write end of the pipe. The parent reads form the pipe and prints it. I hope that is description enoughRobin
. : TO cut to the point, how do I make the new program run for how long I want or until a specific action occurs.Robin

3 Answers

2
votes

Well... you use fork() call to create a child process then execl() to execute another program. The problem is execl() replaces current proces image (your child process) with the image of the command you are executing. So at the end of first pass of for() loop your program gets replaced by the executing command. When it finishes it's job, it just simply quits, terminating the child process.

I think what you need to do is to call popen() instead of execl(). This will cause command to get executed in a separate process, rather than replacing your current process. If you want, you can even start all the commands at once (calling popen() in a loop) and then use select()/epool() to read data from child processes as soon as it becomes available.

2
votes

It will not loop inside the child process because you are doing exec which typically means that it overlays the child process and will exit. If you want to loop , you will have to spawn another child process from your loop in which you will typically do only exec, so as it iterates it will spawn a child process inside which you do exec it will overlay and exit. So what you need to do is the following:-

for(cnt = 0; cnt < 5; cnt++){
    sleep(start_period);
    fflush(stdout);
    child2_fd = fork();
    if (child2_fd == 0){
       prg_r = execl(reactor,"",NULL);
    }
}
0
votes

You are calling upon the reactor program as if it were a library function. This answer is based on the assumption that that is what you Really Wanted. (Maybe a false assumption here but perhaps not for others.)

That is, you want a block of code, currently expressed in reactor.c:main(), to repeat in a loop. You have already taken care to create a separate process with fork(). So another solution is to restructure the whole project: mandate the role of reactor.c as a library (libreactor.a:reactor_func(int argc, char *argv[]) where the reactor code is re-factored into a callable function) rather than as an opaque executable (reactor:main()), and linked at compile-time to the top executable. Then execl(reactor_executable_path, args...) becomes simply: reactor_func(args...).