I am using C programming language, and gcc compiler of C 99 standard. A program of mine is stuck during wait(NULL) of a parent process. There are three programs I am using. All are using command-line arguments.
Because I am also using file-redirection:
The program of the parent process is called foo. It executes another program called goo, and goo executes a third program called hoo.
If I just execute goo, this works fine. I can provide test files for example that I get valid resulsts with them. This is weird, because I would have expect that goo would be in an endless run, what does not happen.
I am adding code in case this is not some fundamental issue. Currently my main issue is that wait() is stuck within foo and not the functionality!
Foo.c
#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <math.h>
#include <string.h>
int main(int argc, char* argv[])
{
// Program use: there are m files.
// It needs to execute goo for each different file.
int i = 0, output_fd = open(file_name, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (output_fd < 0)
{
fprintf(stderr, "*** ERROR: *** open failed!\n");
return 1;
}
for(i = 2; i < argc; i++)
{
int pid = fork();
if (pid == 0)
{
char* arg_vec[3] = { "goo", argv[i], NULL };
dup2(output_fd, STDOUT_FILENO);
execve("goo", arg_vec, NULL); // Check why it's execution does not end?
fprintf(stderr, "*** ERROR: *** execve failed!\n");
return 1;
}
else if (pid < 0)
{
fprintf(stderr, "*** ERROR: *** fork failed!\n");
return 1;
}
}
while(wait(NULL) > 0)
{
}
close(output_fd);
return 0;
}
goo.c
#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <math.h>
#include <string.h>
char** create_argv(char* student_details_line);
int main(int argc, char* argv[])
{
// Program use: read a file of n lines, each lines consists details for n different students.
// For each student, a fork() called, and then executes hoo program.
char* student_details_line = NULL;
size_t len;
int num_stud = 0, input_fd = open("hoo", stdin), output_fd = open(file_name, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (input_fd < 0 || output_fd < 0)
{
fprintf(stderr, "*** ERROR: *** file descriptor failed!\n");
return 1;
}
// Reading input from stdin
FILE* input_file = fdopen(input_fd, "r");
if (input_file == NULL) {
perror("Error opening input file");
exit(EXIT_FAILURE);
}
while (getline(&student_details_line, &len, input_file) != -1)
{
int pid = fork();
if (pid == 0)
{
char** arg_vec = create_argv(student_details_line);
dup2(input_fd, STDIN_FILENO);
dup2(output_fd, STDOUT_FILENO);
execve("hoo", arg_vec, NULL);
fprintf(stderr, "*** ERROR: *** execve failed!\n");
return 1;
}
else if (pid < 0)
{
fprintf(stderr, "*** ERROR: *** fork failed!\n");
return -1;
}
else
num_stud++;
}
while(wait(NULL) > 0)
{
}
fclose(input_file);
close(input_fd);
close(output_fd);
printf("There are %d students\n", num_stud);
return 1;
}
char** create_argv(char* student_details_line)
{
int pid = getpid(), size = 0, max_arguments = 2;
char** arguments_arr = (char**)malloc(max_arguments * sizeof(char*));
if (arguments_arr == NULL)
{
fprintf(stderr, "*** ERROR: *** malloc failed!\n");
_exit(1);
}
arguments_arr[size++] = strdup("hoo"); // Program name
// Get the first token
char* token = strtok(student_details_line, "\n\b\t ");
arguments_arr[size++] = strdup(token);
// Walk through other tokens
while (1)
{
// Reallocate array
if (max_arguments == size)
{
max_arguments = max_arguments * 2;
char** new_arguments_arr = (char**)realloc(arguments_arr, max_arguments * sizeof(char*));
if (new_arguments_arr == NULL)
{
fprintf(stderr, "*** ERROR: *** realloc failed!\n");
free(arguments_arr);
_exit(1);
}
arguments_arr = new_arguments_arr;
}
// Get new token, add it to arguments vector and update the amount of arguments
if ((token = strtok(NULL, "\n\b\t ")) != NULL)
arguments_arr[size++] = strdup(token);
// No more tokens
else
break;
}
// Reallocate array
if (max_arguments == size)
{
max_arguments = max_arguments * 2;
char** new_arguments_arr = (char**)realloc(arguments_arr, max_arguments * sizeof(char*));
if (new_arguments_arr == NULL)
{
fprintf(stderr, "*** ERROR: *** realloc failed!\n");
free(arguments_arr);
_exit(1);
}
arguments_arr = new_arguments_arr;
}
// Function's output
return arguments_arr;
}
hoo.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
int main(int argc, char* argv[])
{
// Program use: returns a name of a student and his average grade in one-liner
double average_grade = 0;
int total_grades = 0;
// Iterate over other arguments (grades only)
for (int i = 2; 0 < argc && i < argc; i++)
{
char* end_ptr = NULL;
int grade = strtol(argv[i], &end_ptr, 10);
int ptr_size = strlen(end_ptr);
for (int j = 0; j < ptr_size; j++)
{
if (14 <= end_ptr[j])
{
fprintf(stderr, "Argument %s is non-integer\n", argv[i]);
return 1;
}
}
average_grade += grade;
total_grades++;
}
// Prints student name and his average grade
if (total_grades == 0)
fprintf(stdout, "%s NaN\n", argv[1]);
else
{
average_grade = average_grade / total_grades;
fprintf(stdout, "%s %.1f\n", argv[1], average_grade);
}
return 0;
}
Makefile
# Makefile for ex2_q1 spring 2023B
CFLAGS = -Wall -std=c99
LDFLAGS = -lm
CC = gcc
ECHO = @echo "going to build target $@ (dependent on $^)"
PROG1 = one_student
PROG2 = read_grades
PROG3 = ex2_q1
PROGS = $(PROG1) $(PROG2) $(PROG3)
all: $(PROGS) test
$(PROG1): $(PROG1).c $(PROG3).h
$(ECHO)
$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@
$(PROG2): $(PROG2).c $(PROG3).h
$(ECHO)
$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@
$(PROG3): $(PROG3).c $(PROG3).h
$(ECHO)
$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@
clean:
rm -vf *.o ${PROG} all_std.log *.temp
test: $(PROGS)
@echo going to run test...
./$(PROG3) readers_msg.txt gr_1.txt
gr_1.txt
Avi 80 90 75
Beni 90
Gadi 70 9 90 100
I am sorry for the amount of code lines. Really thankful for helpers...
As I understand it, foo
is waiting endlessly because the various goo
processes aren’t exiting: they’re stuck waiting for input. If you either change foo
to redirect goo
’s standard input to read from the file it’s supposed to process, or change goo
to read from the file given in its arguments instead of its standard input, everything should work.