Os161 Assignment 2 Bmis

1. Due Dates and Mark Distribution

Due Date: 8am, Fri May 5th

Marks: Worth 30 marks (of the 100 available for the class mark component of the course)

The 10% bonus for one week early is available for the basic assignment.

The advanced assignment is assessable for COMP3891/COMP9283 students. It is worth 5 marks of the 100 class marks available.

COMP3231/COMP9201 students can do the advanced part with the permission of the lecturer, and only if basic assignment is completed a week prior to the deadline. Marks obtained are added to any shortfall in the class mark component up to a maximum of 10 bonus marks overall for all assignments.

A small number of additional bonus marks are available as described in the advanced section.

The familiarisation questions contained herein are the subject of your week 8 tutorial. Please answer the questions and bring them to your tutorial.


2. Introduction

In this assignment you will be implementing a software bridge between a set of file-related system calls inside the OS/161 kernel and their implementation within the VFS (obviously also inside the kernel). Upon completion, your operating system will be able to run a single application at user-level and perform some basic file I/O.

A substantial part of this assignment is understanding how OS/161 works and determining what code is required to implement the required functionality. Expect to spend at least as long browsing and digesting OS/161 code as actually writing and debugging your own code.

If you attempt the advanced part, you will add process related system calls and the ability to run multiple applications.

Your current OS/161 system has minimal support for running executables, nothing that could be considered a true process. Assignment 2 starts the transformation of OS/161 into something closer to a true operating system. After this assignment, OS/161 will be capable of running a process from actual compiled programs stored in your account. The program will be loaded into OS/161 and executed in user mode by System/161; this will occur under the control of your kernel. First, however, you must implement part of the interface between user-mode programs ("userland") and the kernel. As usual, we provide part of the code you will need. Your job is to design and build the missing pieces.

Our code can run one user-level C program at a time as long as it doesn't want to do anything but shut the system down. We have provided sample user programs that do this (reboot, halt, poweroff), as well as others that make use of features you might be adding in this and future assignments. So far, all the code you have written for OS/161 has only been run within, and only been used by, the operating system kernel itself. In a real operating system, the kernel's main function is to provide support for user-level programs. Most such support is accessed via "system calls." We give you two system calls: in and in . In GDB, if you put a breakpoint on and run the "reboot" program, you can use "backtrace" to see how it got there.

User-level programs

Our System/161 simulator can run normal C programs if they are compiled with a cross-compiler, os161-gcc. This runs on a host (e.g., a Linux x86 machine) and produces MIPS executables; it is the same compiler used to compile the OS/161 kernel. Various user-level programs already exist in , , and . Note: that only a small subset these programs will execute successfully due to OS/161 only support a small subset of system calls.

To create new user programs (for testing purposes), you need to edit the Makefile in bin, sbin, or testbin (depending on where you put your programs) and then create a directory similar to those that already exist. Use an existing program and its as a template.

Design

In the beginning, you should tackle this assignment by producing a DESIGN DOCUMENT. The design document should clearly reflect the development of your solution. They should not merely explain what you programmed. If you try to code first and design later, or even if you design hastily and rush into coding, you will most certainly end up in a software "tar pit". Don't do it! Plan everything you will do. Don't even think about coding until you can precisely explain to your partner what problems you need to solve and how the pieces relate to each other. Note that it can often be hard to write (or talk) about new software design, you are facing problems that you have not seen before, and therefore even finding terminology to describe your ideas can be difficult. There is no magic solution to this problem; but it gets easier with practice. The important thing is to go ahead and try. Always try to describe your ideas and designs to someone else. In order to reach an understanding, you may have to invent terminology and notation, this is fine. If you do this, by the time you have completed your design, you will find that you have the ability to efficiently discuss problems that you have never seen before. Why do you think that CS is filled with so much jargon? To help you get started, we have provided the following questions as a guide for reading through the code. We recommend that you answer questions for the different modules and be prepared to discuss them in your Week 8 tutorial. Once you have prepared the answers, you should be ready to develop a strategy for designing your code for this assignment.


3. Code walk-through

Bring your answers to the code walk-through questions to your week 8 tutorial.


3.1 General system calls

: traps and syscalls

Exceptions are the key to operating systems; they are the mechanism that enables the OS to regain control of execution and therefore do its job. You can think of exceptions as the interface between the processor and the operating system. When the OS boots, it installs an "exception handler" (carefully crafted assembly code) at a specific address in memory. When the processor raises an exception, it invokes this, which sets up a "trap frame" and calls into the operating system. Since "exception" is such an overloaded term in computer science, operating system lingo for an exception is a "trap", when the OS traps execution. Interrupts are exceptions, and more significantly for this assignment, so are system calls. Specifically, syscall.c handles traps that happen to be syscalls. Understanding at least the C code in this directory is key to being a real operating systems junkie, so we highly recommend reading through it carefully. The code is also covered in the system calls lecture.

is the key function for returning control to the operating system. This is the C function that gets called by the assembly exception handler. is the function for handling broken user programs; when the processor is in usermode and hits something it can't handle (say, a bad instruction), it raises an exception. There's no way to recover from this, so the OS needs to kill off the process. The bonus part of this assignment will include writing a useful version of this function.

is the function that delegates the actual work of a system call off to the kernel function that implements it. Notice that reboot and time are the only cases currently handled.

Questions

  1. What is the numerical value of the exception code for a MIPS system call (Hint: )?
  2. How many bytes is an instruction in MIPS? (Answer this by reading carefully, not by looking somewhere else.)
  3. What is the contents of the ? Where is the that is passed into stored?
  4. What would be required to implement a system call that took more than 4 arguments?
  5. What is the purpose of ?

3.2 Moving data between kernel and userland.

 

This file contains functions for moving data between kernel and user space. Knowing when and how to cross this boundary is critical to properly implementing userlevel programs, so this is a good file to read very carefully. The framework provided is needed to safely implement application buffer handling in the and system calls. You should also examine the code in .

Questions

  1. What is the difference between and ? When should one use instead?
  2. Why can the that is used to read in an ELF segment be allocated on the stack in (i.e., where is the destination memory for the read)?
  3. In what file are and defined? ? Why can't and be implemented as simply as ?

3.3 The VFS interface.

The files and in this directory contain function declarations and comments that are directly relevant to this assignment.

Questions

  1. How are , used? What other calls are relevant?
  2. What are VOP_READ, VOP_WRITE? How are they used?
  3. What does VOP_ISSEEKABLE do?
  4. Where is the defined? What does this structure contain?
  5. Where is the struct proc defined? What does this structure contain?

3.4 Loading and running programs.

These questions mostly relate to the advanced assignment, but are worth exploring to understand how a program starts running.

 

This directory contains some syscall implementations, and the files that are responsible for the loading and running of userlevel programs. Currently, the only files in the directory are , , and , although you may want to add more of your own during this assignment. Understanding these files is the key to getting started with the assignment, especially the advanced part, the implementation of multiprogramming. Note that to answer some of the questions, you will have to look in files outside this directory.

This file contains the functions responsible for loading an ELF executable from the filesystem and into virtual memory space. Of course, at this point this virtual memory space does not provide what is normally meant by virtual memory, although there is translation between the addresses that executables "believe" they are using and physical addresses, there is no mechanism for providing more memory than exists physically.

This file contains only one function, , which is the function that is responsible for running a program from the kernel menu. Once you have designed your file system calls, a program started by should have the standard file descriptors (stdout, stderr) available while it's running.

In the advanced assignment, is a good base for writing the system call, but only a base. When writing your design doc, you should determine what more is required for that does not need to worry about. Once you have design your process framework, should be altered to start processes properly within this framework.

Questions

  1. What are the ELF magic numbers?
  2. In , why is it important to call before going to usermode?
  3. What function forces the processor to switch into usermode? Is this function machine dependent?

Answer these questions by reading the man page and the sections dealing with in the textbook.

Questions

  1. What is the purpose of the system call?
  2. What process state is shared between the parent and child?
  3. What process state is copied between the parent and child?

3.5 The userland side of system calls.

This section is mostly related to the advanced version, but is still generally insightful to understand how system calls transition into the kernel. This was covered in some detail in the system call lecture in week 2.

The userland C startup code. There's only one file in here, , which contains the MIPS assembly code that receives control first when a user-level program is started. It calls . This is the code that your implementation will be interfacing to, so be sure to check what values it expects to appear in what registers and so forth.

:

There's obviously a lot of code in the OS/161 C library (and a lot more yet in a real system's C library...) We don't expect you to read it all, although it may be instructive in the long run to do so. Job interviewers have an uncanny habit of asking people to implement simple standard C functions on the whiteboard. For present purposes you need only look at the code that implements the user-level side of system calls.

This is where the global variable errno is defined.

This file contains the machine-dependent code necessary for implementing the userlevel side of MIPS system calls. is created from this file at compile time and is the actual file assembled to put into the C library. The actual names of the system calls are placed in this file using a script called that reads them from the kernel's header files. This avoids having to make a second list of the system calls. In a real system, typically each system call stub is placed in its own source file, to allow selectively linking them in. OS/161 puts them all together to simplify the makefiles.

Questions

  1. What is the purpose of the SYSCALL macro?
  2. What is the MIPS instruction that actually triggers a system call? (Answer this by reading the source in this directory, not looking somewhere else.)


4. Basic Assignment

Setup

Remember to use a subshell (or continue using your modified PATH) for this assignment, as outlined in ASST0. Also double-check you have retained your from ASST1.

SVN setup

Only one of you needs to do the following. In this section, you will be setting up the svn repository that will contain your code. We suggest your partner sit in on this part of the assignment.

Import the OS/161 sources into your repository as follows:

% cd /home/cs3231/assigns % svn import asst2/src file:///home/osprjXXX/repo/asst2/trunk -m "Initial import"

Make an immediate branch of this import for easy reference when you generate your diff:

% svn copy -m "Tag initial import" file:///home/osprjXXX/repo/asst2/trunk file:///home/osprjXXX/repo/asst2/initial

Checkout

The following instructions are now for both partners. You have now completed setting up a shared repository for both partners. We'll assume your directory is intact from the previous assignment. Change to your directory:

% cd ~/cs3231

Now checkout a copy of the os161 sources to work on from your shared repository:

% svn checkout file:///home/osprjXXX/repo/asst2/trunk asst2-src You should now have a directory to work on.

Building and Testing Your Assignment

Configure OS/161 for Assignment 2

Before proceeding further, configure your new sources.

% cd ~/cs3231/asst2-src % ./configure

Unlike previous the previous assignment, you will need to build and install the user-level programs that will be run by your kernel in this assignment.

% cd ~/cs3231/asst2-src % bmake % bmake install

For your kernel development, again we have provided you with a framework for you to run your solutions for ASST2.

You have to reconfigure your kernel before you can use this framework. The procedure for configuring a kernel is the same as in ASST0 and ASST1, except you will use the ASST2 configuration file:

% cd ~/cs3231/asst2-src/kern/conf % ./config ASST2 You should now see an ASST2 directory in the compile directory.

Building for ASST2

When you built OS/161 for ASST1, you ran make from compile/ASST1 . In ASST2, you run make from (you guessed it) compile/ASST2. % cd ../compile/ASST2 % bmake depend % bmake % bmake install

If you are told that the directory does not exist, make sure you ran config for ASST2.

Command Line Arguments to OS/161

Your solutions to ASST2 will be tested by running OS/161 with command line arguments that correspond to the menu options in the OS/161 boot menu.

IMPORTANT: Please DO NOT change these menu option strings!

Running "asst2"

For this assignment, we have supplied a user-level OS/161 program that you can use for testing. It is called , and its sources live in .

You can test your assignment by typing at the OS/161 menu prompt. As a short cut, you can also specify menu arguments on the command line, example: .
Note: If you don't have a file, you can use this one.

Running the program produces output similar to the following prior to starting the assignment.

Unknown syscall 55 Unknown syscall 55 Unknown syscall 55 Unknown syscall 55 : : Unknown syscall 55 Unknown syscall 55 Unknown syscall 3
Fatal user mode trap 4 sig 10 (Address error on load, epc 0x400814, vaddr 0xeeeee00f) produces the following output on a (maybe partially) working assignment. OS/161 kernel [? for menu]: p /testbin/asst2 Operation took 0.000212160 seconds OS/161 kernel [? for menu]: ********** * File Tester ********** * write() works for stdout ********** * write() works for stderr ********** * opening new file "test.file" * open() got fd 3 * writing test string * wrote 45 bytes * writing test string again * wrote 45 bytes * closing file ********** * opening old file "test.file" * open() got fd 3 * reading entire file into buffer * attemping read of 500 bytes * read 90 bytes * attemping read of 410 bytes * read 0 bytes * reading complete * file content okay ********** * testing lseek * reading 10 bytes of file into buffer * attemping read of 10 bytes * read 10 bytes * reading complete * file lseek okay * closing file Unknown syscall 3 Fatal user mode trap 4 sig 10 (Address error on load, epc 0x400814, vaddr 0xeeeee00f)

