I'm trying to write the following, 2 part program. In one file ("root.c"), I read in a random string of 1's and 0's. I then split the resulting string in half, and send each half to its own process through fork(). Each child process uses execl() to run the second program ("bit_count.c").
Within bit_count.c, it:
a) checks if the length of the (half)string is 2 or less. If yes, it returns the number of
1's and 0's to it's parent process.
b) if not, it begins to recursively split the string in half, and sending each half to its own new process (replicating the procedure in root.c). This creates a binary process tree, until all pieces of the string are 2 characters long or less.
c) the count results of the left and right children are aggregated by the parent, and returned to its parent, until returning to the root process, which aggregates the highest two children, and outputs it to the user.
My problem with this project is returning the 2-character counts to the parent. My idea right now is to direct the parent's left and right read pipes to stdin with dup2(), and just to print to stdout with fprintf from the children. The select() function of the parent should catch the returning output, right?
My second problem is the format of the output. if the counts are in ints, what is the best way to return that using select() in this case? I've attached my code below, just be warned that it may be a mess - I'm rusty with C code and this is my first exposure to select() and execl().
root.c:
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char* argv[]) {
if (argc != 2) {
perror("input file name");
printf("%d", argc);
exit(1);
}
FILE* fp;
if((fp = fopen(argv[1], "r")) == NULL) {
perror("open file");
}
fseek(fp, 0, SEEK_END);
long fsize = ftell(fp);
fseek(fp, 0, SEEK_SET);
char *bits = malloc(fsize+1);
fread(bits, fsize, 1, fp);
fclose(fp);
char *left_half = malloc( fsize/2 + 1 );
char *right_half;
if (fsize%2) right_half = malloc( fsize/2 + 2 );
else right_half = malloc( fsize/2 + 1 );
if (!left_half || !right_half) perror("array split");
memcpy(left_half, bits, fsize/2);
if (fsize%2) memcpy(right_half, bits + fsize/2, fsize/2 + 1);
else memcpy(right_half, bits + fsize/2, fsize/2);
int fd_left[2], fd_right[2];
int zero, one;
int *left_res, *right_res;
pid_t left, right;
struct timeval tv;
fd_set readfds;
tv.tv_sec = 2;
tv.tv_usec = 500000;
if ((pipe(fd_left) == -1) || (pipe(fd_right) == -1)){
perror("Create pipe error");
exit(1);
}
FD_ZERO(&readfds);
FD_SET(fd_left[0], &readfds);
FD_SET(fd_right[0], &readfds);
if ((left=fork()) == 0) {
close(fd_left[0]);
execl("./bit_count", "bit_count", left_half, NULL);
perror("initiating recursion");
exit(1);
}
else if(left > 0) {
if ((right = fork())==0) {
close(fd_right[0]);
execl("./bit_count", "bit_count", right_half, NULL);
perror("initiating recursion");
exit(1);
}
else if (right > 0) {
close(fd_right[1]);
close(fd_left[1]);
char *left;
char *right;
dup2(fd_left[0], 0);
dup2(fd_right[0], 0);
int ret = select(2, &readfds, NULL, NULL, &tv);
read(fd_left[0], &left_res, 1);
read(fd_right[0], &right_res, 1);
printf("Back in root process!\n");
}
}
zero = (*right_res + *left_res);
one = (*(left_res+sizeof(int)) + *(right_res+sizeof(int)));
printf("%s had %d zeroes and %d ones\n", argv[1], zero, one);
return 0;
}
bit_count.c (only relevant part):
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char* argv[]) {
if (argc != 2) {
perror("sent bit string");
printf("%d", argc);
exit(1);
}
char *bit_string = argv[1];
int size = strlen(bit_string);
int counts[2];
counts[0] = 0;
counts[1] = 0;
if (!(size > 2)) {
int i=0;
for(; i < size; i++) {
if (bit_string[i]=='1') ++counts[1];
else ++counts[0];
}
fprintf(stdout, "%p", &counts);
fflush(stdout);
return 0;
}
}