Answered step by step
Verified Expert Solution
Link Copied!

Question

1 Approved Answer

Need help with a Distributed Systems problem in C please! Will upvote Purpose: To go over multiprocessing on a single machine: pipes/socket pairs fork()/execl() Overview:

Need help with a Distributed Systems problem in C please! Will upvote

Purpose:

To go over multiprocessing on a single machine:

  • pipes/socket pairs
  • fork()/execl()

Overview:

bc is a command line calculator program. We will give it a simple text window interface.

Computing

Please ssh into one of the following: or use your own Unix machine.

  • 140.192.36.185
  • 140.192.36.186
  • 140.192.36.187

  1. Please copy-and-paste the following files (0 Points):

    interactiveCalc.c

    /*-------------------------------------------------------------------------* *--- ---* *--- interactiveCalc.c ---* *--- ---* *--- An interactive calculator. ---* *--- ---* *--- ---- ---- ---- ---- ---- ---- ---- ---- ---* *--- ---* *--- Version 1a 2020 January 8 Joseph Phillips ---* *--- ---* *-------------------------------------------------------------------------*/ // // Compile with: // $ g++ interactiveCalc.c -o interactiveCalc -lncurses -g // // NOTE: // If this program crashes then you may not see what you type. // If that happens, just type: // // stty sane // // to your terminal, even though you cannot even see it. //--- ---// //--- Header file inclusions: ---// //--- ---// #include  #include  #include  #include  // For alarm() #include  #include  #include  // For creat() #include  // For creat(), wait() #include  // For creat() #include  // For creat() #include  #include  //--- ---// //--- Definitions of constants: ---// //--- ---// #define DEFAULT_CALC_PROGRAM "/usr/bin/bc" #define CALC_ARG1 "-l" #define BC_QUIT_CMD "quit" const int HEIGHT = 5; const int WIDTH = 64; const int INIT_TEXT_LEN = 1024; const int MAX_TEXT_LEN = 65536; const char STOP_CHAR = (char)27; const char CALC_CHAR = (char)' '; const int BUFFER_LEN = 4096; const int TYPING_WINDOW_BAR_Y = 0; const int CHECKING_WINDOW_BAR_Y = TYPING_WINDOW_BAR_Y + HEIGHT + 1; const int MESSAGE_WINDOW_BAR_Y = CHECKING_WINDOW_BAR_Y + HEIGHT + 1; const int NUM_MESSAGE_SECS = 4; //--- ---// //--- Definitions of global vars: ---// //--- ---// WINDOW* typingWindow; WINDOW* answerWindow; WINDOW* messageWindow; int shouldRun = 1; int hasChildStopped = 0; // YOUR CODE HERE: add some global variable(s) //--- ---// //--- Definitions of global fncs: ---// //--- ---// // PURPOSE: To turn 'ncurses' on. No parameters. No return value. void onNCurses () { // I. Application validity check: // II. Turn 'ncurses' on: const int LINE_LEN = 80; char line[LINE_LEN]; initscr(); cbreak(); noecho(); nonl(); //intrflush(stdscr, FALSE); //keypad(stdscr, TRUE); typingWindow = newwin(HEIGHT,WIDTH,TYPING_WINDOW_BAR_Y+1,1); answerWindow = newwin(HEIGHT,WIDTH,CHECKING_WINDOW_BAR_Y+1,1); messageWindow = newwin( 1,WIDTH,MESSAGE_WINDOW_BAR_Y,1); scrollok(typingWindow,TRUE); scrollok(answerWindow,TRUE); snprintf(line,LINE_LEN,"'Esc' to quit. Enter to calculate"); mvaddstr(TYPING_WINDOW_BAR_Y,0,line); mvaddstr(CHECKING_WINDOW_BAR_Y,0,"Answers:"); refresh(); wrefresh(typingWindow); // moves cursor back to 'typingWindow': // III. Finished: } // PURPOSE: To handle the 'SIGCHLD' signal. 'sig' will be 'SIGCHLD' and // will be ignored. No return value. void sigChildHandler (int sig ) { int status; wait(&status); hasChildStopped = 1; } // PURPOSE: To handle the 'SIGALRM' signal. 'sig' will be 'SIGALRM' and // will be ignored. No return value. void sigAlarmHandler (int sig ) { // Do not worry, literally does nothing } // PURPOSE: To launch the 'bc' calculator. If 'argc' is at least 2 then // 'argv[1]' will be run. If 'argc' is less then 2 then // 'DEFAULT_CALC_PROGRAM' will be run. No return value. void launchBc (int argc, char* argv[] ) { // I. Application validity check: // II. Attempt to launch 'bc' // YOUR CODE HERE (see (3)) // III. Finished: } // PURPOSE: To save the 'lineIndex' chars at the beginning of 'line' to // to position '*endTextPtrPtr' in buffer '*bufferPtrPtr' of length // '*bufferLenPtr' and with end '*endBufferPtrPtr'. If there is not // enough space in '*bufferPtrPtr' then '*bufferLenPtr' will be doubled, // and '*bufferPtrPtr' will be 'realloc()'-ed to this new length. // No return value. void saveLine (size_t* bufferLenPtr, char** bufferPtrPtr, char** endTextPtrPtr, char** endBufferPtrPtr, const char* line, int lineIndex ) { // I. Application validity check: // II. Save 'line' to '*bufferPtrPtr': // II.A. Allocate more space if needed: if (lineIndex >= (*endBufferPtrPtr - *endTextPtrPtr + 1) ) { size_t textLen = *endTextPtrPtr - *bufferPtrPtr; (*bufferLenPtr) *= 2; (*bufferPtrPtr) = (char*)realloc(*bufferPtrPtr,*bufferLenPtr); (*endTextPtrPtr) = *bufferPtrPtr + textLen; (*endBufferPtrPtr) = *bufferPtrPtr + *bufferLenPtr; } // II.B. Save 'line' to '*bufferPtrPtr': memcpy(*endTextPtrPtr,line,lineIndex); (*endTextPtrPtr) += lineIndex; // III. Finished: } // PURPOSE: To attempt to send the text pointed to by 'bufferPtr' to the // bc-running child process. 'endTextPtr' points to one char beyond // the end of the text to send in 'bufferPtr'. No return value. // // SIDE EFFECT: Prints to 'answerWindow' void calculate (const char* outputBufferPtr, const char* endTextPtr ) { // I. Application validity check: // II. Send 'outputBufferPtr' to calculator: int numBytes; char inputBuffer[BUFFER_LEN]; // See (4) // YOUR CODE HERE TO SEND endTextPtr-outputBufferPtr BYTES POINTED TO BY outputBufferPtr alarm(1); numBytes = 0; // CHANGE THAT 0. // YOUR CODE HERE TO RECEIVE RESPONSE INTO inputBuffer[] alarm(0); if (numBytes > 0) { if ( (endTextPtr[-1] == ' ') || (endTextPtr[-1] == ' ') ) { endTextPtr--; } waddnstr(answerWindow,outputBufferPtr,endTextPtr-outputBufferPtr); waddstr (answerWindow," = "); inputBuffer[numBytes] = '\0'; waddstr(answerWindow,inputBuffer); wrefresh(answerWindow); wrefresh(typingWindow); // moves cursor back to 'typingWindow': } // III. Finished: } // PURPOSE: To allow the user to type, display what they type in // 'typingWindow', and to send what they type to the spell checking // process upon pressing 'Enter'. 'vPtr' comes in, perhaps pointing // to something. Returns 'NULL'. void* type (void* vPtr ) { // I. Application validity check: // II. Handle user typing: unsigned int c; char line[WIDTH+1]; int index = 0; size_t bufferLen = INIT_TEXT_LEN; char* bufferPtr = (char*)malloc(bufferLen); char* endTextPtr = bufferPtr; char* endBufferPtr = bufferPtr + bufferLen; // II.A. Each iteration handles another typed char: while ( (c = getch()) != STOP_CHAR ) { // II.A.1. Handle special chars: if (c == ' ') { // II.A.1.a. Treat carriage return like newline: c = ' '; } else if ( (c == 0x7) || (c == 127) ) { // II.A.1.b. Handle backspace: int col = getcurx(typingWindow); if (col > 0) { index--; wmove(typingWindow,getcury(typingWindow),col-1); wrefresh(typingWindow); } continue; } else if (c == ERR) { continue; } // II.A.2. Print and record the char: waddch(typingWindow,c); wrefresh(typingWindow); line[index++] = c; // II.A.3. Handle when save 'line': if (c == ' ') { // II.A.3.a. Save 'line' when user types newline: size_t textLen = endTextPtr - bufferPtr; saveLine(&bufferLen,&bufferPtr,&endTextPtr,&endBufferPtr,line,index); index = 0; calculate(bufferPtr,endTextPtr); endTextPtr = bufferPtr + textLen; continue; } else if (index == WIDTH-1) { // II.A.3.b. Save 'line' when at last column: line[index] = ' '; index++; saveLine(&bufferLen,&bufferPtr,&endTextPtr,&endBufferPtr,line,index); index = 0; waddch(typingWindow,' '); wrefresh(typingWindow); } } // III. Finished: saveLine(&bufferLen,&bufferPtr,&endTextPtr,&endBufferPtr,line,index); free(bufferPtr); // YOUR CODE HERE TO TELL THE bc PROCESS TO END ITSELF, see (5) return(NULL); } // PURPOSE: To turn off 'ncurses'. No parameters. No return value. void offNCurses () { sleep(1); nl(); echo(); refresh(); delwin(messageWindow); delwin(typingWindow); delwin(answerWindow); endwin(); } // PURPOSE: To do the spell-checking word-processor. Ignores command line // arguments. Return 'EXIT_SUCCESS' to OS. int main (int argc, char* argv[] ) { // YOUR CODE HERE (see (2)) onNCurses(); launchBc(argc,argv); type(NULL); offNCurses(); while (!hasChildStopped) { sleep(1); } return(EXIT_SUCCESS); } 

  2. The action starts, of course, in main(). The first thing that main() should do is to install two simple signal handlers:
    Signal: Handler to run:
    SIGCHLD sigChildHandler()
    SIGALRM sigAlarmHandler()
    After that, mainy-main:
    • turns the windowing on (onNCurses(), already done)
    • starts bc (launchBc(), you must finish)
    • lets the user type expressions (type() is done, but it calls calculcate() which you must finish)
    • turns the windowing off (offNCurses(), already done)
    • hangs out until bc process has finished (already done)
  3. launchBc() takes the same argc and argv arguments as mainy-main because the user can give the path to bc on the command line. launchBc() should make the pipes or socket pairs for a child process to talk to its mama process. Then it should make the child process.

    The child process should close() unnecessary file descriptors and redirect both STDIN_FILENO and STDOUT_FILENO to use the pipes/socket pairs. It should then, of course, try to run argv[1] if there is an argument on the command line, or DEFAULT_CALC_PROGRAM if there is none. Either way, it should give CALC_ARG1 as the sole command line argument.

    The mama process should also close() unnecessary file descriptors, but it should save necessary file descriptor(s) in global variables. They will be used by calculate().

  4. You must finish calculate(), though. Send the endTextPtr-outputBufferPtr bytes pointed to by outputBufferPtr to the bc process via your file descriptor.

    Then do:

    • alarm(1)
    • Get the response from the bc process, putting its bytes in inputBuffer[] and setting numBytes equal to the number of bytes received.
    • alarm(0)
    Not all bc calls will give a response. So the purpose of the alarm(1) call is to say: "Hey OS! Wake me up in 1 second if I have not received anything yet." The purpose of the alarm(0) call is to say: "Hey OS! Nevermind, I am finished getting input."

    Keep the other code in calculate(). It displays the answer.

  5. Most of the work is done by type(), which gets what the user types and saves it into ever expanding char buffer bufferPtr. (Already done.) However, just before the return() at the end you must send BC_QUIT_CMD to the bc process. This politely tells the bc process to end itself, without getting all rude with kill -9 or anything that extreme.
  6. Add whatever variables you want (within reason).
  7. Now run the bad boy! Type an expression, and press Enter. Press Esc to quit.

Sample output:

'Esc' to quit. Enter to calculate s(3.141592) s(3.141292/4) j=3 j^j Answers: 5+6 = 11 s(3.141592) = .00000065358979323841 s(3.141292/4) = .70705363064115213028 j^j = 27 

Sequence diagram:

 parent process | | | fork() | /execl() bc +--------------->| | | | | | | | | | write("2+2") | +--------------->|read() | | | | |<---------------+ write("4") | | | | | | | | | SIGCHLD | |<---------------+ | stops | ends

Step by Step Solution

There are 3 Steps involved in it

Step: 1

blur-text-image

Get Instant Access to Expert-Tailored Solutions

See step-by-step solutions with expert insights and AI powered tools for academic success

Step: 2

blur-text-image

Step: 3

blur-text-image

Ace Your Homework with AI

Get the answers you need in no time with our AI-driven, step-by-step assistance

Get Started

Recommended Textbook for

Database Concepts

Authors: David M. Kroenke, David J. Auer

7th edition

133544621, 133544626, 0-13-354462-1, 978-0133544626

More Books

Students also viewed these Databases questions

Question

Develop successful mentoring programs. page 418

Answered: 1 week ago