Note that the final fatal error is expected, and is due to exit() (system call 3) not being implemented by OS/161. If exit()returns to userland (which would not happen in a complete OS implementation), the userland exit library code simply accesses an illegal memory address in order to cause a fault, which subsequently causes the program (and system) to stop. You can distinguish this expected fault from other faults by the address accessed: 0xeeeee00f.

The Assignment Task: File System Calls

Of the full range of system calls that is listed in , your task is to implement the following file-based system calls: , , , , , . Note: You are writing the kernel code that implements part of the system call functionality within the kernel. The C stubs that user-level applications call to invoke the system calls are already automatically generated when you build OS/161.

Note that the basic assignment does not involve implementing (that's part of the advanced assignment). However, the design and implementation of your system calls should not assume a single process.

It's crucial that your syscalls handle all error conditions gracefully (i.e., without crashing OS/161.) You should consult the OS/161 man pages (also included in the distribution) and understand fully the system calls that you must implement. Your system calls must return the correct value (in case of success) or error code (in case of failure) as specified in the man pages. Some of the auto-marking scripts rely on the return of error codes, however, we are lenient as to which specific code in the case of potential ambiguity as to the most appropriate error code.

The file contains the user-level interface definition of the system calls that you will be writing for OS/161 (including ones you will implement in later assignments). This interface is different from that of the kernel functions that you will define to implement these calls. You need to design this interface and put it in . As you discovered (ideally) in Assignment 0, the integer codes for the calls are defined in . You need to think about a variety of issues associated with implementing system calls. Perhaps, the most obvious one is: can two different user-level processes (or user-level threads, if you choose to implement them) find themselves running a system call at the same time?

Notes on , , , , , and

For any given process, the first file descriptors (0, 1, and 2) are considered to be standard input (stdin), standard output (stdout), and standard error (stderr) respectively. For this basic assignment, the file descriptors 1 (stdout) and 2 (stderr) must start out attached to the console device ("con:"), 0 (stdin) can be left unattached. You will probably modify to achieve this. Your implementation must allow programs to use to change stdin, stdout, stderr to point elsewhere.

Although these system calls may seem to be tied to the filesystem, in fact, these system calls are really about manipulation of file descriptors, or process-specific filesystem state. A large part of this assignment is designing and implementing a system to track this state. Some of this information (such as the cwd) is specific only to the process, but others (such as offset) is specific to the process and file descriptor. Don't rush this design. Think carefully about the state you need to maintain, how to organise it, and when and how it has to change.

While this assignment requires you to implement file-system-related system calls, you actually have to write virtually no low-level file system code in this assignment. You will use the existing VFS layer to do most of the work. Your job is to construct the subsystem that implements the interface expected by userland programs by invoking the appropriate VFS and vnode operations.

While you are not restricted to only modifying these files, please place most of your implementation in the following files: function prototypes and data types for your file subsystem in , and the function implementations and variable instantiations in .

A note on errors and error handling of system calls

The man pages in the OS/161 distribution contain a description of the error return values that you must return. If there are conditions that can happen that are not listed in the man page, return the most appropriate error code from . If none seem particularly appropriate, consider adding a new one. If you're adding an error code for a condition for which UNIX has a standard error code symbol, use the same symbol if possible. If not, feel free to make up your own, but note that error codes should always begin with E, should not be EOF, etc. Consult UNIX man pages to learn about error codes. Note that if you add an error code to you need to add a corresponding error message to the file .

Design Questions

Here are some additional questions and issues to aid you in developing your design. They are by no means comprehensive, but they are a reasonable place to start developing your solution.

What primitive operations exist to support the transfer of data to and from kernel space? Do you want to implement more on top of these?

You will need to "bullet-proof" the OS/161 kernel from user program errors. There should be nothing a user program can do to crash the operating system when invoking the file system calls. It is okay in the basic assignment for the kernel to perform a controlled panic for an unimplemented system call (e.g. ), or a user-level program error. It is not okay for the kernel to crash due to user-program behaviour.

Decide which functions you need to change and which structures you may need to create to implement the system calls.

How you will keep track of open files? For which system calls is this useful?

For additional background, consult one or more of the following texts for details how similar existing operating systems structure their file system management:

Documenting your solution

This is a compulsory component of this assignment. You must submit a small design document identifying the basic issues in this assignment, and then describe your solution to the problems you have identified. The design document you developed in the planning phase (outlined above) would be an ideal start. The document must be plain ASCII text. We expect such a document to be roughly 500—1000 words, i.e. clear and to the point.

The document will be used to guide our markers in their evaluation of your solution to the assignment. In the case of a poor results in the functional testing combined with a poor design document, we will base our assessment on these components alone. If you can't describe your own solution clearly, you can't expect us to reverse engineer the code to a poor and complex solution to the assignment.

Place your design document in (which we have created for you) at the top of the source tree to OS/161 (i.e. in ).

When you later commit your changes into your repository, your design doc will be included in the commit, and later in your submission.

Also, please word wrap you design doc if your have not already done so. You can use the unix command to achieve this if your editor cannot.


5. Basic Assignment Submission

As with the previous assignments, you again will be submitting a diff of your changes to the original tree.

You should first commit your changes back to the repository using the following command. Note: You will have to supply a comment on your changes. You also need to coordinate with your partner that the changes you have (or potentially both have) made are committed consistently by you and your partner, such that the repository contains the work you want from both partners.

% cd ~/cs3231/asst2-src % svn commit

If the above fails, you may need to run to bring your source tree up to date with commits made by your partner. If you do this, you should double check and test your assignment prior to submission.

Beware! If you have created new files for this assignment, they will not be included in your submission unless you add them, using :

% svn add filename.c If you add files after running , you will need to run again.

Now generate a file containing the diff.

% cd ~ % svn diff file:///home/osprjXXX/repo/asst2/initial file:///home/osprjXXX/repo/asst2/trunk >~/asst2.diff

Testing Your Submission

Look here for information on testing and resubmitting your assignment.

Submitting Your Assignment

Now submit the diff as your assignment. % cd ~ % give cs3231 asst2 asst2.diff You're now done.

Even though the generated diff output should represent all the changes you have made to the supplied code, occasionally students do something "ingenious" and generate non representative diff output.

We strongly suggest keeping your svn repository intact to allow for recovery of your work if need be.


6. Advanced Assignment

The advanced assignment is assessable for COMP3891/COMP9283 students. It is worth 5 marks of the 100 class marks available. Marks are awarded as follows
  • fork(), getpid()5 marks.
  • waitpid(), _exit(), kill_curthread() 2 bonus marks.
  • exec() optional for 1 bonus mark.

The advanced assignment is to complete the basic assignment, plus the additional task below. 

Given you're doing the advanced version of the assignment, I'm assuming you're competent with managing your SVN repository and don't need simple directions. You basically need to generate a diff between your final version and the base. There are two ways you can do this: the simpler (but messier) option is to continue developing along your mainline branch and generate the diff in the same way as for the basic assignment. A neater approach is to create a new branch in SVN to work on your advanced solution. Whichever approach you take, make sure you test your diff before you submit it!

User-level Process Management System Calls

Implement the system call. Your implementation of fork should eventually be the same as that described in the man page, however for testing initially, you might consider always returning 1 for the child process id (pid) instead of implementing pid management.

The amount of code to implement fork is quite small; the main challenge is to understand what needs to be done. We strongly encourage you to implement the file-related system calls first, with fork in mind.

Some hints:

  • Read the comments above in
  • Read the comments in , particularly .
  • You will need to copy the trapframe from the parent to the child. You should be careful how you do this, as there is a possible race condition (where?/why?).
  • You may wish to base your implementation on the function in .

A pid, or process ID, is a unique number that identifies a process. The implementation of is not terribly challenging, but pid allocation and reclamation are the important concepts that you must implement. It is not OK for your system to crash because over the lifetime of its execution you've used up all the pids. Design your pid system; implement all the tasks associated with pid maintenance, and only then implement . When your pid system is working correctly, change your implementation to return the child's pid to the parent, rather than 1.

, ,

These system calls are probably the most difficult part of the whole assignment, but also the most rewarding. They enable multiprogramming and make OS/161 a much more useful entity. is your mechanism for creating new processes. It should make a copy of the invoking process and make sure that the parent and child processes each observe the correct return value (that is, 0 for the child and the newly created pid for the parent). You will want to think carefully through the design of fork and consider it together with execv to make sure that each system call is performing the correct functionality. , although "only" a system call, is really the heart of this assignment. It is responsible for taking newly created processes and make them execute something useful (i.e., something different than what the parent is executing). Essentially, it must replace the existing address space with a brand new one for the new executable (created by calling in the current dumbvm system) and then run it. While this is similar to starting a process straight out of the kernel (as does), it's not quite that simple. Remember that this call is coming out of userspace, into the kernel, and then returning back to userspace. You must manage the memory that travels across these boundaries very carefully. (Also, notice that doesn't take an argument vector, but these must of course be handled correctly in ).

