Pencil-and-Paper Assignment – Processes and fork() [50 pts]


You are expected to do your own work on all homework assignments. (See the statement of Academic Dishonesty on the Syllabus.)

Check the Syllabus for the late assignment policy for this course.

How to turn in?

Assignments need to be turned in via Laulima. Check the Syllabus for the late assignment policy for the course.

What to turn in?

You should turn in single plain text file named README.txt with your answers to the assignment’s questions. Your file must be readable “as is” and points will be removed if the report is not readable.


Exercise #1 [14 pts]

You just got hired by a development team that’s writing tons of C/C++ code, and your product uses fork-exec extensively to execute simple scripts and shell commands asynchronously (i.e., you want the main process to do other things while its children processes are running independently). Having taken ICS332, you write code like this:

if (!fork()) {
  char* const arguments[] = {"cp", "./img.jpg", "/tmp/", NULL};
  execv("/bin/cp", arguments);
}

and you’ve also added a handler for the SIGCHILD signal, in which you call wait() to avoid Zombies. With trepidations you do a pull request on the development branch of your software project, but it’s rejected by the abrasive main developer who just writes: “Don’t use signals (we have threads, you n00b!), just call fork() twice”. Luckily, the following code-fragment is included:

if (!fork()) {
   if (!fork()) {
     char* const arguments[] = {"cp", "./img.jpg", "/tmp/", NULL};
     execv("/bin/cp", arguments);
   }
   exit(0);
} else {
   wait(NULL);
}

Hint: Think about what happens to the child and to the grandchild.


Exercise #2 [36 pts]

Consider the following C program (assuming that necessary header files are included and that there are no compilation or execution errors)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
int main(int argc, char **argv)
{
        // Main process's PID=42

        pid_t pid = fork(); // creates process with PID=11
        if (pid > 0) {
                pid_t pid2 = fork(); // creates process with PID=25
                if (pid2 > 0) {
                        sleep(20); // sleep for 20 seconds
                        exit(0);
                }
                exit(0);
        } else {
                pid_t pid3 = fork(); // creates process with PID=89
                if (pid3 == 0) {
                        sleep(40); // sleep for 40 seconds
                        printf("** ONE **\n");
                        exit(0);
                }
                pid_t pid4 = fork(); // creates process with PID=123
                if (pid4 == 0) {
                        sleep(30); // sleep for 30 seconds
                        exit(0);
                }
                waitpid(pid4, NULL, 0);
        }

        sleep(20); // sleep for 20 seconds
        printf("** TWO **\n");      
        exit(0);
}

Assume that the PID of the main process is 42. Each call to fork() in the code is commented to show the PID of the newly created process (The PIDS are thus 42, 11, 25, 89, and 123).

In this exercise we assume that all operations take zero time but for sleep() (which sleeps a prescribed number of seconds) and waitpid(), which obviously might block for a while. We also assume that the execution starts at time zero. Therefore, in all the questions below, whenever time is mentioned/needed, it’s always a perfect multiple of 10 (since all calls to sleep in the above program are for numbers of seconds that are multiples of 10).

Answer the following questions: