Program run in child process doesn't loop
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);
}
}
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.
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);
}
}
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...)
.
精彩评论