CSE4001 Spr. 2004 Exam #2, open book, open notes. Name ___________________ 1. What 2 things does a system call usually do in case of an error? (5 pts) ANSWER: set errno and return -1 2. How many processes are created when the following program is run? (5 pts) main() { fork(); fork(); fork(); } ANSWER: 8 3. What is a zombie? List 2 events that will kill a zombie. (10 pts) ANSWER: A zombie is a process that has exited but its parent has not accepted its exit status so its process ID is still allocated. Choose 2: the parent exits, the parent executes wait(), or the parent handles the SIGCHLD signal (such as signal(SIGCHLD, SIG_IGN)). 4. Write a C or C++ statement that will suspend process 1234. (5 pts) ANSWER: kill(1234, SIGSTOP); or kill(1234, SIGSTP); 5. Consider the following server code from chef.c while (1) { clientFd = accept(serverFd, clientSockAddrPtr, &clientLen); if (fork() == 0) { writeRecipe(clientFd); close(clientFd); exit(0); } else close(clientFd); } a. When does the server stop running? (5 pts) ANSWER: it runs forever (or until killed or the computer is turned off). b. Which process calls writeRecipe(), the parent or the child? (5 pts) ANSWER: the child. c. Rewrite the code without fork() so that everything is done by a single process and the client (cook.c) sees the same behavior. (10 pts) // ANSWER while (1) { clientFd = accept(serverFd, clientSockAddrPtr, &clientLen); writeRecipe(clientFd); close(clientFd); // Do NOT exit } d. What is the disadvantage of this method? (5 pts) ANSWER: The server can process only one client at a time. 6. Write a C or C++ function runpipe() that takes two commands as arrays of strings (like argv), executes them both in parallel with the output of the first piped to the input of the second, waits until both commands have finished, and returns the exit status of the second command, e.g. (50 pts) char* cmd1[] = {"ls", "-las", "-R", NULL}; char* cmd2[] = {"sort", "-r", NULL}; int status = runpipe(cmd1, cmd2); // equivalent to: ls -las -R | sort -r printf("done, cmd2 returns status %d\n", status); // ANSWER. This solution creates 2 children, one for each command, // then waits for both. Since they can exit in either order, it // identifies the second command by its process ID. int runpipe(char**arg1, char**arg2) { int fd[2]; int pid1, pid2, pid; int status1, status2; pipe(fd); // Pipe output of cmd1 in a child process if ((pid1=fork())==0){ close(fd[0]); dup2(fd[1], 1); close(fd[1]); execvp(arg1[0], arg1); perror(arg1[0]); } // Pipe input of cmd2 in another child process else if ((pid2=fork())==0) { close(fd[1]); dup2(fd[0], 0); close(fd[0]); execvp(arg2[0], arg2); perror(arg2[0]); } // Wait for both children in the parent else { close(fd[0]); close(fd[1]); wait(&status1); pid=wait(&status2); if (pid==pid2) return status2>>8; // cmd2 finished last else return status1>>8; // cmd2 finished first } } // A simpler approach that doesn't require checking the pid is to // fork a child for cmd2 and a grandchild for cmd1.