Although it may seem simple at first, requires a fair bit of design. Read the specification carefully to understand the semantics, and consider these semantics from the ground up in your design. You may also wish to consult the UNIX man page, though keep in mind that you are not required to implement all the things UNIX supports, nor is the UNIX parent/child model of waiting the only valid or viable possibility. The implementation of is intimately connected to the implementation of . They are essentially two halves of the same mechanism. Most of the time, the code for will be simple and the code for relatively complicated, but it's perfectly viable to design it the other way around as well. If you find both are becoming extremely complicated, it may be a sign that you should rethink your design.

Feel free to write in as simple a manner as possible. Just keep in mind that essentially nothing about the current thread's userspace state can be trusted if it has suffered a fatal exception: it must be taken off the processor in as judicious a manner as possible, but without returning execution to the user level.

Design Questions

Here are some additional questions and thoughts to aid in writing your design document. They are not, by any means, meant to be a comprehensive list of all the issues you will want to consider. Your system must allow user programs to receive arguments from the command line. By the end of Assignment 2, you should be capable of executing lines (in user programs) such as: char *filename = "/bin/cp"; char *args[4]; pid_t pid; args[0] = "cp"; args[1] = "file1"; args[2] = "file2"; args[3] = NULL; pid = fork(); if (pid == 0) execv(filename, argv); which will load the executable file , install it as a new process, and execute it. The new process will then find on the disk and copy it to .

You can test your implementation using OS/161's shell, .

Some questions to think about:

  • Passing arguments from one user program, through the kernel, into another user program, is a bit of a chore. What form does this take in C? This is rather tricky, and there are many ways to be led astray. You will probably find that very detailed pictures and several walk-throughs will be most helpful.
  • How will you determine: (a) the stack pointer initial value; (b) the initial register contents; (c) the return value; (d) whether you can exec the program at all?
  • What new data structures will you need to manage multiple processes?
  • What relationships do these new structures have with the rest of the system?
  • How will you manage file accesses? When invoke the command, and it starts to read , what will happen if the shell also tries to read ? What would you like to happen?
  • How you will keep track of running processes. For which system calls is this useful?
  • How you will implement the execv system call. How is the argument passing in this function different from that of other system calls?

Advanced Assignment Submission

Submission for the advanced assignment is similar to the basic assignment, except the advance component is given to a distinguished assignment name: Again, you need to generate a diff based on the original source tree.

% cd ~/cs3231/asst2-src % svn commit

Now generate a file containing the diff. (NOTE: How this works depends on how you have set up branches in svn.)

% cd ~ % svn diff file:///home/osprjXXX/repo/asst2/initial file:///home/osprjXXX/repo/asst2/adv >~/asst2_adv.diff Submit your solution % cd ~ % give cs3231 asst2_adv asst2_adv.diff

FAQ and Gotchas

See https://wiki.cse.unsw.edu.au/cs3231cgi/2017s1/Asst2 for an up to date list of potential issues you might encounter.


Page last modified: 8:19pm on Wednesday, 5th of April, 2017

Print Version

CRICOS Provider Number: 00098G

CS 161: Operating Systems

Tuesday/Thursday 1:00-2:30

Pierce 301



CS161 Assignment 2

In-Class Design Review: Tuesday, February 7
Design Due: Friday, February 10 at 5:00PM
Assignment Due: Friday, February 24 at 5:00PM
  • Be able to write code that meets a specified interface definition.
  • Understand how to represent processes in an operating system.
  • Design and implement data structures to manage processes and scheduling in an operating system.
  • Understand how to implement system calls.
  • Understand the theory and practice of process scheduling.

This is the first assignment that requires you to work in teams of two. This may be difficult if you are accustomed to working alone, but it is essential for the completion of the remaining assignments and is a worthwhile skill to develop in any case. These assignments are too complex to be done single-handedly, and you will gain valuable real-world experience from learning to work in a team effectively.

To begin working together, you and your partner need to pick a team name, decide on a code base, and then need to set up a shared Git repository; all three steps are described in more detail below. Choose your code base with care! The assignments are cumulative, and you will have to live with the consequences of this decision for the remainder of the semester. We suggest that you and your partner resolve conflicts about things like programming style and naming conventions now in order to avoid confusion later. Working together on a program can be much more demanding and frustrating than doing lab work together. (Imagine writing a coherent term paper with someone else!)

