Question: Please help complete this C program genie.h #define _POSIX_C_SOURCE 200809L #include pid_t create_genie(const char* command, FILE* fp[2]); int close_genie(pid_t pid); int destroy_genie(pid_t pid); int active_genies();
Please help complete this C program
genie.h
#define _POSIX_C_SOURCE 200809L
#include
pid_t create_genie(const char* command, FILE* fp[2]); int close_genie(pid_t pid); int destroy_genie(pid_t pid); int active_genies();
genie.c
#define _POSIX_C_SOURCE 200809L
#include #include #include #include #include #include #include #include "genie.h"
// Declare any necessary macros, types, and global variables here // TODO /* * Similar to system(), create_genie() uses fork() to create a genie process * that executes 'command' using execl() as follows: * execl("/bin/sh", "sh", "-c", command, (char *)NULL); * Additionally, create_genie() establishes two uni-directional pipes * connected to the stdin and stdout of the genie process, and * associates high-level streams for bi-directional communication * with it. Specifically, when create_genie() returns, * fp[0] is a FILE* pointer that can be used to read the stdout of the genie, * and fp[1] is a FILE* pointer that can be used to write to its stdin. * The return value is the process ID of the genie process, or -1 on error. */
pid_t create_genie(const char* command, FILE* fp[2]) { //TODO
return -1; }
/* * close_genie closes the stream used to send input to genie 'pid'. * This sends an EOF to the genie, allowing it to complete its computation. * The return value is 'pid' on success, -1 on error */ int close_genie(pid_t pid) { // TODO
return -1; }
/* * destroy_genie closes open streams used to communicate with * the genie process 'pid' and reaps the genie process. * The return value is the status returned by the genie, or -1 on error. */ int destroy_genie(pid_t pid) { // TODO
return -1; }
/* * Return the number of genie processes that have been created and not yet destroyed */ int active_genies() { // TODO
return 0; }
/* * test genie functions: do not change the code below */
#define BUF_LEN 1024
#ifndef TEST
int main() { char* message[] = { "English: Hello World!", "French: Bonjour, le monde!", "Spanish: Hola al mundo", "Klingon: Nuq neH!", "German: Guten Tag, Welt!", "Russian: Zdravstvuyte, mir!", "Japan: Sekai e konnichiwa!", "Latin: Orbis, te saluto!" };
int n = sizeof(message) / sizeof(char*); pid_t pid[n]; char md5digest[32];
FILE* fp[2];
for (int i = 0; i < n; i++) { pid[i] = create_genie("md5sum", fp); fprintf(fp[1], "%s ", message[i]); close_genie(pid[i]); // done sending input to this genie fscanf(fp[0], "%32s -", md5digest); printf("sent %s, got %s ", message[i], md5digest); printf("Active genies: %d ", active_genies()); }
for (int i = 0; i < n; i++) { destroy_genie(pid[i]); printf("Active genies: %d ", active_genies()); }
return 0; }
#endif
PROBLEM STATEMENT
one limitation of popen() is that the parent process can communicate with the child in only one direction, either by writing to its standard input or by reading its standard output, but not both. Since bi-directional communication with a child process is often needed, in this homework you will implement a generalization of the popen/pclose functions that will allow you to easily execute shell commands from your programs while being able to bi-directionally communicate with the child processes executing them.
Your task will be to implement the following four functions: pid_t create_genie ( const char * command , FILE * fp [2]) ; int close_genie ( pid_t pid ) ; int destroy_genie ( pid_t pid ); int active_genies () ;
Similar to the library function system(), create genie() uses fork() to create a child process (called genie) that executes the command command by executing execl ("/ bin / sh " , " sh " , " -c" , command , ( char *) NULL );
Additionally, create genie() creates two uni-directional pipes connected to the standard input and standard output of the genie process, and associates high-level streams for bi-directional communication with it. Specifically, when create genie() returns, fp[0] is a FILE* pointer that the parent can use to read the standard output of the genie, and fp[1] is a FILE* pointer that the parent can use to write to its standard input. The return value of create genie() is the process ID of the genie process if its creation succeeds, or -1 on error.
close genie() takes as argument the process ID returned by a previous create genie() call and closes the stream used to send input to the corresponding genie process. This sends an EOF to the genie, allowing it to complete its computation. The return value of close genie() is the process ID of the child unless an error occurs in which case the return value is -1.
destroy genie() takes as argument the process ID returned by a previous create genie() call, closes any open streams used to communicate with the corresponding genie, and reaps the genie process. Note that in some applications calling close genie() on a genie process may not be necessary. Thus, in addition to the stream used to read the standard output of the genie process, destroy genie() may also need to close the stream used to send input to it. The return value of destroy genie() is the status returned by the genie, or -1 on error.
Finally, active genies() is a convenience function that returns the number of genie processes that have been created and not yet destroyed. Your implementation should support at least 1,024 concurrent genies.
Step by Step Solution
There are 3 Steps involved in it
Get step-by-step solutions from verified subject matter experts
