Answered step by step
Verified Expert Solution
Question
1 Approved Answer
Genie in a bottle In previous assignments you have used the popen() library function, which opens a child process by creating a pipe, forking, and
Genie in a bottle In previous assignments you have used the popen() library function, which "opens a child process by creating a pipe, forking, and invoking the shell to execute a command given as argument. However, 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", "--", 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. The template code includes a main function exercising these functions by creating genies to compute the 128-bit MD5 checksum of welcome messages in various languages. The expected output from the program is as follows: $ ./genie sent English: Hello world!, got 8be8bed482a7ef78c8a9d33e34c527e9 Active genies: 1 sent French: Bonjour, le monde!, got adf410ea0314b68c87e9a20918f8d526 Active genies: 2 sent Spanish: Hola al mundo, got 6701c9c86a51376b468afa3c23e1d0ec Active genies: 3 Active genies: 4 sent German: Guten Tag, Welt!, got e4895ad70386f8963e76b221fc45b0be Active genies: 5 sent Russian: Zdravstvuyte, mir!, got f306509582fd02f197d7c4847bdeaba5 Active genies: 6 sent Japan: Sekai e konnichiwa!, got 470519324022497d67e364eaa4005284 Active genies: 7 sent Latin: Orbis, te saluto!, got d88c52eae13bafb0c98f31e4538b2087 Active genies: 8 Active genies: 7 Active genies: 6 Active genies: 5 Active genies: 4 Active genies: 3 Active genies: 2 Active genies: 1 Active genies: 0 * #define _POSIX_C_SOURCE 200809L 2 3 #include 4 #include 5 #include 6 #include 7 #include 8 #include 9 #include 10 #include "genie.h" 11 12 // Declare any necessary macros, types, and global variables here 13 // TODO 14 15 16 17 18 - /* 19 * Similar to system(), create_genie() uses fork() to create a genie process 20 * that executes 'command' using execl as follows: 21 execl("/bin/sh", "sh", "-", command, (char *) NULL); 22 * Additionally, create_genie() establishes two uni-directional pipes 23 * connected to the stdin and stdout of the genie process, and 24 * associates high-level streams for bi-directional communication 25 * with it. Specifically, when create_genie() returns, 26 * fp[@] is a FILE* pointer that can be used to read the stdout of the genie, 27 * and fp[1] is a FILE* pointer that can be used to write to its stdin. 28 * The return value is the process ID of the genie process, or -1 on error. 29 */ 30 31 pid_t create_genie(const char *command, FILE* fp[2]) 32 * { 33 //TODO 34 35 return -1; 36 } 37 38 39 /* 40 close_genie closes the stream used to send input to genie 'pid'. 41 * This sends an EoF to the genie, allowing it to complete its computation. 42 * The return value is 'pid' on success, -1 on error 43 44 int close_genie (pid_t pid) 45 - { 46 // TODO 47 48 return -1; 49 } 50 51 52 53" /* * destroy_genie closes open streams used to communicate with 55 * the genie process 'pid' and reaps the genie process. 56 * The return value is the status returned by the genie, or -1 on error. 57 58 int destroy_genie(pid_t pid) 59 * { * 54 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; } Genie in a bottle In previous assignments you have used the popen() library function, which "opens a child process by creating a pipe, forking, and invoking the shell to execute a command given as argument. However, 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", "--", 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. The template code includes a main function exercising these functions by creating genies to compute the 128-bit MD5 checksum of welcome messages in various languages. The expected output from the program is as follows: $ ./genie sent English: Hello world!, got 8be8bed482a7ef78c8a9d33e34c527e9 Active genies: 1 sent French: Bonjour, le monde!, got adf410ea0314b68c87e9a20918f8d526 Active genies: 2 sent Spanish: Hola al mundo, got 6701c9c86a51376b468afa3c23e1d0ec Active genies: 3 Active genies: 4 sent German: Guten Tag, Welt!, got e4895ad70386f8963e76b221fc45b0be Active genies: 5 sent Russian: Zdravstvuyte, mir!, got f306509582fd02f197d7c4847bdeaba5 Active genies: 6 sent Japan: Sekai e konnichiwa!, got 470519324022497d67e364eaa4005284 Active genies: 7 sent Latin: Orbis, te saluto!, got d88c52eae13bafb0c98f31e4538b2087 Active genies: 8 Active genies: 7 Active genies: 6 Active genies: 5 Active genies: 4 Active genies: 3 Active genies: 2 Active genies: 1 Active genies: 0 * #define _POSIX_C_SOURCE 200809L 2 3 #include 4 #include 5 #include 6 #include 7 #include 8 #include 9 #include 10 #include "genie.h" 11 12 // Declare any necessary macros, types, and global variables here 13 // TODO 14 15 16 17 18 - /* 19 * Similar to system(), create_genie() uses fork() to create a genie process 20 * that executes 'command' using execl as follows: 21 execl("/bin/sh", "sh", "-", command, (char *) NULL); 22 * Additionally, create_genie() establishes two uni-directional pipes 23 * connected to the stdin and stdout of the genie process, and 24 * associates high-level streams for bi-directional communication 25 * with it. Specifically, when create_genie() returns, 26 * fp[@] is a FILE* pointer that can be used to read the stdout of the genie, 27 * and fp[1] is a FILE* pointer that can be used to write to its stdin. 28 * The return value is the process ID of the genie process, or -1 on error. 29 */ 30 31 pid_t create_genie(const char *command, FILE* fp[2]) 32 * { 33 //TODO 34 35 return -1; 36 } 37 38 39 /* 40 close_genie closes the stream used to send input to genie 'pid'. 41 * This sends an EoF to the genie, allowing it to complete its computation. 42 * The return value is 'pid' on success, -1 on error 43 44 int close_genie (pid_t pid) 45 - { 46 // TODO 47 48 return -1; 49 } 50 51 52 53" /* * destroy_genie closes open streams used to communicate with 55 * the genie process 'pid' and reaps the genie process. 56 * The return value is the status returned by the genie, or -1 on error. 57 58 int destroy_genie(pid_t pid) 59 * { * 54 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; }
Step by Step Solution
There are 3 Steps involved in it
Step: 1
Get Instant Access to Expert-Tailored Solutions
See step-by-step solutions with expert insights and AI powered tools for academic success
Step: 2
Step: 3
Ace Your Homework with AI
Get the answers you need in no time with our AI-driven, step-by-step assistance
Get Started