The code base you select should be a working OS/161 system with clean, well-commented, bullet-proof synchronization primitives. You and your partner should share your solutions to the previous assignments (it's good practice to learn to read and understand someone else's code) and decide what your code base will be. You are free to choose either partner's code, to merge your solutions, or to use the solution set.

Once you have selected a code base, refer to the section below for directions on setting up a shared Git repository.

For over 20 years, the teams in CS 161 have been named after animals. You and your partner should select the animal that most accurately represents your excellence. The animal can be real or mythical, but choose wisely! Good things rarely happen to Team Unambitious Sloth.

There are a number of issues that you and your partner should work out now, when things are calm, so you needn't figure them out at 2:00 AM in the heat of the moment.

Naming Conventions

It's a good idea to select some rudimentary protocol for naming global variables and variables passed as arguments to functions. This way, you can just ask your partner to write some function and, while s/he's doing it, you can make calls to that function in your own code, confident that you have a common naming convention from which to work. Be consistent in the way you write the names of functions: given a function called "my function", one might write its name as my_function, myFunction, MyFunction, mYfUnCtIoN, ymayUnctionFay, etc. Pick one model and stick to it (although we discourage the last two examples).

Git Use

Since you and your partner will be using Git to manage your work, you will need to decide when and how often to commit and push changes. (Advice: early and often.) Additionally, you should agree upon how much detail to log when committing files. Perhaps more importantly, you also need to think about how to maintain the integrity of the system- what procedures to follow to make sure you can always pull a working version of some sort from Git, whether or not it's the latest version, what tests to run on a new version to make sure you haven't inadvertently broken something, etc.

Clear, explicit Git logs are essential. If you are incommunicado for some reason, it is vital for your partner to be able to reconstruct your design, implementation and debugging process from your Git logs. In general, leaving something uncommitted and/or unpushed for a long period of time is dangerous: it means that you are undertaking too large a piece of work and have not broken it down effectively. Once some new code compiles and doesn't break the world, push it. When you've got a small part working, push it. When you've designed something and written a lot of comments, push it. Committing, pushing, and pulling is free. Hours spent hand-merging hundreds of lines of code wastes time you'll never get back. The combination of frequent pushes and good, detailed comments will facilitate more efficient program development.

Use the features of Git to help you. For example, you may want to use tags to identify when major features are added and when they're stable. The brave of heart might want to investigate Git branches, which provide completely separate threads of development (one significant caveat—although branches make life much easier while you're developing within a branch, merging branches together later can be a major headache).

Communication

Nothing replaces good, open communication between partners. The more you can direct that communication to issues of content ("How shall we design ?") instead of procedural details ("What do you mean, you never pushed your version of ?"), the more productive your group will be.

In your design documents for each assignment, you must identify, at least in general terms, who is responsible for the various parts of your solutions.

If at any time during the course of the semester, you and your partner realize that you are having difficulty working together, please come speak with Professor Mickens or one of the teaching fellows. We will work with you to help your partnership work more effectively, or in extreme circumstances, we will help you find new partners. Do not suffer in silence; please come talk with us. Addressing issues early is practically always better than suffering in silence.

Setting up Your Git Repositories

