Project 4: Inter-Process Communication and Process Management


Overview

In this project, you will do the following:

  1. Implement a spawn system call
  2. Implement inter-process communication using message boxes
  3. Implement a handler for the keyboard interrupt
  4. Implement a kill system call
  5. Implement a wait system call
We recommend that you tackle these problems in the given order.

WARNING: Do not view the starter code for this project before completing the previous one. Doing so is a violation of the honor code.

The starter code is available at /u/318/code/project4 on courselab.

Spawning Processes

The spawn() system call should create a new running process.

First, it must look up a process by name. Since we have not yet implemented file systems, you are provided a dummy filesystem defined in ramdisk.h. The test cases each define their own files.

You may assume a finite number of running processes (NUM_PCBS).

Return the pid on success, -1 if unable to find the process, -2 if there are too many processes.


Inter-Process Communication

Processes will be able to communicate via first-in, first-out message box queues. These queues should be an efficient implementation of the bounded-buffer problem.

Message boxes support four operations, each with a corresponding system call:

NOTE: Neither do_mbox_send() nor do_mbox_recv() should call enter_critical() or leave_critical() directly.


Handling the Keyboard

You will write a handler for irq1. This handler will receive bytes from the keyboard, and buffer them using a message box. If the keyboard buffer is full, the handler must instead discard the character.

You must also implement the get_char() system call. This system call will try to read a character from the keyboard buffer, or block until one is available.

To aid in your debugging, the initial code distribution contains a dummy implementation of get_char(). This implementation repeatedly types out the strings:

These strings are commands for the shell in the test_given test case.


Killing Processes

The kill() system call should change the state of a process such that it will die (soon). Special care must be taken in certain circumstances; for instance, there may be difficulties if this process is not in the ready queue. Think about this problem, and discuss your solution at design review.

When a process is killed, no effort should be made to release any resources that it holds (such as locks).

The kill system call should immediately kill a process, even if it is sleeping or blocked (even on a wait() call). If a process is killed while sleeping, other sleeping processes should still wake on schedule. If a process is killed while blocked on a lock, semaphore, condition variable or barrier, the other processes which interact with that synchronization primitive should be unaffected. If a process is killed while it is in the ready queue, lottery scheduling should still give proportional scheduling to the surviving processes.

If a process has opened message boxes, their usage counts should be decremented when a process is killed. This should also be the case when exiting a process.


Waiting on Processes

The wait() system call should block the caller until a given process has terminated. Your implementation must be efficient.


Test Cases

The source code is distributed with two test cases:

To select a test case, use the settest script just like in project 3. Writing your own, more specific test cases is recommended.

When you have finished the project, the test_given test should look similar to this:

Shell example picture

Hints


Design Review

Mailboxes What fields will the structs need? Which synchronization primitives will you use?

Process Management Use the
signup sheet to schedule a time to see the TAs.

Submission

Submit via Tigerfile. When you submit, you should submit a README. Do not submit a modified Makefile.


Extra Credit