You are expected to understand this. CS 111 Operating Systems Principles, Spring 2005

Midterm Sample Questions

Tom Thumb found the Lab 1 "shell" project just too hard, so he decided to write a "mini-shell" instead. His mini-shell can only run one sub-program, with mandatory input redirection. For example, the command "minish wc -l foo.txt" should run the command "wc -l < foo.txt". When the sub-command exits, the mini-shell will print out "Done!". Here's his code:

int
main(int argc, char **argv)
{
    int infd;
    pid_t p;

    // Open the last argv[] argument for redirection
    infd = open(argv[argc - 1], O_RDONLY);
    dup2(infd, 0);
    
    if ((p = fork()) == 0) {
        argv[argc - 1] = NULL;      // clear out redirection
        execvp(argv[1], &argv[2]);  // run subcommand!
    }

    printf("Done!\n");
}

Needless to say, Tom Thumb isn't a very good programmer! Help the poor fellow out.

Question. List at least 3 error conditions that Tom has forgotten to check for.

Chastened, Tom returns to the drawing board. Here's his second try.

void
sigchld_handler(int signal_value)
{
    int status;
    (void) wait(&status);
    printf("Done!\n");
    exit(0);
}

int
main(int argc, char **argv)
{
    int infd;
    pid_t p;

    // Open the last argv[] argument for redirection
    infd = open(argv[argc - 1], O_RDONLY);
    dup2(infd, 0);
    
    if ((p = fork()) == 0) {
        argv[argc - 1] = NULL;      // clear out redirection
        execvp(argv[1], &argv[2]);  // run subcommand!
    }

    signal(SIGCHLD, &sigchld_handler);
    while (1)
        /* Do nothing */;
}

This is better, but not much.

Question. Does Tom's code contain any race conditions, or "Heisenbugs"? If yes, describe a sequence of events that will trigger a race condition. If no, explain why not.

Question. Describe the performance consequences of Tom's waiting strategy (the while loop in main). Could Tom do better? Why and how? Refer to specific operating system structures discussed in class.

Question. Describe at least two fundamentally different circumstances where Tom's minishell will never return.


All your CS 111 TAs love mutexes. In fact, they love mutexes to an insane degree. Last weekend on a late-night skim-milk bender, they wrote three programs that attempt to synchronize on three different mutexes. Here they are:

mutex_t l1, l2, l3;

process_1() {
    acquire(l3);
    acquire(l1);
    release(l1);
    release(l3);
}

process_2() {
    acquire(l2);
    acquire(l3);
    acquire(l2);
    release(l2);
    release(l2);
    release(l3);
}

process_3() {
    acquire(l3);
    acquire(l1);
    acquire(l2);
    release(l1);
    release(l3);
    release(l2);
}

The TAs were supposed to figure out whether these processes contained a deadlock, but cleverly, they've decided to pass off this work to you.

Question. Describe sequences of operations that will lead to deadlock, or argue why no such sequences exist, in the cases when:
  1. mutex_t is a simple mutual-exclusion lock.
  2. mutex_t is a recursive mutual-exclusion lock.
  3. mutex_t is a semaphore allowing at most two processes to hold the lock at a time.

Question. Define a lock ordering for the mutexes, and change one or more of the processes to follow that lock ordering, so that no deadlock is possible with recursive mutexes.


Question. Circle one of the following goals that was a motivation behind the Flash server's AMPED design. Justify your choice briefly, referring to specific features of the SPED design from which AMPED was derived.
  1. Performance
  2. Isolation
  3. Portability
  4. Moral virtue
  5. Ease of programming
  6. Small code size

Extra Credit. Put a box around the lame joke in the preceding question.