Before working on this assignment, you and your partner must set up a Git repository that will serve as the master repository for both of you for the rest of the semester. In the instructions below, we assume that your names are ALICE and BOB, and that you've chosen to use ALICE's code. [You are also allowed to use the Assignment 1 solution set instead of your or your partner's code. Please contact the course staff if you're interested in this option, but we very much recommend that you use either your or your partner's code.]

  • ALICE should click on the Github Classroom link for creating the group Github account that she and her partner will use for Assignments 2, 3, and 4.
  • That link will allow ALICE to create a new team whose name is the spirit animal for ALICE and BOB. A new team repository will be created; this repository will initially be empty.
  • ALICE should follow the directions provided by Github Classroom to "push an existing repository from the command line;" that existing repository should be her Assignment 1 repository.
  • At this point, the team repository has now been initialized.
  • BOB should now click on the Github Classroom link for joining a team repository. BOB should join the team created by ALICE.
Now, both ALICE and BOB have access to the team repository.

BOB should now do the following:

$ cd ~/cs161$ mv os161 oldos161 # This will move Bob's existing code out of the way (feel free to back it up to # some other location if you like) $ git clone git@github.com:CS161/a2-4-your-spirit-animal.git os161 # Replace "your-spirit-animal" with the name of your team # Now you need to set up the handout remote again $ cd os161$ git remote add handout git@github.com:CS161/CS161-handout.git

Now one of you should tag the repository:

$ cd ~/cs161/os161$ git tag asst2-start$ git push --tags Total 0 (delta 0), reused 0 (delta 0) To git@github.com:CS161/a2-4-your-spirit-animal.git * [new tag] asst2-start -> asst2-start

The other partner should and ensure that the asst2-start tag got pulled successfully.

Don't forget to configure and build the new tree you're working in (especially BOB, since this is an entirely new repository for him).

There are three videos that we consider supplemental to this assignment. Both you and your partner should check them out and make sure you know the material covered in them.

Your current OS/161 system has minimal support for running executables -- nothing that could be considered a true process. Assignment 2 starts the transformation of OS/161 into a true multi-tasking operating system. After the next assignment, it will be capable of running multiple processes at once from actual compiled programs stored in your account. These programs will be loaded into OS/161 and executed in user mode by System/161; this will occur under the control of your kernel and the command shell in .

First, however, you must implement the interface between user-mode programs ("userland") and the kernel. As usual, we provide part of the code you will need. Your job is to design and build the missing pieces.

You will also be implementing the subsystem that keeps track of the multiple tasks you will have in the future. You must decide what data structures you will need to hold the data pertinent to a "process" (hint: look at kernel include files of your favorite operating system for suggestions, specifically the structure.)

The first step is to read and understand the parts of the system that we have written for you. Our code can run one user-level C program at a time as long as it doesn't want to do anything but shut the system down. We have provided sample user programs that do this (, , ), as well as others that make use of features you will be adding in this and future assignments.

So far, all the code you have written for OS/161 has only been run within, and only been used by, the operating system kernel. In a real operating system, the kernel's main function is to provide support for user-level programs. Most such support is accessed via "system calls." We give you one system call, , which is implemented in the function in main.c. In GDB, if you put a breakpoint on and run the "reboot" program, you can use "backtrace" to see how it got there.

User level programs

Our System/161 simulator can run normal programs compiled from C. The programs are compiled with a cross-compiler, . This compiler runs on the host machine and produces MIPS executables; it is the same compiler used to compile the OS/161 kernel. To create new user programs, you will need to edit the Makefile in , , or (depending on where you put your programs) and then create a directory similar to those that already exist. Use an existing program and its Makefile as a template.

Design

Beginning with this assignment, please note that your design documents become an important part of the work you submit. The design documents should clearly reflect the development of your solution. They should not merely explain what you programmed. If you try to code first and design later, or even if you design hastily and rush into coding, you will most certainly end up in a software "tar pit". Don't do it! Work with your partner to plan everything you will do. Don't even think about coding until you can precisely explain to each other what problems you need to solve and how the pieces relate to each other.

Note that it can often be hard to write (or talk) about new software design -- you are facing problems that you have not seen before, and therefore even finding terminology to describe your ideas can be difficult. There is no magic solution to this problem; but it gets easier with practice. The important thing is to go ahead and try. Always try to describe your ideas and designs to someone else (we suggest your partner; roommates seem to have a low tolerance for this sort of thing). In order to reach an understanding, you may have to invent terminology and notation - this is fine (just be sure to explain it to your TF in your design document). If you do this, by the time you have completed your design, you will find that you have the ability to efficiently discuss problems that you have never seen before. Why do you think that CS is filled with so much jargon?

To help you get started, we have provided the following questions as a guide for reading through the code. We recommend that you divide up the code and have each partner answer questions for different modules. After reading the code and answering questions, get together and exchange summations of the code you each reviewed. Once you have done this, you should be ready to discuss strategy for designing your code for this assignment.

Code walk-through (10 points)

Please write up and hand in answers to the questions found below. Put them in a text file , which you should put in a new directory called "asst2" in the subdirectory of your OS/161 repository, i.e. .

The key files that are responsible for the loading and running of user-level programs are , , and , although you may want to add more of your own during this assignment. Understanding these files is the key to getting started with the implementation of multiprogramming. Note that to answer some of the questions, you will have to look in other files.

: This file contains the functions responsible for loading an ELF executable from the filesystem and into virtual memory space. (ELF is the name of the executable format produced by .) Of course, at this point this virtual memory space does not provide what is normally meant by virtual memory -- although there is translation between the addresses that executables "believe" they are using and physical addresses, there is no mechanism for providing more memory than exists physically. We recommend not stressing about this until Assignment 3.

: This file contains only one function, , which is responsible for running a program from the kernel menu. It is a good base for writing the system call, but only a base -- when writing your design doc, you should determine what more is required for that does not concern itself with. Additionally, once you have designed your process system, should be altered to start processes properly within this framework; for example, a program started by should have the standard file descriptors available while it's running.

: This file contains functions for moving data between kernel and user space. Knowing when and how to cross this boundary is critical to properly implementing userlevel programs, so this is a good file to read very carefully. You should also examine the code in .

Questions

  1. What are the ELF magic numbers?
  2. What is the difference between and ? When should one use instead?
  3. Why can the that is used to read in a segment be allocated on the stack in (i.e., where does the memory read actually go)?
  4. In , why is it important to call before going to usermode?
  5. What function forces the processor to switch into usermode? Is this function machine dependent?
  6. In what file are and defined? ? Why can't and be implemented as simply as ?
  7. What (briefly) is the purpose of ?

kern/arch/mips: traps and syscalls

Exceptions are the key to operating systems; they are the mechanism that enables the OS to regain control of execution and therefore do its job. You can think of exceptions as the interface between the processor and the operating system. When the OS boots, it installs an "exception handler" (carefully crafted assembly code) at a specific address in memory. When the processor raises an exception, it invokes this exception handler, which sets up a "trap frame" and calls into the operating system. Since "exception" is such an overloaded term in computer science, operating system lingo for an exception is a "trap". Interrupts are exceptions, and more significantly for this assignment, so are system calls. Specifically, handles traps that happen to be syscalls. Understanding at least the C code in this directory is key to being a real operating systems junkie, so we highly recommend reading through it carefully.

: is the key function for returning control to the operating system. This is the C function that gets called by the assembly exception handler. is the key function for returning control to user programs. is the function for handling broken user programs; when the processor is in usermode and hits something it can't handle (say, a bad instruction), it raises an exception. There's no way to recover from this, so the OS needs to kill off the process. Part of this assignment will be to write a useful version of this function.

: is the function that delegates the actual work of a system call to the kernel function that implements it. Notice that is the only case currently handled. You will also find a function, , which is a stub where you will place your code to implement the system call. It should get called from .

Questions

  1. What is the numerical value of the exception code for a MIPS system call?
  2. How many bytes is an instruction in MIPS? (Answer this by reading carefully, not by looking somewhere else.)
  3. Why do you "probably want to change" the implementation of ?
  4. What would be required to implement a system call that took more than 4 arguments?

: This is the user program startup code. There's only one file in here, , which contains the MIPS assembly code that receives control first when a user-level program is started. It calls the user program's . This is the code that your implementation will be interfacing to, so be sure to check what values it expects to appear in what registers and so forth.

: This is the user-level C library. There's obviously a lot of code here. We don't expect you to read it all, although it may be instructive in the long run to do so. Job interviewers have an uncanny habit of asking people to implement standard C library functions on the whiteboard. For present purposes you need only look at the code that implements the user-level side of system calls, which we detail below.

: This is where the global variable errno is defined.

: This file contains the machine-dependent code necessary for implementing the user-level side of MIPS system calls.

: This file is created from syscalls-mips.S at compile time and is the actual file assembled into the C library. The actual names of the system calls are placed in this file using a script called that reads them from the kernel's header files. This avoids having to make a second list of the system calls. In a real system, typically each system call stub is placed in its own source file, to allow selectively linking them in. OS/161 puts them all together to simplify the makefiles.

Questions

  1. What is the purpose of the macro?
  2. What is the MIPS instruction that actually triggers a system call? (Answer this by reading the source in this directory, not looking somewhere else.)
  3. After reading syscalls-mips.S and syscall.c, you should be prepared to answer the following question: OS/161 supports 64-bit values; takes and returns a 64-bit offset value. Thus, lseek() takes a 32-bit file handle (arg0), a 64-bit offset (arg1), a 32-bit whence (arg3), and needs to return a 64-bit offset value. In where will you find each of the three arguments (in which registers) and how will you return the 64-bit offset?
Design and Implementation
(90 points total; 30 points design, 30 points for functionality, 30 points for clarity and attention to detail)

As directed above, before you begin this assignment, tag your repository as .

System calls and exceptions

Implement system calls and exception handling. The full range of system calls that we think you might want over the course of the semester is listed in . For this assignment you should implement:

  • open, read, write, lseek, close, dup2, chdir, getcwd
  • getpid
  • fork, execv, waitpid, _exit

It's crucial that your syscalls handle all error conditions gracefully (i.e., without crashing OS/161.) You should consult the OS/161 man pages included in the distribution and understand fully the system calls that you must implement. You must return the error codes as decribed in the man pages.

Additionally, your syscalls must return the correct value (in case of success) or error code (in case of failure) as specified in the man pages. Some of the grading scripts rely on the return of appropriate error codes; adherence to the guidelines is as important as the correctness of the implementation.

The file contains the user-level interface definition of the system calls that you will be writing for OS/161 (including ones you will implement in later assignments). This interface is different from that of the kernel functions that you will define to implement these calls. You need to design this interface and put it in . As you discovered (ideally) in Assignment 0, the integer codes for the calls are defined in .

You need to think about a variety of issues associated with implementing system calls. Perhaps the most obvious one is: can two different user-level processes find themselves running a system call at the same time? Be sure to argue for or against this, and explain your final decision in the design document.

open(), read(), write(), lseek(), close(), dup2(), chdir(), and __getcwd()

For any given process, the first file descriptors (0, 1, and 2) are considered to be standard input (), standard output (), and standard error (). These file descriptors should start out attached to the console device (""), but your implementation must allow programs to use to change them to point elsewhere.

Although these system calls may seem to be tied to the filesystem, in fact, these system calls are really about manipulation of file descriptors, or process-specific filesystem state. A large part of this assignment is designing and implementing a system to track this state. Some of this information (such as the current working directory) is specific only to the process, but others (such as file offset) is specific to the process and file descriptor. Don't rush this design. Think carefully about the state you need to maintain, how to organize it, and when and how it has to change.

Note that there is a system call and then a library routine . Once you've written the system call, the library routine should function correctly.

getpid()

A pid, or process ID, is a unique number that identifies a process. The implementation of is not terribly challenging, but pid allocation and reclamation are the important concepts that you must implement. It is not OK for your system to crash because over the lifetime of its execution you've used up all the pids. Design your pid system; implement all the tasks associated with pid maintenance, and only then implement .

fork(), execv(), waitpid(), _exit()

These system calls are probably the most difficult part of the assignment, but also the most rewarding. They enable multiprogramming and make OS/161 a much more useful entity.

is the mechanism for creating new processes. It should make a copy of the invoking process and make sure that the parent and child processes each observe the correct return value (that is, 0 for the child and the newly created pid for the parent). You will want to think carefully through the design of and consider it together with to make sure that each system call is performing the correct functionality.

, although "only" a system call, is really the heart of this assignment. It is responsible for taking newly created processes and make them execute something useful (i.e., something different than what the parent is executing). Essentially, it must replace the existing address space with a brand new one for the new executable (created by calling in the current system) and then run it. While this is similar to starting a process straight out of the kernel (as does), it's not quite that simple. Remember that this call is coming out of userspace, into the kernel, and then returning back to userspace. You must manage the memory that travels across these boundaries very carefully. (Also, notice that doesn't take an argument vector -- but this must of course be handled correctly in ).

