# Project 1: User Programs
## Preliminaries
If you have any preliminary comments on your submission, notes for the TAs, please
give them here.
Please cite any offline or online sources you consulted while preparing your
submission, other than the PintOS documentation, course text, lecture notes, and
course staff.
## Argument Passing
### Argument Passing - Data Structures
- Copy here the declaration of each new or changed struct or struct member, global or
static variable, typedef, or enumeration. Identify the purpose of each in 25 words
or less.
### Argument Passing - Algorithms
- Briefly describe how you implemented argument parsing. How do you arrange for the
elements of `argv[]` to be in the right order? How do you avoid overflowing the
stack page?
### Argument Passing - Rationale
- Why does PintOS implement `strtok_r()` but not `strtok()`?
- In PintOS, the kernel separates commands into a executable name and arguments. In
Unix-like systems, the shell does this separation. Identify at least two
advantages of the Unix approach.
## System Calls
Provide the following four sections for each of the syscall tasks (process control,
file operations, and floating point operations).
### System Calls - Data Structures
- Copy here the declaration of each new or changed struct or struct member, global or
static variable, typedef, or enumeration. Identify the purpose of each in 25 words
or less.
- Describe how file descriptors are associated with open files. Are file descriptors
unique within the entire OS or just within a single process?
### System Calls - Algorithms
- Describe your code for reading and writing user data from the kernel.
- Suppose a system call causes a full page (4,096 bytes) of data to be copied from
user space into the kernel. What is the least and the greatest possible number of
inspections of the page table (e.g. calls to `pagedir_get_page()`) that might
result? What about for a system call that only copies 2 bytes of data? Is there
room for improvement in these numbers, and how much?
- Briefly describe your implementation of the "wait" system call and how it
interacts with process termination.
- Any access to user program memory at a user-specified address can fail due to a
bad pointer value. Such accesses must cause the process to be terminated. System
calls are fraught with such accesses, e.g. a `write` system call requires reading
the system call number from the user stack, then each of the call's three
arguments, then an arbitrary amount of user memory, and any of these can fail at
any point.
This poses a design and error-handling problem: how do you best avoid obscuring the
primary function of code in a morass of error-handling? Furthermore, when an error
is detected, how do you ensure that all temporarily allocated resources (locks,
buffers, etc.) are freed? In a few paragraphs, describe the strategy or strategies
you adopted for managing these issues. Give an example.
### System Calls - Synchronization
- Study the interface of the semaphore functions and describe the sequence of calls
required for a thread to be able to wait for an event that happens in another
thread.
- The `exec` system call returns `-1` if loading the new executable fails, so it
cannot return before the new executable has completed loading. How does your code
ensure this? How is the load success/failure status passed back to the thread that
calls "exec"?
- Consider parent process P with child process C. How do you ensure proper
synchronization and avoid race conditions when P calls `wait(C)` before `C` exits?
After `C` exits? How do you ensure that all resources are freed in each case? How
about when `P` terminates without waiting, before `C` exits? After `C` exits? Are
there any special cases?
### System Calls - Rationale
- Why did you choose to implement access to user memory from the kernel in the way
that you did?
- What advantages or disadvantages can you see to your design for file descriptors?
- The default `tid_t` to `pid_t` mapping is the identity mapping. If you changed it,
what advantages are there to your approach?
## Changes
Discuss any changes you made since your initial design document. Explain why you
made those changes. Feel free to reiterate what you discussed with your TA during
the design review if necessary.
## Reflection
Discuss the contribution of each member. Make sure to be specific about the parts of
each task each member worked on. Reflect on the overall working environment and
discuss what went well and areas of improvement.
## Testing
For each of the 2 test cases you write, provide
- Description of the feature your test case is supposed to test.
- Overview of how the mechanics of your test case work, as well as a qualitative
description of the expected output.
- Output and results of your own PintOS kernel when you run the test case. These
files will have the extensions .output and .result.
- Two non-trivial potential kernel bugs and how they would have affected the output
of this test case. Express these in the form "If my kernel did X instead of Y,
then the test case would output Z instead". You should identify two different bugs
per test case, but you can use the same bug for both of your two test cases. These
bugs should be related to your test case (e.g. syntax errors don't)
In addition, tell us about your experience writing tests for PintOS. What can be
improved about the PintOS testing system? What did you learn from writing test cases?