Although it may seem simple at first, requires a fair bit of design. Read the specification carefully to understand the semantics, and consider these semantics from the ground up in your design. You may also wish to consult the UNIX man page, though keep in mind that you are not required to implement all the things UNIX supports -- nor is the UNIX parent/child model of waiting the only valid or viable possibility.

The implementation of is intimately connected to the implementation of waitpid(). They are essentially two halves of the same mechanism. Most of the time, the code for will be simple and the code for relatively complicated -- but it's perfectly viable to design it the other way around as well. If you find both are becoming extremely complicated, it may be a sign that you should rethink your design.

A note on errors and error handling of system calls:

The man pages in the OS/161 distribution contain a description of the error return values that you must return. If there are conditions that can happen that are not listed in the man page, return the most appropriate error code from . If none seem particularly appropriate, consider adding a new one. If you're adding an error code for a condition for which Unix has a standard error code symbol, use the same symbol if possible. If not, feel free to make up your own, but note that error codes should always begin with , should not be , etc. Consult Unix man pages to learn about Unix error codes; on Linux systems will do the trick.

Note that if you add an error code to , you need to add a corresponding error message to the file .

kill_curthread()

Feel free to write in as simple a manner as possible. Just keep in mind that essentially nothing about the current thread's userspace state can be trusted if it has suffered a fatal exception -- it must be taken off the processor in as judicious a manner as possible, but without returning execution to the user level.

Testing using the shell

In you will find a simple shell that will allow you to test your new system call interfaces. When executed, the shell prints a prompt, and allows you to type simple commands to run other programs. Each command and its argument list (an array of character pointers) is passed to the system call, after calling to get a new thread for its execution. The shell also allows you to run a job in the background using . You can exit the shell by typing "exit".

Under OS/161, once you have the system calls for this assignment, you should be able to use the shell to execute the following user programs from the bin directory: cat, cp, false, pwd, and true. You will also find several of the programs in the testbin directory helpful.

Scheduling

Note that you do not need to include discussion of the scheduler in your initial design document submission, though if you do we're happy to talk about it with you. It is, however, expected in your final design document submission.

Right now, the OS/161 scheduler implements a simple round-robin queue. You will see in thread.c that the schedule() function is actually blank. The round-robin scheduling comes into effect when hardclock() calls thread_yield() and a subsequent call to thread_switch() pops the current thread on the cpu's run-queue and takes the next thread off the current cpu's run-queue (FIFO order). As we learned in class, this is probably not the best method for achieving optimal processor throughput. For this assignment, you should implement a more interesting scheduling algorithm.

You should select a better scheduling algorithm to implement and in your design document, explain why you selected it over other schedulers and under what conditions you would expect it to perform better or worse than the other scheduling algorithms. Think carefully about what information you will need to maintain in order to implement your scheduler. Provide an analysis of how you would conduct a fair and extensive analysis of your scheduling algorithm. Which workloads would you run to find and demonstrate the benefits and compromises of your scheduler? What parameters are tuneable? Consult some of the test programs in (e.g., add.c, hog.c, farm.c, sink.c, kitchen.c, ps.c) and consider how you would devise your own benchmark if tasked to do so. After you finish coding your scheduler implementation, update your design document with any new insights on the performance capabilities and pitfalls inherent in your implementation and where there is room for improvement.

For this portion of the assignment it is OK to ignore the multi-core nature of OS/161. Your scheduler can operate on the current cpu's run-queue (e.g., reshuffle the threads on the current cpu's run-queue based on some priority metric). The threads on the other core will be reshuffled when your scheduler runs on the other core.

You may want your scheduler to be configurable. For example, for a round robin scheduler, it should be possible to specify the time slice. For a multi-level feedback queuing system, you might want to specify the number of queues and/or the time slice for the highest priority queue.

It is OK to have to recompile to change these settings, as with the HZ parameter of the default scheduler. And it is OK to require a recompile to switch schedulers. But it shouldn't require editing more than a couple or the kernel config file to make these changes.

In any event, OS/161 should display at bootup which scheduler is in use.

Here are some additional questions and thoughts to aid in writing your design document. They are not, by any means, meant to be a comprehensive list of all the issues you will want to consider. You do not need to explicitly answer or discuss these questions in your design document, but you should at least think about them.

Your system must allow user programs to receive arguments from the command line. For example, you should be able to run the following program:

char *filename = "/bin/cp"; char *args[4]; pid_t pid; args[0] = "cp"; args[1] = "file1"; args[2] = "file2"; args[3] = NULL; pid = fork(); if (pid == 0) execv(filename, argv); which will load the executable file , install it as a new process, and execute it. The new process will then find on the disk and copy it to .

Some questions to think about:

Passing arguments from one user program, through the kernel, into another user program, is a bit of a chore. What form does this take in C? This is rather tricky, and there are many ways to be led astray. You will probably find that very detailed pictures and several walk-throughs will be most helpful.

What primitive operations exist to support the transfer of data to and from kernel space? Do you want to implement more on top of these?

How will you determine: (a) the stack pointer initial value; (b) the initial register contents; (c) the return value; (d) whether you can exec the program at all?

You will need to "bullet-proof" the OS/161 kernel from user program errors. There should be nothing a user program can do to crash the operating system (with the exception of explicitly asking the system to halt).

What new data structures will you need to manage multiple processes?

What relationships do these new structures have with the rest of the system?

How will you manage file accesses? When the shell invokes the command, and the command starts to read , what will happen if another program also tries to read ? What would you like to happen?

In class on Tuesday, February 7, we will conduct peer design reviews. You should have a complete first revision of your design complete by then. Bring two hard copies of that design to class and commit that design to your team repository (in the directory ).

During the design review, you will complete a review for another team and they will complete a review for you. You will then undoubtedly want to update your design. Please do so. Document who your review partners were and include a list of the things you changed in response to your design review. Commit this updated design to your team repository.

Finally, turn in your design document by putting it in the subdirectory of your OS/161 repository as, e.g., (the extension can change based on your file type). Your should also be included in the submission. Please commit and push to Github Classroom with a message like "ASST2: Design Doc Submission" by 5:00pm on Friday, February 10. Your group will be assigned to a TF who will contact you to set up a meeting to discuss your design. It is important that both partners attend this meeting and that it's clear that both partners understand all the pieces of the assignment.

Note: Your design document and the code_reading questions are worth 30% of the grade for this assignment. The design document should contain:

  • A high level description of how you are approaching the problem.
  • A detailed description of the implementation (e.g., new structures, why they were created, what they are encapsulating, what problems they solve).
  • A discussion of the pros and cons of your approach.
  • Alternatives you considered and why you discarded them.

Your submission will need to include a number of scripts that demonstrate your working solution. For each script requested,

  1. Begin recording each script into your directory: $ script ~/cs161/os161/submit/asst2/scriptname.script
  2. Change into your root directory. $ cd ~/cs161/root and boot into your kernel $ sys161 kernel
  3. At the prompt, run the requested tests or programs for your current script. When finished, type to shut down.
  4. End your script session by typing or by pressing .

Your final submission should include the following things:

  • Your design document, named . The design document should be updated to reflect the final design of your assignment. Remember that this includes discussion of your scheduler, which was not required for the initial design doc submission.
  • A script of OS/161 running the various tests successfully. Name each script (e.g., )
  • A script of the OS/161 shell running various basic commands (, , ) under OS/161. Name each script .
  • Your file.

Your submission folder should look something like the following:

$ cd ~/cs161/os161/submit/asst2$ ls cat.script design_document.pdf tt1.script code_reading.txt pwd.script tt2.script cp.script sys161.conf tt3.script

Once you have added and committed all of your changes, including your submit directory, please tag and push your changes to Github Classroom:

$ git status # On branch master nothing to commit $ git tag asst2-submit$ git diff asst2-start asst2-submit # This will list all of your asst2 changes. Please review it to make sure # everything is there! $ git diff --stat asst2-start asst2-submit # This will list all the files you've modified, along with a rough indication of # how much work has been done on each file. Make sure this looks right too! $ git push --tags Total 0 (delta 0), reused 0 (delta 0) To git@github.com:CS161/a2-4-your-spirit-animal.git * [new tag] asst2-submit -> asst2-submit If you ever need to update your submission tag, you might get the warning "fatal: tag 'asst2-submit' already exists". If this happens, just run $ git tag -f asst2-submit Updated tag 'foo' (was d6a0fb9) $ git push --tags -f Total 0 (delta 0), reused 0 (delta 0) To git@github.com:CS161/a2-4-your-spirit-animal.git + d6a0fb9...21c346a asst2-submit -> asst2-submit (forced update)

Finally, you must verify your intended submission is displayed on the grading server; we will not accept submissions not visible on the grading server.

Congrats! You're done!

Before the design doc is due:

  1. Meet with your partner. Review the files described above. Separately answer the questions provided. Compare your solutions.
  2. Discuss high level implementations of your solutions. Do detailed design in parallel with your partner.
  3. Decide which functions you need to change and which structures you may need to create to implement the system calls. Discuss how you will pass arguments from user space to kernel space (and vice versa). Discuss how you will keep track of open files. For which system call is this useful? Discuss how you will keep track of running processes. For which system call is this useful?
  4. Discuss how you will implement the system call. How is the argument passing in this function different from that of other system calls?

Before the assignment is due:

  1. Carefully divide up the work. might be the single most demanding part of the assignment, but is non-trivial as well. Perhaps one of you will implement the basic system calls and the other will focus on process support.
  2. For the parts you're assigned, verify that the collaborated design will really work. If something needs to be redesigned, do it now, and run it by your partner.
  3. Implement.
  4. Test, test, test. Test your partner's code especially.
  5. Fix. The wise kernel hacker always schedules copious time for debugging.

On the assignment due date:

  1. Push all your final changes to your master repository. Make sure your partner has committed and pushed everything as well, and that there are no merge conflicts. Make sure you have the most up-to-date version of everything. Re-run make on both the kernel and userland to make sure all the last-minute changes get incorporated.
  2. Run the tests and generate scripts. If anything breaks, curse (politely) and repeat step 1.
  3. Tag and push your Git repository
Categories: 1

0 Replies to “Os161 Assignment 2 Bmis”

Leave a comment

L'indirizzo email non verrà pubblicato. I campi obbligatori sono contrassegnati *