project4.zip

project4/.DS_Store

__MACOSX/project4/._.DS_Store

project4/nachos.tar

nachos/c++example/c++.ps

nachos/c++example/copyright.h

#ifndef COPYRIGHT_H #define COPYRIGHT_H /* Copyright (c) 1992,1993,1995 The Regents of the University of California. All rights reserved. Permission to use, copy, modify, and distribute this software and its documentation for any purpose, without fee, and without written agreement is hereby granted, provided that the above copyright notice and the following two paragraphs appear in all copies of this software. IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */ static char *copyright = "Copyright (c) 1992,1993,1995 The Regents of the University of California. All rights reserved."; #endif /* COPYRIGHT_H */

nachos/c++example/inheritstack.cc

nachos/c++example/inheritstack.cc

// inheritstack.cc
//  Routines for two implementions of a LIFO stack of integers, 
//  one as an array, the other as a list.
//  
// Copyright (c) 1992,1993,1995 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.


extern   "C"   {
#include   < assert . h >

#define  ASSERT ( expression )   assert ( expression )
}

const   bool  FALSE  =   false ;
const   bool  TRUE  =   true ;

#include   < iostream . h >
#include   "copyright.h"
#include   "list.h"
#include   "inheritstack.h"

//----------------------------------------------------------------------
// Stack::Stack, Stack::~Stack
//  constructor and destructor for the Stack class; no data
//  to initialize!
//----------------------------------------------------------------------

Stack :: Stack ()   {}
Stack ::~ Stack ()   {}


// IMPLEMENTATION #1: AS AN ARRAY

//----------------------------------------------------------------------
// ArrayStack::ArrayStack
//  The constructor for the ArrayStack class.
//
//  "sz" -- maximum number of elements on the ArrayStack at any time
//----------------------------------------------------------------------

ArrayStack :: ArrayStack ( int  sz )   :   Stack ()   {

    ASSERT ( sz  >=   1 );

     // Initialize the data members of the stack object.
    size  =  sz ;
    top  =   0 ;
    stack  =   new   int [ size ];     // allocate an array of integers.
}

//----------------------------------------------------------------------
// ArrayStack::~ArrayStack
//  The destructor for the ArrayStack class.  Just get rid of the array we
//  allocated in the constructor.
//----------------------------------------------------------------------

ArrayStack ::~ ArrayStack ()   {

     delete   []  stack ;
}

//----------------------------------------------------------------------
// ArrayStack::Push
//  Put an integer on the top of the stack; error on overflow.
//
//  "value" -- the value to put on the stack
//----------------------------------------------------------------------

void
ArrayStack :: Push ( int   value )   {
    ASSERT ( ! Full ());
    
    stack [ top ++ ]   =   value ;
}

//----------------------------------------------------------------------
// ArrayStack::Pop
//  Remove an integer from the top of the stack, returning its value.
//  Error if the stack is empty.
//----------------------------------------------------------------------

int
ArrayStack :: Pop ()   {

    ASSERT ( ! Empty ());
    
     return   ( stack [ -- top ]);
}

//----------------------------------------------------------------------
// ArrayStack::Full
//  Return TRUE if the stack has no more room.
//----------------------------------------------------------------------

bool
ArrayStack :: Full ()   {
     return   ( top  ==  size );
}

//----------------------------------------------------------------------
// ArrayStack::Empty
//  Return TRUE if the stack has nothing on it.
//----------------------------------------------------------------------

bool
ArrayStack :: Empty ()   {
     return   ( top  ==   0 );
}


// IMPLEMENTATION #2: AS A LIST

//----------------------------------------------------------------------
// ListStack::ListStack
//  The constructor for the ListStack class.
//----------------------------------------------------------------------

ListStack :: ListStack ()   :   Stack ()   {

    stack  =   new   List ;      // allocate an empty list of integers.
}

//----------------------------------------------------------------------
// ListStack::~ListStack
//  The destructor for the ListStack class.  Just get rid of the list we
//  allocated in the constructor.
//----------------------------------------------------------------------

ListStack ::~ ListStack ()   {

     delete  stack ;
}

//----------------------------------------------------------------------
// ListStack::Push
//  Put an integer on the top of the stack.
//
//  "value" -- the value to put on the stack
//----------------------------------------------------------------------

void
ListStack :: Push ( int   value )   {
    stack -> Prepend ( value );
}

//----------------------------------------------------------------------
// ListStack::Pop
//  Remove an integer from the top of the stack, returning its value.
//  Error if the stack is empty.
//----------------------------------------------------------------------

int
ListStack :: Pop ()   {

    ASSERT ( ! Empty ());
    
     return  stack -> Remove ();
}

//----------------------------------------------------------------------
// ListStack::Full
//  Return FALSE, because a liststack can never overflow
//----------------------------------------------------------------------

bool
ListStack :: Full ()   {
     return  FALSE ;
}

//----------------------------------------------------------------------
// ListStack::Empty
//  Return TRUE if the stack has nothing on it.
//----------------------------------------------------------------------

bool
ListStack :: Empty ()   {
     return  stack -> Empty ();
}

//----------------------------------------------------------------------
// Stack::SelfTest
//  Test our stack implementation by pushing 10 numbers onto the 
//  stack, and then print them as it pops them off.
//
//  Note this code is generic between the two versions --
//  it doesn't matter whether this is an ArrayStack or a ListStack!
//
//  "numToPush" is the number of items to put on the stack in the 
//  selftest.
//----------------------------------------------------------------------

void
Stack :: SelfTest ( int  numToPush )   {
     int  count  =   17 ;
    
     // Put a bunch of stuff in the stack...
     for   ( int  i  =   0 ;  i  <  numToPush ;  i ++ )   {
    ASSERT ( ! Full ());
    cout  <<   "pushing "   <<  count  <<   "\n" ;
     Push ( count ++ );
     }
    
     // ... and take it out again.
     while   ( ! Empty ())   {
    cout  <<   "popping "   <<   Pop ()   <<   "\n" ;
     }
}

//----------------------------------------------------------------------
// main
//  Run the test code for the stack implementation.
//----------------------------------------------------------------------

int
main ()   {
     Stack   * s1  =   new   ArrayStack ( 10 );     // Constructor with an argument.
     Stack   * s2  =   new   ListStack ();  

    cout  <<   "Testing ArrayStack\n" ;
    s1 -> SelfTest ( 10 );

    cout  <<   "Testing ListStack\n" ;
    s2 -> SelfTest ( 10 );

     delete  s1 ;           // always delete what you allocate
     delete  s2 ;           // always delete what you allocate
     return   0 ;
}

nachos/c++example/list.cc

nachos/c++example/list.cc

// list.cc 
//      Routines to manage a singly-linked list of integers. 
//
//  A "ListElement" is allocated for each item to be put on the
//  list; it is de-allocated when the item is removed. This means
//      we don't need to keep a "next" pointer in every object we
//      want to put on a list.
// 
// Copyright (c) 1992,1993,1995 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.


extern   "C"   {
#include   < assert . h >

#define  ASSERT ( expression )   assert ( expression )
}

#include   "copyright.h"
#include   "list.h"

const   int  NULL  =   0 ;


// The following class defines a "list element" -- which is
// used to keep track of one item on a list.  It is equivalent to a
// LISP cell, with a "car" ("next") pointing to the next element on the list,
// and a "cdr" ("item") containing the item on the list.
//
// Class defined in list.cc, because only the List class can be allocating
// and accessing ListElements.

class   ListElement   {
    public :
      ListElement ( int   value )   {  item  =   value ;  next  =  NULL ;};
                         // constructor for list element

      ListElement   * next ;       // next element on list, 
                 // NULL if this is the last
      int  item ;                    // value of this element
};



//----------------------------------------------------------------------
// List::List
//  Initialize a list, empty to start with.
//  Elements can now be added to the list.
//----------------------------------------------------------------------

List :: List ()   {  

    first  =  last  =  NULL ;  
}


//----------------------------------------------------------------------
// List::~List
//  Prepare a list for deallocation.  If the list still contains any 
//  ListElements, de-allocate them.
//----------------------------------------------------------------------

List ::~ List ()   {  
   
     while   ( ! Empty ())
     ( void )   Remove ();       // delete all the list elements
}


//----------------------------------------------------------------------
// List::Prepend
//      Put an integer on the front of the list.
//      
//  Allocate a ListElement to keep track of the integer.
//      If the list is empty, then this will be the only element.
//  Otherwise, put it at the beginning.
//
//  "value" is the integer to be put on the list.
//----------------------------------------------------------------------

void
List :: Prepend ( int   value )   {
     ListElement   * element  =   new   ListElement ( value );

     if   ( Empty ())   {        // list is empty
    first  =  element ;
    last  =  element ;
     }   else   {              // else put it before first
    element -> next  =  first ;
    first  =  element ;
     }
}

//----------------------------------------------------------------------
// List::Remove
//      Remove the first integer from the front of the list.
//  Error if nothing on the list.
// 
// Returns:
//  The removed integer.
//----------------------------------------------------------------------

int
List :: Remove ()   {
     ListElement   * element  =  first ;
     int   value ;

    ASSERT ( ! Empty ());

    element  =  first ;
     value   =  first -> item ;

     if   ( first  ==  last )   {      // list had one item, now has none 
        first  =  NULL ;
    last  =  NULL ;
     }   else   {
        first  =  element -> next ;
     }

     delete  element ;       // deallocate list element -- no longer needed
     return   value ;
}

//----------------------------------------------------------------------
// List::Empty
//      Returns TRUE if the list is empty (has no items).
//----------------------------------------------------------------------

bool
List :: Empty ()   {  
     return   ( first  ==  NULL );
}

nachos/c++example/templatestack.cc

nachos/c++example/templatestack.cc

// templatestack.cc
//  Routines to implement a LIFO stack of arbitrary things.
//  
//  The stack is represented as an array; we return an error
//  if the caller tries to push more things onto the stack than we have
//  room for.
//
// Copyright (c) 1992,1993,1995 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.


extern   "C"   {
#include   < assert . h >

#define  ASSERT ( expression )   assert ( expression )
}

#include   < iostream . h >
#include   "copyright.h"
#include   "templatestack.h"

//----------------------------------------------------------------------
// Stack<T>::Stack
//  The constructor for the Stack class.  Note that it doesn't have a
//  return type.
//
//  "sz" -- maximum number of elements on the Stack at any time
//----------------------------------------------------------------------

template   < class  T >
Stack < T >:: Stack ( int  sz )   {

    ASSERT ( sz  >=   1 );

     // Initialize the data members of the stack object.
    size  =  sz ;
    top  =   0 ;
    stack  =   new  T [ size ];     // allocate an array of integers.
}

//----------------------------------------------------------------------
// Stack<T>::~Stack
//  The destructor for the Stack class.  Just get rid of the array we
//  allocated in the constructor.
//----------------------------------------------------------------------

template   < class  T >
Stack < T >::~ Stack ()   {

     delete   []  stack ;
}

//----------------------------------------------------------------------
// Stack<T>::Push
//  Put a T on the top of the stack; error on overflow.
//
//  "value" -- the value to put on the stack
//----------------------------------------------------------------------


template   < class  T >
void
Stack < T >:: Push ( value )   {
    ASSERT ( ! Full ());
    
    stack [ top ++ ]   =   value ;
}

//----------------------------------------------------------------------
// Stack<T>::Pop
//  Remove a T from the top of the stack, returning its value.
//  Error if the stack is empty.
//----------------------------------------------------------------------

template   < class  T >
T
Stack < T >:: Pop ()   {

    ASSERT ( ! Empty ());
    
     return   ( stack [ -- top ]);
}

//----------------------------------------------------------------------
// Stack<T>::Full
//  Return TRUE if the stack has no more room.
//----------------------------------------------------------------------

template   < class  T >
bool
Stack < T >:: Full ()   {
     return   ( top  ==  size );
}

//----------------------------------------------------------------------
// Stack<T>::Empty
//  Return TRUE if the stack has nothing on it.
//----------------------------------------------------------------------

template   < class  T >
bool
Stack < T >:: Empty ()   {
     return   ( top  ==   0 );
}

//----------------------------------------------------------------------
// Stack<T>::SelfTest
//  Test our stack implementation by pushing 10 T's onto the 
//  stack, and then print them as it pops them off.
//----------------------------------------------------------------------

template   < class  T >
void
Stack < T >:: SelfTest ( T start )   {
    T count  =  start ;
    
     // Put a bunch of stuff in the stack...
     while   ( ! Full ())   {
    cout  <<   "pushing "   <<  count  <<   "\n" ;
     Push ( count ++ );
     }
    
     // ... and take it out again.
     while   ( ! Empty ())   {
    cout  <<   "popping "   <<   Pop ()   <<   "\n" ;
     }
}

//----------------------------------------------------------------------
// main
//  Run the test code for the stack implementation.
//----------------------------------------------------------------------

int
main ()   {
     Stack < int >   * s1  =   new   Stack < int > ( 10 );    
     Stack < char >   * s2  =   new   Stack < char > ( 10 );    

    cout  <<   "Testing Stack<int>\n" ;
    s1 -> SelfTest ( 17 );

    cout  <<   "Testing Stack<char>\n" ;
    s2 -> SelfTest ( 'a' );

     delete  s1 ;           // always delete what you allocate
     delete  s2 ;           // always delete what you allocate
     return   0 ;
}

nachos/c++example/stack.cc

nachos/c++example/stack.cc

// stack.cc
//  Routines to implement a LIFO stack of integers.
//  
//  The stack is represented as an array; we return an error
//  if the caller tries to push more things onto the stack than we have
//  room for.
//
// Copyright (c) 1992,1993,1995 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.


extern   "C"   {
#include   < assert . h >

#define  ASSERT ( expression )   assert ( expression )
}

#include   < iostream . h >
#include   "copyright.h"
#include   "stack.h"

//----------------------------------------------------------------------
// Stack::Stack
//  The constructor for the Stack class.  Note that it doesn't have a
//  return type.
//
//  "sz" -- maximum number of elements on the Stack at any time
//----------------------------------------------------------------------

Stack :: Stack ( int  sz )   {

    ASSERT ( sz  >=   1 );

     // Initialize the data members of the stack object.
    size  =  sz ;
    top  =   0 ;
    stack  =   new   int [ size ];     // allocate an array of integers.
}

//----------------------------------------------------------------------
// Stack::~Stack
//  The destructor for the Stack class.  Just get rid of the array we
//  allocated in the constructor.
//----------------------------------------------------------------------

Stack ::~ Stack ()   {

     delete   []  stack ;
}

//----------------------------------------------------------------------
// Stack::Push
//  Put an integer on the top of the stack; error on overflow.
//
//  "value" -- the value to put on the stack
//----------------------------------------------------------------------

void
Stack :: Push ( int   value )   {
    ASSERT ( ! Full ());
    
    stack [ top ++ ]   =   value ;
}

//----------------------------------------------------------------------
// Stack::Pop
//  Remove an integer from the top of the stack, returning its value.
//  Error if the stack is empty.
//----------------------------------------------------------------------

int
Stack :: Pop ()   {

    ASSERT ( ! Empty ());
    
     return   ( stack [ -- top ]);
}

//----------------------------------------------------------------------
// Stack::Full
//  Return TRUE if the stack has no more room.
//----------------------------------------------------------------------

bool
Stack :: Full ()   {
     return   ( top  ==  size );
}

//----------------------------------------------------------------------
// Stack::Empty
//  Return TRUE if the stack has nothing on it.
//----------------------------------------------------------------------

bool
Stack :: Empty ()   {
     return   ( top  ==   0 );
}

//----------------------------------------------------------------------
// Stack::SelfTest
//  Test our stack implementation by pushing 10 numbers onto the 
//  stack, and then print them as it pops them off.
//----------------------------------------------------------------------

void
Stack :: SelfTest ()   {
     int  count  =   17 ;
    
     // Put a bunch of stuff in the stack...
     while   ( ! Full ())   {
    cout  <<   "pushing "   <<  count  <<   "\n" ;
     Push ( count ++ );
     }
    
     // ... and take it out again.
     while   ( ! Empty ())   {
    cout  <<   "popping "   <<   Pop ()   <<   "\n" ;
     }
}

//----------------------------------------------------------------------
// main
//  Run the test code for the stack implementation.
//----------------------------------------------------------------------

int
main ()   {
     Stack   * stack  =   new   Stack ( 10 );     // Constructor with an argument.

    stack -> SelfTest ();

     delete  stack ;            // always delete what you allocate
     return   0 ;
}

nachos/c++example/Makefile

PREFIX=decstation-ultrix- # add crosscompiler prefix here i.e. decstation-ultrix- INCLUDEDIR= # add path to include directories for crosscompiler environment here: # don't forget the -I tag before the directory # i.e: -I/usr/lcoal/nachosxdev/include -I/usr/local/nachosxdev/include/g++-3 all: stack inheritstack templatestack stack: stack.h stack.cc $(PREFIX)g++ $(INCLUDEDIR) -o stack stack.cc inheritstack: inheritstack.h inheritstack.cc list.h list.cc $(PREFIX)g++ $(INCLUDEDIR) -o inheritstack inheritstack.cc list.cc templatestack: templatestack.h templatestack.cc $(PREFIX)g++ $(INCLUDEDIR) -o templatestack templatestack.cc

nachos/c++example/stack.h

// stack.h // Data structures for a "stack" -- a Last-In-First-Out list of integers. // // Copyright (c) 1992,1993,1995 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef STACK_H // to prevent recursive includes #define STACK_H #include "copyright.h" // The following defines the Stack class. The functions are // implemented in the file stack.cc. // // The constructor (initializer) for the Stack is passed the number // of elements (integers) in the stack. class Stack { public: Stack(int sz); // Constructor: initialize variables, allocate space. ~Stack(); // Destructor: deallocate space allocated above. void Push(int value); // Push an integer on the stack, checking for overflow int Pop(); // Pop an integer off the stack, checking for underflow. bool Full(); // Returns TRUE if the stack is full, FALSE otherwise. bool Empty(); // Returns TRUE if the stack is empty, FALSE otherwise. void SelfTest(); // Test whether the implementation works. private: int size; // The maximum capacity of the stack. int top; // Index of the next position to be used. int *stack; // A pointer to an array that holds the contents. }; #endif // STACK_H

nachos/c++example/templatestack.h

// templatestack.h // Data structures for a stack" -- a Last-In-First-Out list -- // of arbitrary things. // // Copyright (c) 1992,1993,1995 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef TEMPLATESTACK_H // to prevent recursive includes #define TEMPLATESTACK_H #include "copyright.h" // The following defines the Stack class. The functions are // implemented in the file templatestack.cc. // // T is the type of the thing we want to put on the stack. template <class T> class Stack { public: Stack(int sz); // Constructor ~Stack(); // Destructor void Push(T value); // Push a T on the stack T Pop(); // Pop a T off the stack bool Full(); // Returns TRUE if the stack is full bool Empty(); // Returns TRUE if the stack is empty void SelfTest(T start); // Test whether the implementation works. private: int size; // The maximum capacity of the stack. int top; // Index of the next position to be used. T *stack; // A pointer to an array that holds the contents. }; #endif // TEMPLATESTACK_H

nachos/c++example/list.h

// list.h // Data structures to manage LISP-like lists. // // Copyright (c) 1992,1993,1995 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef LIST_H #define LIST_H #include "copyright.h" class ListElement; // The following class defines a "list" -- a singly linked list of // list elements, each of which contains an integer. class List { public: List(); // initialize the list ~List(); // de-allocate the list void Prepend(int value); // Put item at the beginning of the list int Remove(); // Take item off the front of the list bool Empty(); // is the list empty? void SelfTest(); private: ListElement *first; // Head of the list, NULL if list is empty ListElement *last; // Last element of list }; #endif // LIST_H

nachos/c++example/c++.tex

\documentstyle[12pt,fullpage]{article} \newcommand{\putfig}[3]% {\begin{figure}% \centerline{% \psfig{figure=#1.ps,width=#3}}% \caption{#2}% \label{fig:#1}% \end{figure}} \input{psfig} \begin{document} \begin{figure*}[t] \begin{center} {\LARGE\bf A Quick Introduction to C++} \vspace{3.0ex} {\Large Tom Anderson} \end{center} \end{figure*} \renewcommand{\thefootnote}{\fnsymbol{footnote}} \footnotetext{This article is based on an earlier version written by Wayne Christopher.} \renewcommand{\thefootnote}{} \renewcommand{\thefootnote}{\arabic{footnote}} \begin{quote} ``If programming in Pascal is like being put in a straightjacket, then programming in C is like playing with knives, and programming in C++ is like juggling chainsaws.'' \\ \hbox{} \hfill Anonymous. \end{quote} \section{Introduction} This note introduces some simple C++ concepts and outlines a subset of C++ that is easier to learn and use than the full language. Although we originally wrote this note for explaining the C++ used in the Nachos project, I believe it is useful to anyone learning C++. I assume that you are already somewhat familiar with C concepts like procedures, for loops, and pointers; these are pretty easy to pick up from reading Kernighan and Ritchie's ``The C Programming Language.'' I should admit up front that I am quite opinionated about C++, if that isn't obvious already. I know several C++ purists (an oxymoron perhaps?) who violently disagree with some of the prescriptions contained here; most of the objections are of the form, ``How could you have possibly left out feature X?'' However, I've found from teaching C++ to nearly 1000 undergrads over the past several years that the subset of C++ described here is pretty easy to learn, taking only a day or so for most students to get started. The basic premise of this note is that while object-oriented programming is a useful way to simplify programs, C++ is a wildly over-complicated language, with a host of features that only very, very rarely find a legitimate use. It's not too far off the mark to say that C++ includes every programming language feature ever imagined, and more. The natural tendency when faced with a new language feature is to try to use it, but in C++ this approach leads to disaster. Thus, we need to carefully distinguish between (i) those concepts that are fundamental (e.g., classes, member functions, constructors) -- ones that everyone should know and use, (ii) those that are sometimes but rarely useful (e.g., single inheritance, templates) -- ones that beginner programmers should be able to recognize (in case they run across them) but avoid using in their own programs, at least for a while, and (iii) those that are just a bad idea and should be avoided like the plague (e.g., multiple inheritance, exceptions, overloading, references, etc). Of course, all the items in this last category have their proponents, and I will admit that, like the hated goto, it is possible to construct cases when the program would be simpler using a goto or multiple inheritance. However, it is my belief that most programmers will never encounter such cases, and even if you do, you will be much more likely to misuse the feature than properly apply it. For example, I seriously doubt an undergraduate would need any of the features listed under (iii) for any course project (at least at Berkeley this is true). And if you find yourself wanting to use a feature like multiple inheritance, then, my advice is to fully implement your program both with and without the feature, and choose whichever is simpler. Sure, this takes more effort, but pretty soon you'll know from experience when a feature is useful and when it isn't, and you'll be able to skip the dual implementation. A really good way to learn a language is to read clear programs in that language. I have tried to make the Nachos code as readable as possible; it is written in the subset of C++ described in this note. It is a good idea to look over the first assignment as you read this introduction. Of course, your TA's will answer any questions you may have. You should not need a book on C++ to do the Nachos assignments, but if you are curious, there is a large selection of C++ books at Cody's and other technical bookstores. (My wife quips that C++ was invented to make researchers at Bell Labs rich from writing ``How to Program in C++'' books.) Most new software development these days is being done in C++, so it is a pretty good bet you'll run across it in the future. I use Stroustrup's "The C++ Programming Language" as a reference manual, although other books may be more readable. I would also recommend Scott Meyer's ``Effective C++'' for people just beginning to learn the language, and Coplien's ``Advanced C++'' once you've been programming in C++ for a couple years and are familiar with the language basics. Also, C++ is continually evolving, so be careful to buy books that describe the latest version (currently 3.0, I think!). \section{C in C++} To a large extent, C++ is a superset of C, and most carefully written ANSI C will compile as C++. There are a few major caveats though: \begin{enumerate} \item All functions must be declared before they are used, rather than defaulting to type {\tt int}. \item All function declarations and definition headers must use new-style declarations, e.g., \begin{verbatim} extern int foo(int a, char* b); \end{verbatim} The form {\tt extern int foo();} means that {\tt foo} takes {\it no} arguments, rather than arguments of an unspecified type and number. In fact, some advise using a C++ compiler even on normal C code, because it will catch errors like misused functions that a normal C compiler will let slide. \item If you need to link C object files together with C++, when you declare the C functions for the C++ files, they must be done like this: \begin{verbatim} extern "C" int foo(int a, char* b); \end{verbatim} Otherwise the C++ compiler will alter the name in a strange manner. \item There are a number of new keywords, which you may not use as identifiers --- some common ones are {\tt new}, {\tt delete}, {\tt const}, and {\tt class}. \end{enumerate} \section{Basic Concepts} Before giving examples of C++ features, I will first go over some of the basic concepts of object-oriented languages. If this discussion at first seems a bit obscure, it will become clearer when we get to some examples. \begin{enumerate} \item {\bf Classes and objects}. A class is similar to a C {\em structure}, except that the definition of the data structure, {\em and} all of the functions that operate on the data structure are grouped together in one place. An {\em object} is an instance of a class (an instance of the data structure); objects share the same functions with other objects of the same class, but each object (each instance) has its own copy of the data structure. A class thus defines two aspects of the objects: the {\em data} they contain, and the {\em behavior} they have. \item {\bf Member functions}. These are functions which are considered part of the object and are declared in the class definition. They are often referred to as {\em methods} of the class. In addition to member functions, a class's behavior is also defined by: \begin{enumerate} \item What to do when you create a new object (the {\bf constructor} for that object) -- in other words, initialize the object's data. \item What to do when you delete an object (the {\bf destructor} for that object). \end{enumerate} \item {\bf Private vs. public members}. A public member of a class is one that can be read or written by anybody, in the case of a data member, or called by anybody, in the case of a member function. A private member can only be read, written, or called by a member function of that class. \end{enumerate} Classes are used for two main reasons: (1) it makes it much easier to organize your programs if you can group together data with the functions that manipulate that data, and (2) the use of private members makes it possible to do {\em information hiding}, so that you can be more confident about the way information flows in your programs. \subsection{Classes} C++ classes are similar to C structures in many ways. In fact, a C++ struct is really a class that has only public data members. In the following explanation of how classes work, we will use a stack class as an example. \begin{enumerate} \item {\bf Member functions.} Here is a (partial) example of a class with a member function and some data members: \begin{verbatim} class Stack { public: void Push(int value); // Push an integer, checking for overflow. int top; // Index of the top of the stack. int stack[10]; // The elements of the stack. }; void Stack::Push(int value) { ASSERT(top < 10); // stack should never overflow stack[top++] = value; } \end{verbatim} This class has two data members, {\tt top} and {\tt stack}, and one member function, {\tt Push}. The notation {\em class}::{\em function} denotes the {\em function} member of the class {\em class}. (In the style we use, most function names are capitalized.) The function is defined beneath it. As an aside, note that we use a call to {\tt ASSERT} to check that the stack hasn't overflowed; ASSERT drops into the debugger if the condition is false. It is an extremely good idea for you to use ASSERT statements liberally throughout your code to document assumptions made by your implementation. Better to catch errors automatically via ASSERTs than to let them go by and have your program overwrite random locations. In actual usage, the definition of {\tt class Stack} would typically go in the file {\tt stack.h} and the definitions of the member functions, like {\tt Stack::Push}, would go in the file {\tt stack.cc}. If we have a pointer to a {\tt Stack} object called {\tt s}, we can access the {\tt top} element as {\tt s->top}, just as in C. However, in C++ we can also call the member function using the following syntax: \begin{verbatim} s->Push(17); \end{verbatim} Of course, as in C, {\tt s} must point to a valid {\tt Stack} object. Inside a member function, one may refer to the members of the class by their names alone. In other words, the class definition creates a scope that includes the member (function and data) definitions. Note that if you are inside a member function, you can get a pointer to the object you were called on by using the variable {\tt this}. If you want to call another member function on the same object, you do not need to use the {\tt this} pointer, however. Let's extend the Stack example to illustrate this by adding a {\tt Full()} function. \begin{verbatim} class Stack { public: void Push(int value); // Push an integer, checking for overflow. bool Full(); // Returns TRUE if the stack is full, FALSE otherwise. int top; // Index of the lowest unused position. int stack[10]; // A pointer to an array that holds the contents. }; \end{verbatim} \newpage \begin{verbatim} bool Stack::Full() { return (top == 10); } \end{verbatim} Now we can rewrite {\tt Push} this way: \begin{verbatim} void Stack::Push(int value) { ASSERT(!Full()); stack[top++] = value; } \end{verbatim} We could have also written the ASSERT: \begin{verbatim} ASSERT(!(this->Full()); \end{verbatim} but in a member function, the \verb+this->+ is implicit. The purpose of member functions is to encapsulate the functionality of a type of object along with the data that the object contains. A member function does not take up space in an object of the class. \item {\bf Private members.} One can declare some members of a class to be {\it private}, which are hidden to all but the member functions of that class, and some to be {\it public}, which are visible and accessible to everybody. Both data and function members can be either public or private. In our stack example, note that once we have the {\tt Full()} function, we really don't need to look at the {\tt top} or {\tt stack} members outside of the class -- in fact, we'd rather that users of the Stack abstraction {\em not} know about its internal implementation, in case we change it. Thus we can rewrite the class as follows: \begin{verbatim} class Stack { public: void Push(int value); // Push an integer, checking for overflow. bool Full(); // Returns TRUE if the stack is full, FALSE otherwise. private: int top; // Index of the top of the stack. int stack[10]; // The elements of the stack. }; \end{verbatim} Before, given a pointer to a {\tt Stack} object, say {\tt s}, any part of the program could access {\tt s->top}, in potentially bad ways. Now, since the {\tt top} member is private, only a member function, such as {\tt Full()}, can access it. If any other part of the program attempts to use {\tt s->top} the compiler will report an error. You can have alternating {\tt public:} and {\tt private:} sections in a class. Before you specify either of these, class members are private, thus the above example could have been written: \begin{verbatim} class Stack { int top; // Index of the top of the stack. int stack[10]; // The elements of the stack. public: void Push(int value); // Push an integer, checking for overflow. bool Full(); // Returns TRUE if the stack is full, FALSE otherwise. }; \end{verbatim} Which form you prefer is a matter of style, but it's usually best to be explicit, so that it is obvious what is intended. In Nachos, we make everything explicit. What is not a matter of style: {\bf all data members of a class should be private.} All operations on data should be via that class' member functions. Keeping data private adds to the modularity of the system, since you can redefine how the data members are stored without changing how you access them. \item {\bf Constructors and the operator new.} In C, in order to create a new object of type {\tt Stack}, one might write: \begin{verbatim} struct Stack *s = (struct Stack *) malloc(sizeof (struct Stack)); InitStack(s, 17); \end{verbatim} The {\tt InitStack()} function might take the second argument as the size of the stack to create, and use {\tt malloc()} again to get an array of 17 integers. The way this is done in C++ is as follows: \begin{verbatim} Stack *s = new Stack(17); \end{verbatim} The {\tt new} function takes the place of {\tt malloc()}. To specify how the object should be initialized, one declares a {\it constructor} function as a member of the class, with the name of the function being the same as the class name: \begin{verbatim} class Stack { public: Stack(int sz); // Constructor: initialize variables, allocate space. void Push(int value); // Push an integer, checking for overflow. bool Full(); // Returns TRUE if the stack is full, FALSE otherwise. private: int size; // The maximum capacity of the stack. int top; // Index of the lowest unused position. int* stack; // A pointer to an array that holds the contents. }; Stack::Stack(int sz) { size = sz; top = 0; stack = new int[size]; // Let's get an array of integers. } \end{verbatim} There are a few things going on here, so we will describe them one at a time. The {\tt new} operator automatically creates (i.e. allocates) the object and then calls the constructor function for the new object. This same sequence happens even if, for instance, you declare an object as an automatic variable inside a function or block -- the compiler allocates space for the object on the stack, and calls the constructor function on it. In this example, we create two stacks of different sizes, one by declaring it as an automatic variable, and one by using {\tt new}. \begin{verbatim} void test() { Stack s1(17); Stack* s2 = new Stack(23); } \end{verbatim} Note there are two ways of providing arguments to constructors: with {\tt new}, you put the argument list after the class name, and with automatic or global variables, you put them after the variable name. It is crucial that you {\bf always} define a constructor for every class you define, and that the constructor initialize {\bf every} data member of the class. If you don't define your own constructor, the compiler will automatically define one for you, and believe me, it won't do what you want (``the unhelpful compiler''). The data members will be initialized to random, unrepeatable values, and while your program may work anyway, it might not the next time you recompile (or vice versa!). As with normal C variables, variables declared inside a function are deallocated automatically when the function returns; for example, the {\tt s1} object is deallocated when {\tt test} returns. Data allocated with {\tt new} (such as {\tt s2}) is stored on the heap, however, and remains after the function returns; heap data must be explicitly disposed of using {\tt delete}, described below. The {\tt new} operator can also be used to allocate arrays, illustrated above in allocating an array of {\tt ints}, of dimension {\tt size}: \begin{verbatim} stack = new int[size]; \end{verbatim} Note that you can use {\tt new} and {\tt delete} (described below) with built-in types like {\tt int} and {\tt char} as well as with class objects like {\tt Stack}. \item {\bf Destructors and the operator delete.} Just as {\tt new} is the replacement for {\tt malloc()}, the replacement for {\tt free()} is {\tt delete}. To get rid of the {\tt Stack} object we allocated above with {\tt new}, one can do: \begin{verbatim} delete s2; \end{verbatim} This will deallocate the object, but first it will call the {\it destructor} for the {\tt Stack} class, if there is one. This destructor is a member function of {\tt Stack} called {\tt {\verb^~^}Stack()}: \begin{verbatim} class Stack { public: Stack(int sz); // Constructor: initialize variables, allocate space. ~Stack(); // Destructor: deallocate space allocated above. void Push(int value); // Push an integer, checking for overflow. bool Full(); // Returns TRUE if the stack is full, FALSE otherwise. private: int size; // The maximum capacity of the stack. int top; // Index of the lowest unused position. int* stack; // A pointer to an array that holds the contents. }; Stack::~Stack() { delete [] stack; // delete an array of integers } \end{verbatim} The destructor has the job of deallocating the data the constructor allocated. Many classes won't need destructors, and some will use them to close files and otherwise clean up after themselves. The destructor for an object is called when the object is deallocated. If the object was created with {\tt new}, then you must call {\tt delete} on the object, or else the object will continue to occupy space until the program is over -- this is called ``a memory leak.'' Memory leaks are bad things -- although virtual memory is supposed to be unlimited, you can in fact run out of it -- and so you should be careful to {\bf always} delete what you allocate. Of course, it is even worse to call {\tt delete} too early -- {\tt delete} calls the destructor and puts the space back on the heap for later re-use. If you are still using the object, you will get random and non-repeatable results that will be very difficult to debug. In my experience, using data that has already been deleted is major source of hard-to-locate bugs in student (and professional) programs, so hey, be careful out there! If the object is an automatic, allocated on the execution stack of a function, the destructor will be called and the space deallocated when the function returns; in the {\tt test()} example above, {\tt s1} will be deallocated when {\tt test()} returns, without you having to do anything. In Nachos, we always explicitly allocate and deallocate objects with {\tt new} and {\tt delete}, to make it clear when the constructor and destructor is being called. For example, if an object contains another object as a member variable, we use {\tt new} to explicitly allocated and initialize the member variable, instead of implicitly allocating it as part of the containing object. C++ has strange, non-intuitive rules for the order in which the constructors and destructors are called when you implicitly allocate and deallocate objects. In practice, although simpler, explicit allocation is slightly slower and it makes it more likely that you will forget to deallocate an object (a bad thing!), and so some would disagree with this approach. When you deallocate an array, you have to tell the compiler that you are deallocating an array, as opposed to a single element in the array. Hence to delete the array of integers in {\tt Stack::{\verb^~^}Stack}: \begin{verbatim} delete [] stack; \end{verbatim} \end{enumerate} \subsection{Other Basic C++ Features} Here are a few other C++ features that are useful to know. \begin{enumerate} \item When you define a {\tt class Stack}, the name {\tt Stack} becomes usable as a type name as if created with {\tt typedef}. The same is true for {\tt enum}s. \item You can define functions inside of a {\tt class} definition, whereupon they become {\it inline functions}, which are expanded in the body of the function where they are used. The rule of thumb to follow is to only consider inlining one-line functions, and even then do so rarely. As an example, we could make the {\tt Full} routine an inline. \begin{verbatim} class Stack { ... bool Full() { return (top == size); }; ... }; \end{verbatim} There are two motivations for inlines: convenience and performance. If overused, inlines can make your code more confusing, because the implementation for an object is no longer in one place, but spread between the {\tt .h} and {\tt .c} files. Inlines can sometimes speed up your code (by avoiding the overhead of a procedure call), but that shouldn't be your principal concern as a student (rather, at least to begin with, you should be most concerned with writing code that is simple and bug free). Not to mention that inlining sometimes slows down a program, since the object code for the function is duplicated wherever the function is called, potentially hurting cache performance. \item Inside a function body, you can declare some variables, execute some statements, and then declare more variables. This can make code a lot more readable. In fact, you can even write things like: \begin{verbatim} for (int i = 0; i < 10; i++) ; \end{verbatim} Depending on your compiler, however, the variable {\tt i} may still visible after the end of the {\tt for} loop, however, which is not what one might expect or desire. \item Comments can begin with the characters \verb+//+ and extend to the end of the line. These are usually more handy than the \verb+/* */+ style of comments. \item C++ provides some new opportunities to use the {\tt const} keyword from ANSI C. The basic idea of {\tt const} is to provide extra information to the compiler about how a variable or function is used, to allow it to flag an error if it is being used improperly. You should always look for ways to get the compiler to catch bugs for you. After all, which takes less time? Fixing a compiler-flagged error, or chasing down the same bug using gdb? For example, you can declare that a member function only reads the member data, and never modifies the object: \begin{verbatim} class Stack { ... bool Full() const; // Full() never modifies member data ... }; \end{verbatim} As in C, you can use {\tt const} to declare that a variable is never modified: \begin{verbatim} const int InitialHashTableSize = 8; \end{verbatim} This is {\em much} better than using {\tt \#define} for constants, since the above is type-checked. \item Input/output in C++ can be done with the {\tt >>} and {\tt <<} operators and the objects {\tt cin} and {\tt cout}. For example, to write to {\tt stdout}: \begin{verbatim} cout << "Hello world! This is section " << 3 << "!"; \end{verbatim} This is equivalent to the normal C code \begin{verbatim} fprintf(stdout, "Hello world! This is section %d!\n", 3); \end{verbatim} except that the C++ version is type-safe; with {\tt printf}, the compiler won't complain if you try to print a floating point number as an integer. In fact, you can use traditional {\tt printf} in a C++ program, but you will get bizarre behavior if you try to use both {\tt printf} and {\tt <<} on the same stream. Reading from {\tt stdin} works the same way as writing to {\tt stdout}, except using the shift right operator instead of shift left. In order to read two integers from {\tt stdin}: \begin{verbatim} int field1, field2; cin >> field1 >> field2; // equivalent to fscanf(stdin, "%d %d", &field1, &field2); // note that field1 and field2 are implicitly modified \end{verbatim} In fact, {\tt cin} and {\tt cout} are implemented as normal C++ objects, using operator overloading and reference parameters, but (fortunately!) you don't need to understand either of those to be able to do I/O in C++. \end{enumerate} \section{Advanced Concepts in C++: Dangerous but Occasionally Useful} There are a few C++ features, namely (single) inheritance and templates, which are easily abused, but can dramatically simplify an implementation if used properly. I describe the basic idea behind these ``dangerous but useful'' features here, in case you run across them. Feel free to skip this section -- it's long, complex, and you can understand 99\% of the code in Nachos without reading this section. Up to this point, there really hasn't been any fundamental difference between programming in C and in C++. In fact, most experienced C programmers organize their functions into modules that relate to a single data structure (a "class"), and often even use a naming convention which mimics C++, for example, naming routines {\tt StackFull()} and {\tt StackPush()}. However, the features I'm about to describe {\em do} require a paradigm shift -- there is no simple translation from them into a normal C program. The benefit will be that, in some circumstances, you will be able to write generic code that works with multiple kinds of objects. Nevertheless, I would advise a beginning C++ programmer against trying to use these features, because you will almost certainly misuse them. It's possible (even easy!) to write completely inscrutable code using inheritance and/or templates. Although you might find it amusing to write code that is impossible for your graders to understand, I assure you they won't find it amusing at all, and will return the favor when they assign grades. In industry, a high premium is placed on keeping code simple and readable. It's easy to write new code, but the real cost comes when you try to keep it working, even as you add new features to it. Nachos contains a few examples of the correct use of inheritance and templates, but realize that Nachos does {\em not} use them everywhere. In fact, if you get confused by this section, don't worry, you don't need to use any of these features in order to do the Nachos assignments. I omit a whole bunch of details; if you find yourself making widespread use of inheritance or templates, you should consult a C++ reference manual for the real scoop. This is meant to be just enough to get you started, and to help you identify when it would be appropriate to use these features and thus learn more about them! \subsection{Inheritance} Inheritance captures the idea that certain classes of objects are related to each other in useful ways. For example, lists and sorted lists have quite similar behavior -- they both allow the user to insert, delete, and find elements that are on the list. There are two benefits to using inheritance: \begin{enumerate} \item You can write generic code that doesn't care exactly which kind of object it is manipulating. For example, inheritance is widely used in windowing systems. Everything on the screen (windows, scroll bars, titles, icons) is its own object, but they all share a set of member functions in common, such as a routine {\tt Repaint} to redraw the object onto the screen. This way, the code to repaint the entire screen can simply call the {\tt Repaint} function on every object on the screen. The code that calls {\tt Repaint} doesn't need to know which kinds of objects are on the screen, as long as each implements {\tt Repaint}. \item You can share pieces of an implementation between two objects. For example, if you were to implement both lists and sorted lists in C, you'd probably find yourself repeating code in both places -- in fact, you might be really tempted to only implement sorted lists, so that you only had to debug one version. Inheritance provides a way to re-use code between nearly similar classes. For example, given an implementation of a list class, in C++ you can implement sorted lists by replacing the insert member function -- the other functions, delete, isFull, print, all remain the same. \end{enumerate} \subsubsection{Shared Behavior} Let me use our Stack example to illustrate the first of these. Our Stack implementation above could have been implemented with linked lists, instead of an array. Any code using a Stack shouldn't care which implementation is being used, except that the linked list implementation can't overflow. (In fact, we could also change the array implementation to handle overflow by automatically resizing the array as items are pushed on the stack.) To allow the two implementations to coexist, we first define an {\em abstract} Stack, containing just the public member functions, but no data. \begin{verbatim} class Stack { public: Stack(); virtual ~Stack(); // deallocate the stack virtual void Push(int value) = 0; // Push an integer, checking for overflow. virtual bool Full() = 0; // Is the stack is full? }; // For g++, need these even though no data to initialize. Stack::Stack {} Stack::~Stack() {} \end{verbatim} The {\tt Stack} definition is called a {\em base class} or sometimes a {\em superclass}. We can then define two different {\em derived classes}, sometimes called {\em subclasses} which inherit behavior from the base class. (Of course, inheritance is recursive -- a derived class can in turn be a base class for yet another derived class, and so on.) Note that I have prepended the functions in the base class is prepended with the keyword {\tt virtual}, to signify that they can be redefined by each of the two derived classes. The virtual functions are initialized to zero, to tell the compiler that those functions must be defined by the derived classes. Here's how we could declare the array-based and list-based implementations of {\tt Stack}. The syntax {\tt : public Stack} signifies that both {\tt ArrayStack} and {\tt ListStack} are kinds of {\tt Stacks}, and share the same behavior as the base class. \begin{verbatim} class ArrayStack : public Stack { // the same as in Section 2 public: ArrayStack(int sz); // Constructor: initialize variables, allocate space. ~ArrayStack(); // Destructor: deallocate space allocated above. void Push(int value); // Push an integer, checking for overflow. bool Full(); // Returns TRUE if the stack is full, FALSE otherwise. private: int size; // The maximum capacity of the stack. int top; // Index of the lowest unused position. int *stack; // A pointer to an array that holds the contents. }; class ListStack : public Stack { public: ListStack(); ~ListStack(); void Push(int value); bool Full(); private: List *list; // list of items pushed on the stack }; ListStack::ListStack() { list = new List; } ListStack::~ListStack() { delete list; } \end{verbatim} \newpage \begin{verbatim} void ListStack::Push(int value) { list->Prepend(value); } bool ListStack::Full() { return FALSE; // this stack never overflows! } \end{verbatim} The neat concept here is that I can assign pointers to instances of {\tt ListStack} or {\tt ArrayStack} to a variable of type {\tt Stack}, and then use them as if they were of the base type. \begin{verbatim} Stack *s1 = new ListStack; Stack *s2 = new ArrayStack(17); if (!stack->Full()) s1->Push(5); if (!s2->Full()) s2->Push(6); delete s1; delete s2; \end{verbatim} The compiler automatically invokes {\tt ListStack} operations for {\tt s1}, and {\tt ArrayStack} operations for {\tt s2}; this is done by creating a procedure table for each object, where derived objects override the default entries in the table defined by the base class. To the code above, it invokes the operations {\tt Full}, {\tt Push}, and {\tt delete} by indirection through the procedure table, so that the code doesn't need to know which kind of object it is. In this example, since I never create an instance of the abstract class {\tt Stack}, I do not need to {\em implement} its functions. This might seem a bit strange, but remember that the derived classes are the various implementations of Stack, and Stack serves only to reflect the shared behavior between the different implementations. Also note that the destructor for {\tt Stack} is a virtual function but the constructor is not. Clearly, when I create an object, I have to know which kind of object it is, whether {\tt ArrayStack} or {\tt ListStack}. The compiler makes sure that no one creates an instance of the abstract {\tt Stack} by mistake -- you cannot instantiate any class whose virtual functions are not completely defined (in other words, if any of its functions are set to zero in the class definition). But when I deallocate an object, I may no longer know its exact type. In the above code, I want to call the destructor for the derived object, even though the code only knows that I am deleting an object of class {\tt Stack}. If the destructor were not virtual, then the compiler would invoke {\tt Stack}'s destructor, which is not at all what I want. This is an easy mistake to make (I made it in the first draft of this article!) -- if you don't define a destructor for the abstract class, the compiler will define one for you implicitly (and by the way, it won't be virtual, since you have a {\em really} unhelpful compiler). The result for the above code would be a memory leak, and who knows how you would figure that out! \subsubsection{Shared Implementation} What about sharing code, the other reason for inheritance? In C++, it is possible to use member functions of a base class in its derived class. (You can also share data between a base class and derived classes, but this is a bad idea for reasons I'll discuss later.) Suppose that I wanted to add a new member function, {\tt NumberPushed()}, to both implementations of {\tt Stack}. The {\tt ArrayStack} class already keeps count of the number of items on the stack, so I could duplicate that code in {\tt ListStack}. Ideally, I'd like to be able to use the same code in both places. With inheritance, we can move the counter into the {\tt Stack} class, and then invoke the base class operations from the derived class to update the counter. \begin{verbatim} class Stack { public: virtual ~Stack(); // deallocate data virtual void Push(int value); // Push an integer, checking for overflow. virtual bool Full() = 0; // return TRUE if full int NumPushed(); // how many are currently on the stack? protected: Stack(); // initialize data private: int numPushed; }; Stack::Stack() { numPushed = 0; } void Stack::Push(int value) { numPushed++; } int Stack::NumPushed() { return numPushed; } \end{verbatim} We can then modify both {\tt ArrayStack} and {\tt ListStack} to make use the new behavior of {\tt Stack}. I'll only list one of them here: \begin{verbatim} class ArrayStack : public Stack { public: ArrayStack(int sz); ~ArrayStack(); void Push(int value); bool Full(); private: int size; // The maximum capacity of the stack. int *stack; // A pointer to an array that holds the contents. }; ArrayStack::ArrayStack(int sz) : Stack() { size = sz; stack = new int[size]; // Let's get an array of integers. } void ArrayStack::Push(int value) { ASSERT(!Full()); stack[NumPushed()] = value; Stack::Push(); // invoke base class to increment numPushed } \end{verbatim} There are a few things to note: \begin{enumerate} \item The constructor for {\tt ArrayStack} needs to invoke the constructor for {\tt Stack}, in order to initialize {\tt numPushed}. It does that by adding {\tt : Stack()} to the first line in the constructor: \begin{verbatim} ArrayStack::ArrayStack(int sz) : Stack() \end{verbatim} The same thing applies to destructors. There are special rules for which get called first -- the constructor/destructor for the base class or the constructor/destructor for the derived class. All I should say is, it's a bad idea to rely on whatever the rule is -- more generally, it is a bad idea to write code which requires the reader to consult a manual to tell whether or not the code works! \item I introduced a new keyword, {\tt protected}, in the new definition of {\tt Stack}. For a base class, {\tt protected} signifies that those member data and functions are accessible to classes derived (recursively) from this class, but inaccessible to other classes. In other words, protected data is {\tt public} to derived classes, and {\tt private} to everyone else. For example, we need {\tt Stack}'s constructor to be callable by {\tt ArrayStack} and {\tt ListStack}, but we don't want anyone else to create instances of {\tt Stack}. Hence, we make {\tt Stack}'s constructor a protected function. In this case, this is not strictly necessary since the compiler will complain if anyone tries to create an instance of {\tt Stack} because {\tt Stack} still has an undefined virtual functions, {\tt Push}. By defining {\tt Stack::Stack} as {\tt protected}, you are safe even if someone comes along later and defines {\tt Stack::Push}. Note however that I made {\tt Stack}'s data member {\tt private}, not {\tt protected}. Although there is some debate on this point, as a rule of thumb you should never allow one class to see directly access the data in another, even among classes related by inheritance. Otherwise, if you ever change the implementation of the base class, you will have to examine and change all the implementations of the derived classes, violating modularity. \item The interface for a derived class automatically includes all functions defined for its base class, without having to explicitly list them in the derived class. Although we didn't define {\tt NumPushed()} in {\tt ArrayStack}, we can still call it for those objects: \begin{verbatim} ArrayStack *s = new ArrayStack(17); ASSERT(s->NumPushed() == 0); // should be initialized to 0 \end{verbatim} \item Conversely, even though we have defined a routine {\tt Stack::Push()}, because it is declared as {\tt virtual}, if we invoke {\tt Push()} on an {\tt ArrayStack} object, we will get {\tt ArrayStack}'s version of {\tt Push}: \begin{verbatim} Stack *s = new ArrayStack(17); if (!s->Full()) // ArrayStack::Full s->Push(5); // ArrayStack::Push \end{verbatim} \item {\tt Stack::NumPushed()} is not {\tt virtual}. That means that it cannot be re-defined by {\tt Stack}'s derived classes. Some people believe that you should mark {\em all} functions in a base class as {\tt virtual}; that way, if you later want to implement a derived class that redefines a function, you don't have to modify the base class to do so. \item Member functions in a derived class can explicitly invoke public or protected functions in the base class, by the full name of the function, {\tt Base::Function()}, as in: \begin{verbatim} void ArrayStack::Push(int value) { ... Stack::Push(); // invoke base class to increment numPushed } \end{verbatim} Of course, if we just called {\tt Push()} here (without prepending {\tt Stack::}, the compiler would think we were referring to {\tt ArrayStack}'s {\tt Push()}, and so that would recurse, which is not exactly what we had in mind here. \end{enumerate} Whew! Inheritance in C++ involves lots and lots of details. But it's real downside is that it tends to spread implementation details across multiple files -- if you have a deep inheritance tree, it can take some serious digging to figure out what code actually executes when a member function is invoked. So the question to ask yourself before using inheritance is: what's your goal? Is it to write your programs with the fewest number of characters possible? If so, inheritance is really useful, but so is changing all of your function and variable names to be one letter long -- "a", "b", "c" -- and once you run out of lower case ones, start using upper case, then two character variable names: "XX XY XZ Ya ..." (I'm joking here.) Needless to say, it is really easy to write unreadable code using inheritance. So when is it a good idea to use inheritance and when should it be avoided? My rule of thumb is to only use it for representing {\em shared behavior} between objects, and to never use it for representing {\em shared implementation}. With C++, you can use inheritance for both concepts, but only the first will lead to truly simpler implementations. To illustrate the difference between shared behavior and shared implementation, suppose you had a whole bunch of different kinds of objects that you needed to put on lists. For example, almost everything in an operating system goes on a list of some sort: buffers, threads, users, terminals, etc. A very common approach to this problem (particularly among people new to object-oriented programming) is to make every object inherit from a single base class {\em Object}, which contains the forward and backward pointers for the list. But what if some object needs to go on multiple lists? The whole scheme breaks down, and it's because we tried to use inheritance to share implementation (the code for the forward and backward pointers) instead of to share behavior. A much cleaner (although slightly slower) approach would be to define a list implementation that allocated forward/backward pointers for each object that gets put on a list. In sum, if two classes share at least some of the same member function signatures -- that is, the same behavior, {\em and} if there's code that only relies on the shared behavior, then there {\em may} be a benefit to using inheritance. In Nachos, locks don't inherit from semaphores, even though locks are implemented using semaphores. The operations on semaphores and locks are different. Instead, inheritance is only used for various kinds of lists (sorted, keyed, etc.), and for different implementations of the physical disk abstraction, to reflect whether the disk has a track buffer, etc. A disk is used the same way whether or not it has a track buffer; the only difference is in its performance characteristics. \subsection{Templates} Templates are another useful but dangerous concept in C++. With templates, you can parameterize a class definition with a {\em type}, to allow you to write generic type-independent code. For example, our {\tt Stack} implementation above only worked for pushing and popping {\em integers}; what if we wanted a stack of characters, or floats, or pointers, or some arbitrary data structure? In C++, this is pretty easy to do using templates: \begin{verbatim} template <class T> class Stack { public: Stack(int sz); // Constructor: initialize variables, allocate space. ~Stack(); // Destructor: deallocate space allocated above. void Push(T value); // Push an integer, checking for overflow. bool Full(); // Returns TRUE if the stack is full, FALSE otherwise. private: int size; // The maximum capacity of the stack. int top; // Index of the lowest unused position. T *stack; // A pointer to an array that holds the contents. }; \end{verbatim} To define a template, we prepend the keyword {\tt template} to the class definition, and we put the parameterized type for the template in angle brackets. If we need to parameterize the implementation with two or more types, it works just like an argument list: {\tt template <class T, class S>}. We can use the type parameters elsewhere in the definition, just like they were normal types. When we provide the implementation for each of the member functions in the class, we also have to declare them as templates, and again, once we do that, we can use the type parameters just like normal types: \begin{verbatim} // template version of Stack::Stack template <class T> Stack<T>::Stack(int sz) { size = sz; top = 0; stack = new T[size]; // Let's get an array of type T } // template version of Stack::Push template <class T> void Stack<T>::Push(T value) { ASSERT(!Full()); stack[top++] = value; } \end{verbatim} Creating an object of a template class is similar to creating a normal object: \begin{verbatim} void test() { Stack<int> s1(17); Stack<char> *s2 = new Stack<char>(23); s1.Push(5); s2->Push('z'); delete s2; } \end{verbatim} Everything operates as if we defined two classes, one called {\tt Stack<int>} -- a stack of integers, and one called {\tt Stack<char>} -- a stack of characters. {\tt s1} behaves just like an instance of the first; {\tt s2} behaves just like an instance of the second. In fact, that is exactly how templates are typically implemented -- you get a complete {\em copy} of the code for the template for each different instantiated type. In the above example, we'd get one copy of the code for {\tt ints} and one copy for {\tt chars}. So what's wrong with templates? You've all been taught to make your code modular so that it can be re-usable, so {\em everything} should be a template, right? Wrong. The principal problem with templates is that they can be {\em very} difficult to debug -- templates are easy to use if they work, but finding a bug in them can be difficult. In part this is because current generation C++ debuggers don't really understand templates very well. Nevertheless, it is easier to debug a template than two nearly identical implementations that differ only in their types. So the best advice is -- don't make a class into a template unless there really is a near term use for the template. And if you do need to implement a template, implement and debug a non-template version first. Once that is working, it won't be hard to convert it to a template. Then all you have to worry about code explosion -- e.g., your program's object code is now megabytes because of the 15 copies of the hash table/list/... routines, one for each kind of thing you want to put in a hash table/list/... (Remember, you have an unhelpful compiler!) \section{Features To Avoid Like the Plague} Despite the length of this note, there are numerous features in C++ that I haven't explained. I'm sure each feature has its advocates, but despite programming in C and C++ for over 15 years, I haven't found a compelling reason to use them in any code that I've written (outside of a programming language class!) Indeed, there is a compelling reason to avoid using these features -- they are easy to misuse, resulting in programs that are harder to read and understand instead of easier to understand. In most cases, the features are also redundant -- there are other ways of accomplishing the same end. Why have two ways of doing the same thing? Why not stick with the simpler one? I do not use any of the following features in Nachos. If you use them, {\it caveat hacker}. \begin{enumerate} \item {\bf Multiple inheritance.} It is possible in C++ to define a class as inheriting behavior from multiple classes (for instance, a dog is both an animal and a furry thing). But if programs using single inheritance can be difficult to untangle, programs with multiple inheritance can get really confusing. \item {\bf References.} Reference variables are rather hard to understand in general; they play the same role as pointers, with slightly different syntax (unfortunately, I'm not joking!) Their most common use is to declare some parameters to a function as {\it reference parameters}, as in Pascal. A call-by-reference parameter can be modified by the calling function, without the callee having to pass a pointer. The effect is that parameters look (to the caller) like they are called by value (and therefore can't change), but in fact can be transparently modified by the called function. Obviously, this can be a source of obscure bugs, not to mention that the semantics of references in C++ are in general not obvious. \item {\bf Operator overloading.} C++ lets you redefine the meanings of the operators (such as {\tt +} and \verb+>>+) for class objects. This is dangerous at best ("exactly which implementation of '+' does this refer to?"), and when used in non-intuitive ways, a source of great confusion, made worse by the fact that C++ does implicit type conversion, which can affect which operator is invoked. Unfortunately, C++'s I/O facilities make heavy use of operator overloading and references, so you can't completely escape them, but think twice before you redefine '+' to mean ``concatenate these two strings''. \item {\bf Function overloading.} You can also define different functions in a class with the same name but different argument types. This is also dangerous (since it's easy to slip up and get the unintended version), and we never use it. We will also avoid using default arguments (for the same reason). Note that it can be a good idea to use the same name for functions in different classes, provided they use the same arguments and behave the same way -- a good example of this is that most Nachos objects have a {\tt Print()} method. \item {\bf Standard template library.} An ANSI standard has emerged for a library of routines implementing such things as lists, hash tables, etc., called the standard template library. Using such a library should make programming much simpler if the data structure you need is already provided in the library. Alas, the standard template library pushes the envelope of legal C++, and so virtually no compilers (including g++) can support it today. Not to mention that it uses (big surprise!) references, operator overloading, and function overloading. \item {\bf Exceptions.} There are two ways to return an error from a procedure. One is simple -- just define the procedure to return an error code if it isn't able to do it's job. For example, the standard library routine {\tt malloc} returns NULL if there is no available memory. However, lots of programmers are lazy and don't check error codes. So what's the solution? You might think it would be to get programmers who aren't lazy, but no, the C++ solution is to add a programming language construct! A procedure can return an error by ``raising an exception'' which effectively causes a {\tt goto} back up the execution stack to the last place the programmer put an exception handler. You would think this is too bizarre to be true, but unfortunately, I'm not making this up. \end{enumerate} While I'm at it, there are a number of features of C that you also should avoid, because they lead to bugs and make your code less easy to understand. See Maguire's "Writing Solid Code" for a more complete discussion of this issue. All of these features are legal C; what's legal isn't necessarily good. \begin{enumerate} \item Pointer arithmetic. Runaway pointers are a principal source of hard-to-find bugs in C programs, because the symptom of this happening can be mangled data structures in a completely different part of the program. Depending on exactly which objects are allocated on the heap in which order, pointer bugs can appear and disappear, seemingly at random. For example, {\tt printf} sometimes allocates memory on the heap, which can change the addresses returned by all future calls to {\tt new}. Thus, adding a {\tt printf} can change things so that a pointer which used to (by happenstance) mangle a critical data structure (such as the middle of a thread's execution stack), now overwrites memory that may not even be used. The best way to avoid runaway pointers is (no surprise) to be {\em very} careful when using pointers. Instead of iterating through an array with pointer arithmetic, use a separate index variable, and assert that the index is never larger than the size of the array. Optimizing compilers have gotten very good, so that the generated machine code is likely to be the same in either case. Even if you don't use pointer arithmetic, it's still easy (easy is bad in this context!) to have an off-by-one errror that causes your program to step beyond the end of an array. How do you fix this? Define a class to contain the array {\em and its length}; before allowing any access to the array, you can then check whether the access is legal or in error. \item Casts from integers to pointers and back. Another source of runaway pointers is that C and C++ allow you to convert integers to pointers, and back again. Needless to say, using a random integer value as a pointer is likely to result in unpredictable symptoms that will be very hard to track down. In addition, on some 64 bit machines, such as the Alpha, it is no longer the case that the size of an integer is the same as the the size of a pointer. If you cast between pointers and integers, you are also writing highly non-portable code. \item Using bit shift in place of a multiply or divide. This is a clarity issue. If you are doing arithmetic, use arithmetic operators; if you are doing bit manipulation, use bitwise operators. If I am trying to multiply by 8, which is easier to understand, {\tt x << 3} or {\tt x * 8}? In the 70's, when C was being developed, the former would yield more efficient machine code, but today's compilers generate the same code in both cases, so readability should be your primary concern. \item Assignment inside conditional. Many programmers have the attitude that simplicity equals saving as many keystrokes as possible. The result can be to hide bugs that would otherwise be obvious. For example: \begin{verbatim} if (x = y) { ... \end{verbatim} Was the intent really {\tt x == y}? After all, it's pretty easy to mistakenly leave off the extra equals sign. By never using assignment within a conditional, you can tell by code inspection whether you've made a mistake. \item Using {\tt \#define} when you could use {\tt enum}. When a variable can hold one of a small number of values, the original C practice was to use {\tt \#define} to set up symbolic names for each of the values. {\tt enum} does this in a type-safe way -- it allows the compiler to verify that the variable is only assigned one of the enumerated values, and none other. Again, the advantage is to eliminate a class of errors from your program, making it quicker to debug. \end{enumerate} \newpage \section{Style Guidelines} Even if you follow the approach I've outlined above, it is still as easy to write unreadable and undebuggable code in C++ as it is in C, and perhaps easier, given the more powerful features the language provides. For the Nachos project, and in general, we suggest you adhere to the following guidelines (and tell us if you catch us breaking them): \begin{enumerate} \item Words in a name are separated SmallTalk-style (i.e., capital letters at the start of each new word). All class names and member function names begin with a capital letter, except for member functions of the form {\tt getSomething()} and {\tt setSomething()}, where {\tt Something} is a data element of the class (i.e., accessor functions). Note that you would want to provide such functions only when the data should be visible to the outside world, but you want to force all accesses to go through one function. This is often a good idea, since you might at some later time decide to compute the data instead of storing it, for example. \item All global functions should be capitalized, except for {\tt main} and library functions, which are kept lower-case for historical reasons. \item Minimize the use of global variables. If you find yourself using a lot of them, try and group some together in a class in a natural way or pass them as arguments to the functions that need them if you can. \item Minimize the use of global functions (as opposed to member functions). If you write a function that operates on some object, consider making it a member function of that object. \item For every class or set of related classes, create a separate {\tt .h} file and {\tt .cc} file. The {\tt .h} file acts as the {\it interface} to the class, and the {\tt .cc} file acts as the {\it implementation} (a given {\tt .cc} file should {\tt include} it's respective {\tt .h} file). If using a particular {\tt .h} file requires another {\tt .h} file to be included (e.g., {\tt synch.h} needs class definitions from {\tt thread.h}) you should include the dependency in the {\tt .h} file, so that the user of your class doesn't have to track down all the dependencies himself. To protect against multiple inclusion, bracket each {\tt .h} file with something like: \begin{verbatim} #ifndef STACK_H #define STACK_H class Stack { ... }; #endif \end{verbatim} Sometimes this will not be enough, and you will have a circular dependency. For example, you might have a {\tt .h} file that uses a definition from one {\tt .h} file, but also defines something needed by that {\tt .h} file. In this case, you will have to do something ad-hoc. One thing to realize is that you don't always have to completely define a class before it is used. If you only use a pointer to class {\tt Stack} and do not access any member functions or data from the class, you can write, in lieu of including {\tt stack.h}: \begin{verbatim} class Stack; \end{verbatim} This will tell the compiler all it needs to know to deal with the pointer. In a few cases this won't work, and you will have to move stuff around or alter your definitions. \item Use {\tt ASSERT} statements liberally to check that your program is behaving properly. An assertion is a condition that if FALSE signifies that there is a bug in the program; {\tt ASSERT} tests an expression and aborts if the condition is false. We used {\tt ASSERT} above in {\tt Stack::Push()} to check that the stack wasn't full. The idea is to catch errors as early as possible, when they are easier to locate, instead of waiting until there is a user-visible symptom of the error (such as a segmentation fault, after memory has been trashed by a rogue pointer). Assertions are particularly useful at the beginnings and ends of procedures, to check that the procedure was called with the right arguments, and that the procedure did what it is supposed to. For example, at the beginning of List::Insert, you could assert that the item being inserted isn't already on the list, and at the end of the procedure, you could assert that the item is now on the list. If speed is a concern, ASSERTs can be defined to make the check in the debug version of your program, and to be a no-op in the production version. But many people run with ASSERTs enabled even in production. \item Write a module test for every module in your program. Many programmers have the notion that testing code means running the entire program on some sample input; if it doesn't crash, that means it's working, right? Wrong. You have no way of knowing how much code was exercised for the test. Let me urge you to be methodical about testing. Before you put a new module into a bigger system, make sure the module works as advertised by testing it standalone. If you do this for every module, then when you put the modules together, instead of {\em hoping} that everything will work, you will {\em know} it will work. Perhaps more importantly, module tests provide an opportunity to find as many bugs as possible in a localized context. Which is easier: finding a bug in a 100 line program, or in a 10000 line program? \end{enumerate} \section{Compiling and Debugging} The Makefiles we will give you works only with the GNU version of make, called ``gmake''. You may want to put ``alias make gmake'' in your .cshrc file. You should use {\bf gdb} to debug your program rather than {\bf dbx}. Dbx doesn't know how to decipher C++ names, so you will see function names like \verb+Run__9SchedulerP6Thread+. On the other hand, in GDB (but not DBX) when you do a stack backtrace when in a forked thread (in homework 1), after printing out the correct frames at the top of the stack, the debugger will sometimes go into a loop printing the lower-most frame ({\tt ThreadRoot}), and you have to type control-C when it says ``more?''. If you understand assembly language and can fix this, please let me know. \section{Example: A Stack of Integers} We've provided the complete, working code for the stack example. You should read through it and play around with it to make sure you understand the features of C++ described in this paper. To compile the simple stack test, type {\tt make all} -- this will compile the simple stack test ({\tt stack.cc}), the inherited stack test ({\tt inheritstack.cc}), and the template version of stacks ({\tt templatestack.cc}). \section{Epilogue} I've argued in this note that you should avoid using certain C++ and C features. But you're probably thinking I must be leaving something out -- if someone put the feature in the language, there must be a good reason, right? I believe that every programmer should strive to write code whose behavior would be immediately obvious to a reader; if you find yourself writing code that would require someone reading the code to thumb through a manual in order to understand it, you are almost certainly being way too subtle. There's probably a much simpler and more obvious way to accomplish the same end. Maybe the code will be a little longer that way, but in the real world, it's whether the code works and how simple it is for someone else to modify, that matters a whole lot more than how many characters you had to type. A final thought to remember: \begin{quote} ``There are two ways of constructing a software design: one way is to make it so simple that there are {\em obviously} no deficiencies and the other way is to make it so complicated that there are no {\em obvious} deficiencies.'' \\ \hbox{} \hfill C. A. R. Hoare, ``The Emperor's Old Clothes'', CACM Feb. 1981 \end{quote} \section{Further Reading} \begin{itemize} \item[] James Coplien, ``Advanced C++'', Addison-Wesley. This book is only for experts, but it has some good ideas in it, so keep it in mind once you've been programming in C++ for a few years. \item[] James Gosling. ``The Java Language.'' Online at ``http://java.sun.com/'' Java is a safe subset of C++. It's main application is the safe extension of Web browsers by allowing you to download Java code as part of clicking on a link to interpret and display the document. Safety is key here, since after all, you don't want to click on a Web link and have it download code that will crash your browser. Java was defined independently of this document, but interestingly, it enforces a very similar style (for example, no multiple inheritance and no operator overloading). \item[] C.A.R. Hoare, ``The Emperor's Old Clothes.'' {\em Communications of the ACM}, Vol. 24, No. 2, February 1981, pp. 75-83. Tony Hoare's Turing Award lecture. How do you build software that really works? Attitude is everything -- you need a healthy respect for how hard it is to build working software. It might seem that addding this whiz-bang feature is only ``a small matter of code'', but that's the path to late, buggy products that don't work. \item[] Brian Kernighan and Dennis Ritchie, ``The C Programming Language'', Prentice-Hall. The original C book -- a very easy read. But the language has evolved since it was first designed, and this book doesn't describe all of C's newest features. But still the best place for a beginner to start, even when learning C++. \item[] Steve Maguire, ``Writing Solid Code'', Microsoft Press. How to write bug-free software; I think this should be required reading for all software engineers. This really {\em will} change your life -- if you don't follow the recommendations in this book, you'll probably never write code that completely works, and you'll spend your entire life struggling with hard to find bugs. There is a better way! Contrary to the programming language types, this doesn't involve proving the correctness of your programs, whatever that means. Instead, Maguire has a set of practical engineering solutions to writing solid code. \item[] Steve Maguire, ``Debugging the Development Process'', Microsoft Press. Maguire's follow up book on how to lead an effective team, and by the way, how to be an effective engineer. Maguire's background is that he is a turnaround artist for Microsoft -- he gets assigned to floundering teams, and figures out how to make them effective. After you've pulled a few all-nighters to get that last bug out of your course project, you're probably wondering why in heck you're studying computer science anyway. This book will explain how to write programs that work, {\em and} still have a life! \item[] Scott Meyers, ``Effective C++''. This book describes how 50 easy ways to make mistakes C++; if you avoid these, you will be a lot more likely to write C++ code that works. \item[] Bjarne Stroustrup, ``The C++ Programming Language'', Addison-Wesley. This should be the definite reference manual, but it isn't. You probably thought I was joking when I said the C++ language was continually evolving. I bought the second edition of this book three years ago, and it is already out of date. Fortunately, it's still OK for the subset of C++ that I use. \end{itemize} \end{document}

nachos/c++example/inheritstack.h

// inheritstack.h // Data structures for a "stack" -- a Last-In-First-Out list of integers. // // We define two separate implementations of stacks, to // illustrate C++ inheritance. // // Copyright (c) 1992,1993,1995 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef INHERITSTACK_H // to prevent recursive includes #define INHERITSTACK_H #include "copyright.h" #include "list.h" // The following defines an "abstract" stack of integers. // This class is abstract because no one is allowed to create // instances of it; instead, you make instances of the derived // classes that inherit from it. class Stack { public: virtual ~Stack(); // Destructor virtual void Push(int value) = 0; // Push an integer on the stack virtual int Pop() = 0; // Pop an integer off the stack virtual bool Full() = 0; // Returns TRUE if the stack is full virtual bool Empty() = 0; // Returns TRUE if the stack is empty void SelfTest(int numToPush); // Test whether the implementation works. // Note that the test routine is shared among // all derived classes because it shouldn't // matter to the test code which version we're using! protected: Stack(); // Constructor is protected to prevent anyone but // derived classes from calling constructor. }; // The following defines an implementation of Stack using arrays. // This is the same as the original implementation in stack.h, // except we don't need a SelfTest() because that's defined above by Stack! class ArrayStack : public Stack { public: ArrayStack(int sz); // Constructor: initialize variables, allocate space. ~ArrayStack(); // Destructor: deallocate space allocated above. void Push(int value); // Push an integer on the stack int Pop(); // Pop an integer off the stack bool Full(); // Returns TRUE if the stack is full bool Empty(); // Returns TRUE if the stack is empty private: int size; // The maximum capacity of the stack. int top; // Index of the next position to be used. int *stack; // A pointer to an array that holds the contents. }; // The following defines an implementation of Stack using lists. // // Note that a list implementation can't overflow, so we don't // need to pass a maximum size into the constructor. class ListStack : public Stack { public: ListStack(); // Constructor: initialize variables, allocate space. ~ListStack(); // Destructor: deallocate space allocated above. void Push(int value); // Push an integer on the stack int Pop(); // Pop an integer off the stack bool Full(); // Always return FALSE, this implementation never overflows bool Empty(); // Returns TRUE if the stack is empty private: List *stack; }; #endif INHERITSTACK_H

nachos/coff2noff/coff2noff.x86Linux

nachos/coff2noff/copyright.h

/* Copyright (c) 1992-1996 The Regents of the University of California. All rights reserved. Permission to use, copy, modify, and distribute this software and its documentation for any purpose, without fee, and without written agreement is hereby granted, provided that the above copyright notice and the following two paragraphs appear in all copies of this software. IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */ #ifdef MAIN /* include the copyright message in every executable */ static char *copyright = "Copyright (c) 1992-1993 The Regents of the University of California. All rights reserved."; #endif // MAIN

nachos/coff2noff/noff.h

/* noff.h * Data structures defining the Nachos Object Code Format * * Basically, we only know about three types of segments: * code (read-only), initialized data, and unitialized data */ #define NOFFMAGIC 0xbadfad /* magic number denoting Nachos * object code file */ typedef struct segment { int virtualAddr; /* location of segment in virt addr space */ int inFileAddr; /* location of segment in this file */ int size; /* size of segment */ } Segment; typedef struct noffHeader { int noffMagic; /* should be NOFFMAGIC */ Segment code; /* executable code segment */ Segment initData; /* initialized data segment */ #ifdef RDATA Segment readonlyData; /* read only data */ #endif Segment uninitData; /* uninitialized data segment -- * should be zero'ed before use */ } NoffHeader;

nachos/coff2noff/Makefile.dep

############################################################################# # Machine-specific definitions # # In the MFCF environment, this attempts to determine automatically # the machine type and OS type. If it cannot, it gives up and # prints a message. # # If you are not in the MFCF environment, you can either add a new # automatic test for your machine/OS type, or you can set the # necessary variables "manually" here ############################################################################# # unfortunately, command line arguments to uname are not # very consistent across UNIX flavours. However, the following # seem to work almost everywhere in MFCF land osname = $(shell uname -s) osrelease = $(shell uname -r) hosttype = unknown # Test for Solaris (5.6) # At Waterloo: agnesi,bacon,fenchel,fitch,lassar,magnus,merrill # If Solaris, we assume we are on a SPARC, which is not necessarily # a good assumption outside of MFCF ifeq ($(osname),SunOS) ifeq ($(osrelease),5.6) HOSTCFLAGS = -DHOST_IS_BIG_ENDIAN hosttype = sparcSolaris endif endif # Test for Solaris (5.5) # At Waterloo: hermite.math,markov.math,picard.math,wronski.math,... # If Solaris, we assume we are on a SPARC, which is not necessarily # a good assumption outside of MFCF ifeq ($(osname),SunOS) ifeq ($(osrelease),5.5) HOSTCFLAGS = -DHOST_IS_BIG_ENDIAN hosttype = sparcSolaris endif endif # Test for Solaris (5.4) # At Waterloo: hume.math, hypatia.math,... # This is the same setup as Solaris 5.5 # If Solaris, we assume we are on a SPARC, which is not necessarily # a good assumption outside of MFCF ifeq ($(osname),SunOS) ifeq ($(osrelease),5.4) HOSTCFLAGS = -DHOST_IS_BIG_ENDIAN hosttype = sparcSolaris endif endif # Test for SunOS 4.xx # At Waterloo: descartes,cayley,napier,.... # If SunOS, we assume we are on a SPARC, which is not necessarily # a good assumption outside of MFCF ifeq ($(osname),SunOS) ifeq ($(osrelease),4.1.3_U1) HOSTCFLAGS = -DHOST_IS_BIG_ENDIAN hosttype = sparcSunOS endif endif # Test for ULTRIX # At Waterloo: cantor.math,noether.math # Assume ULTRIX on a MIPS architecture ifeq ($(osname),ULTRIX) HOSTCFLAGS = hosttype = mipsUltrix endif # Note: # If you are trying to build on Linux on an x86 # try something like this, substituting whatever # uname -s returns on your machine for the XXX # ifeq ($(osname),Linux) HOSTCFLAGS = hosttype = x86Linux endif ifeq ($(osname),CYGWIN_NT-5.1) HOSTCFLAGS = hosttype = x86Linux endif

nachos/coff2noff/coff2noff.o

nachos/coff2noff/Makefile

# Makefile for: # coff2noff -- converts a normal MIPS executable into a Nachos executable # # This is a GNU Makefile. It must be used with the GNU make program. # At UW, the GNU make program is /software/gnu/bin/make. # In many other places it is known as "gmake". # You may wish to include /software/gnu/bin/ early in your command # search path, so that you will be using GNU make when you type "make". # # Use "make" to build the executable(s) # Use "make clean" to remove .o files # Use "make distclean" to remove all files produced by make, including # the executable # # # Copyright (c) 1992-1996 The Regents of the University of California. # All rights reserved. See copyright.h for copyright notice and limitation # of liability and disclaimer of warranty provisions. # # This file has been modified for use at Waterloo # ############################################################################# # Makefile.dep contains all machine-dependent definitions # If you are trying to build coff2noff somewhere outside # of the MFCF environment, you will almost certainly want # to visit and edit Makefile.dep before doing so ############################################################################# include Makefile.dep CC=gcc CFLAGS= $(HOSTCFLAGS) -DRDATA -m32 LD=gcc -m32 RM = /bin/rm MV = /bin/mv ifeq ($(hosttype),unknown) buildtargets = unknownhost else buildtargets = coff2noff.$(hosttype) endif all: $(buildtargets) # converts a COFF file to Nachos object format coff2noff.$(hosttype): coff2noff.o $(LD) coff2noff.o -o coff2noff.$(hosttype) strip coff2noff.$(hosttype) clean: $(RM) -f coff2noff.o distclean: clean $(MV) coff2noff.c temp.c $(RM) -f coff2noff.* $(MV) temp.c coff2noff.c unknownhost: @echo Host type could not be determined. @echo make is terminating @echo If you are on an MFCF machine, contact the instructor @echo to report this problem @echo Otherwise, edit Makefile.dep and try again.

nachos/coff2noff/coff2noff.c

/* coff2noff.c * * This program reads in a COFF format file, and outputs a NOFF format file. * The NOFF format is essentially just a simpler version of the COFF file, * recording where each segment is in the NOFF file, and where it is to * go in the virtual address space. * * Assumes coff file is linked with either * gld with -N -Ttext 0 * ld with -N -T 0 * to make sure the object file has no shared text. * * Also assumes that the COFF file has at most 3 segments: * .text -- read-only executable instructions * .data -- initialized data * .bss/.sbss -- uninitialized data (should be zero'd on program startup) #ifdef RDATA * .rdata -- read-only data (e.g., string literals). * mark this segment readonly to prevent it from being modified #endif * * * Copyright (c) 1992-1993 The Regents of the University of California. * All rights reserved. See copyright.h for copyright notice and limitation * of liability and disclaimer of warranty provisions. */ /* * Modified at UW by KMS, August, 1997 * The modified program always writes the NOFF header in little-endian * format, rather than host format. This is to avoid the problem * that user programs run through coff2noff on a big-endian host * would not run properly on Nachos machines running on little-endian * hosts. * * Note that the Nachos address space loading code * (in AddrSpace::Load) on big-endian hosts converts the header * to big-endian format when it is read in. * Thus, the little-endian header NOFF * header should work OK whether Nachos is running on a little-endian * host or a big-endian host. */ #define MAIN #include "copyright.h" #undef MAIN #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <limits.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include "coff.h" #include "noff.h" /****************************************************************/ /* Routines for converting words and short words to and from the * simulated machine's format of little endian. These end up * being NOPs when the host machine is little endian. */ unsigned int WordToHost(unsigned int word) { #ifdef HOST_IS_BIG_ENDIAN register unsigned long result; result = (word >> 24) & 0x000000ff; result |= (word >> 8) & 0x0000ff00; result |= (word << 8) & 0x00ff0000; result |= (word << 24) & 0xff000000; return result; #else return word; #endif /* HOST_IS_BIG_ENDIAN */ } unsigned short ShortToHost(unsigned short shortword) { #if HOST_IS_BIG_ENDIAN register unsigned short result; result = (shortword << 8) & 0xff00; result |= (shortword >> 8) & 0x00ff; return result; #else return shortword; #endif /* HOST_IS_BIG_ENDIAN */ } unsigned int WordToMachine(unsigned int word) { return WordToHost(word); } unsigned short ShortToMachine(unsigned short shortword) { return ShortToHost(shortword); } // this routine was borrowed from userprog/addrspace.cc // on a big-endian machine, it converts all fields of // the NOFF header to little-endian format // on a little-endian machine, where the header is already // in little-endian format, it does nothing static void SwapHeader (NoffHeader *noffH) { noffH->noffMagic = WordToHost(noffH->noffMagic); noffH->code.size = WordToHost(noffH->code.size); noffH->code.virtualAddr = WordToHost(noffH->code.virtualAddr); noffH->code.inFileAddr = WordToHost(noffH->code.inFileAddr); #ifdef RDATA noffH->readonlyData.size = WordToHost(noffH->readonlyData.size); noffH->readonlyData.virtualAddr = WordToHost(noffH->readonlyData.virtualAddr); noffH->readonlyData.inFileAddr = WordToHost(noffH->readonlyData.inFileAddr); #endif noffH->initData.size = WordToHost(noffH->initData.size); noffH->initData.virtualAddr = WordToHost(noffH->initData.virtualAddr); noffH->initData.inFileAddr = WordToHost(noffH->initData.inFileAddr); noffH->uninitData.size = WordToHost(noffH->uninitData.size); noffH->uninitData.virtualAddr = WordToHost(noffH->uninitData.virtualAddr); noffH->uninitData.inFileAddr = WordToHost(noffH->uninitData.inFileAddr); } /****************************************************************/ #define ReadStruct(f,s) Read(f,(char *)&s,sizeof(s)) char *noffFileName = NULL; /* read and check for error */ void Read(int fd, char *buf, int nBytes) { if (read(fd, buf, nBytes) != nBytes) { fprintf(stderr, "File is too short\n"); unlink(noffFileName); exit(1); } } /* write and check for error */ void Write(int fd, char *buf, int nBytes) { if (write(fd, buf, nBytes) != nBytes) { fprintf(stderr, "Unable to write file\n"); unlink(noffFileName); exit(1); } } int main(int argc, char **argv) { int fdIn, fdOut, numsections, i, inNoffFile; struct filehdr fileh; struct aouthdr systemh; struct scnhdr *sections; char *buffer; NoffHeader noffH; if (argc < 2) { fprintf(stderr, "Usage: %s <coffFileName> <noffFileName>\n", argv[0]); exit(1); } /* open the COFF file (input) */ fdIn = open(argv[1], O_RDONLY, 0); if (fdIn == -1) { perror(argv[1]); exit(1); } /* open the NOFF file (output) */ fdOut = open(argv[2], O_WRONLY|O_CREAT|O_TRUNC , 0666); if (fdIn == -1) { perror(argv[2]); exit(1); } noffFileName = argv[2]; /* Read in the file header and check the magic number. */ ReadStruct(fdIn,fileh); fileh.f_magic = ShortToHost(fileh.f_magic); fileh.f_nscns = ShortToHost(fileh.f_nscns); if (fileh.f_magic != MIPSELMAGIC) { fprintf(stderr, "File is not a MIPSEL COFF file\n"); unlink(noffFileName); exit(1); } /* Read in the system header and check the magic number */ ReadStruct(fdIn,systemh); systemh.magic = ShortToHost(systemh.magic); if (systemh.magic != OMAGIC) { fprintf(stderr, "File is not a OMAGIC file\n"); unlink(noffFileName); exit(1); } /* Read in the section headers. */ numsections = fileh.f_nscns; printf("numsections %d \n",numsections); sections = (struct scnhdr *)malloc(numsections * sizeof(struct scnhdr)); Read(fdIn, (char *) sections, numsections * sizeof(struct scnhdr)); for (i = 0; i < numsections; i++) { sections[i].s_paddr = WordToHost(sections[i].s_paddr); sections[i].s_size = WordToHost(sections[i].s_size); sections[i].s_scnptr = WordToHost(sections[i].s_scnptr); } /* initialize the NOFF header, in case not all the segments are defined * in the COFF file */ noffH.noffMagic = NOFFMAGIC; noffH.code.size = 0; noffH.initData.size = 0; noffH.uninitData.size = 0; #ifdef RDATA noffH.readonlyData.size = 0; #endif /* Copy the segments in */ inNoffFile = sizeof(NoffHeader); lseek(fdOut, inNoffFile, 0); printf("Loading %d sections:\n", numsections); for (i = 0; i < numsections; i++) { printf("\t\"%s\", filepos 0x%x, mempos 0x%x, size 0x%x\n", sections[i].s_name, (unsigned int)sections[i].s_scnptr, (unsigned int)sections[i].s_paddr, (unsigned int)sections[i].s_size); if (sections[i].s_size == 0) { /* do nothing! */ } else if (!strcmp(sections[i].s_name, ".text")) { noffH.code.virtualAddr = sections[i].s_paddr; noffH.code.inFileAddr = inNoffFile; noffH.code.size = sections[i].s_size; lseek(fdIn, sections[i].s_scnptr, 0); buffer = malloc(sections[i].s_size); Read(fdIn, buffer, sections[i].s_size); Write(fdOut, buffer, sections[i].s_size); free(buffer); inNoffFile += sections[i].s_size; } else if (!strcmp(sections[i].s_name, ".data")){ noffH.initData.virtualAddr = sections[i].s_paddr; noffH.initData.inFileAddr = inNoffFile; noffH.initData.size = sections[i].s_size; lseek(fdIn, sections[i].s_scnptr, 0); buffer = malloc(sections[i].s_size); Read(fdIn, buffer, sections[i].s_size); Write(fdOut, buffer, sections[i].s_size); free(buffer); inNoffFile += sections[i].s_size; #ifdef RDATA } else if (!strcmp(sections[i].s_name, ".rdata")){ noffH.readonlyData.virtualAddr = sections[i].s_paddr; noffH.readonlyData.inFileAddr = inNoffFile; noffH.readonlyData.size = sections[i].s_size; lseek(fdIn, sections[i].s_scnptr, 0); buffer = malloc(sections[i].s_size); Read(fdIn, buffer, sections[i].s_size); Write(fdOut, buffer, sections[i].s_size); free(buffer); inNoffFile += sections[i].s_size; #endif } else if (!strcmp(sections[i].s_name, ".bss")){ /* need to check if we have both .bss and .sbss -- make sure they * are contiguous */ if (noffH.uninitData.size != 0) { if (sections[i].s_paddr == (noffH.uninitData.virtualAddr + noffH.uninitData.size)) { fprintf(stderr, "Can't handle both bss and sbss\n"); unlink(noffFileName); exit(1); } noffH.uninitData.size += sections[i].s_size; } else { noffH.uninitData.virtualAddr = sections[i].s_paddr; noffH.uninitData.size = sections[i].s_size; } /* we don't need to copy the uninitialized data! */ } else { fprintf(stderr, "Unknown segment type: %s\n", sections[i].s_name); unlink(noffFileName); exit(1); } } lseek(fdOut, 0, 0); // convert the NOFF header to little-endian before // writing it to the file SwapHeader(&noffH); Write(fdOut, (char *)&noffH, sizeof(NoffHeader)); close(fdIn); close(fdOut); exit(0); }

nachos/coff2noff/coff.h

/* coff.h * Data structures that describe the MIPS COFF format. */ struct filehdr { unsigned short f_magic; /* magic number */ unsigned short f_nscns; /* number of sections */ long f_timdat; /* time & date stamp */ long f_symptr; /* file pointer to symbolic header */ long f_nsyms; /* sizeof(symbolic hdr) */ unsigned short f_opthdr; /* sizeof(optional hdr) */ unsigned short f_flags; /* flags */ }; #define MIPSELMAGIC 0x0162 #define OMAGIC 0407 #define SOMAGIC 0x0701 typedef struct aouthdr { short magic; /* see above */ short vstamp; /* version stamp */ long tsize; /* text size in bytes, padded to DW bdry*/ long dsize; /* initialized data " " */ long bsize; /* uninitialized data " " */ long entry; /* entry pt. */ long text_start; /* base of text used for this file */ long data_start; /* base of data used for this file */ long bss_start; /* base of bss used for this file */ long gprmask; /* general purpose register mask */ long cprmask[4]; /* co-processor register masks */ long gp_value; /* the gp value used for this object */ } AOUTHDR; #define AOUTHSZ sizeof(AOUTHDR) struct scnhdr { char s_name[8]; /* section name */ long s_paddr; /* physical address, aliased s_nlib */ long s_vaddr; /* virtual address */ long s_size; /* section size */ long s_scnptr; /* file ptr to raw data for section */ long s_relptr; /* file ptr to relocation */ long s_lnnoptr; /* file ptr to gp histogram */ unsigned short s_nreloc; /* number of relocation entries */ unsigned short s_nlnno; /* number of gp histogram entries */ long s_flags; /* flags */ };

nachos/code/README

Building Instructions: * got to the directory build.<host>, where <host> is your working OS * do a "make depend" to build depenencies (DO IT!) * do a "make" to build NachOS Usage: see "nachos -u" for all command line options Building and starting user-level programs in NachOS: * use Mips cross-compiler to build and link coff-binaries * use coff2noff to translate the binaries to the NachOS-format * start binary with nachos -x <path_to_file/file>

nachos/code/build.cygwin/Makefile.dep

################################################################## # Machine Dependencies - this file is included automatically # into the main Makefile # # This file contains definitions below for x86 running Linux # It has *not* been tested! ################################################################## HOSTCFLAGS = -Dx86 -DLINUX -DCYGWIN #----------------------------------------------------------------- # Do not put anything below this point - it will be destroyed by # "make depend" # # DO NOT DELETE THIS LINE -- make depend uses it # DEPENDENCIES MUST END AT END OF FILE bitmap.o: ../lib/bitmap.cc ../lib/copyright.h ../lib/debug.h \ ../lib/utility.h ../lib/sysdep.h /usr/include/g++-3/iostream.h \ /usr/include/g++-3/streambuf.h /usr/include/g++-3/libio.h \ /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h ../lib/bitmap.h debug.o: ../lib/debug.cc ../lib/copyright.h ../lib/utility.h \ ../lib/debug.h ../lib/sysdep.h /usr/include/g++-3/iostream.h \ /usr/include/g++-3/streambuf.h /usr/include/g++-3/libio.h \ /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h hash.o: ../lib/hash.cc ../lib/copyright.h libtest.o: ../lib/libtest.cc ../lib/copyright.h ../lib/libtest.h \ ../lib/bitmap.h ../lib/utility.h ../lib/list.h ../lib/debug.h \ ../lib/sysdep.h /usr/include/g++-3/iostream.h \ /usr/include/g++-3/streambuf.h /usr/include/g++-3/libio.h \ /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h ../lib/list.cc ../lib/hash.h ../lib/hash.cc list.o: ../lib/list.cc ../lib/copyright.h sysdep.o: ../lib/sysdep.cc ../lib/copyright.h ../lib/debug.h \ ../lib/utility.h ../lib/sysdep.h /usr/include/g++-3/iostream.h \ /usr/include/g++-3/streambuf.h /usr/include/g++-3/libio.h \ /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h /usr/include/unistd.h /usr/include/sys/unistd.h \ /usr/include/getopt.h /usr/include/sys/time.h \ /usr/include/sys/select.h /usr/include/time.h \ /usr/include/machine/time.h /usr/include/sys/file.h \ /usr/include/fcntl.h /usr/include/sys/fcntl.h /usr/include/sys/stat.h \ /usr/include/cygwin/stat.h /usr/include/sys/socket.h \ /usr/include/features.h /usr/include/cygwin/socket.h \ /usr/include/asm/socket.h /usr/include/cygwin/if.h \ /usr/include/cygwin/sockios.h /usr/include/cygwin/uio.h \ /usr/include/sys/un.h /usr/include/signal.h /usr/include/sys/signal.h interrupt.o: ../machine/interrupt.cc ../lib/copyright.h \ ../machine/interrupt.h ../lib/list.h ../lib/debug.h ../lib/utility.h \ ../lib/sysdep.h /usr/include/g++-3/iostream.h \ /usr/include/g++-3/streambuf.h /usr/include/g++-3/libio.h \ /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h ../lib/list.cc ../machine/callback.h \ ../threads/main.h ../threads/kernel.h ../threads/thread.h \ ../machine/machine.h ../machine/translate.h ../userprog/addrspace.h \ ../filesys/filesys.h ../filesys/openfile.h ../threads/scheduler.h \ ../machine/stats.h ../threads/alarm.h ../machine/timer.h stats.o: ../machine/stats.cc ../lib/copyright.h ../lib/debug.h \ ../lib/utility.h ../lib/sysdep.h /usr/include/g++-3/iostream.h \ /usr/include/g++-3/streambuf.h /usr/include/g++-3/libio.h \ /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h ../machine/stats.h timer.o: ../machine/timer.cc ../lib/copyright.h ../machine/timer.h \ ../lib/utility.h ../machine/callback.h ../threads/main.h \ ../lib/debug.h ../lib/sysdep.h /usr/include/g++-3/iostream.h \ /usr/include/g++-3/streambuf.h /usr/include/g++-3/libio.h \ /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h ../threads/kernel.h ../threads/thread.h \ ../machine/machine.h ../machine/translate.h ../userprog/addrspace.h \ ../filesys/filesys.h ../filesys/openfile.h ../threads/scheduler.h \ ../lib/list.h ../lib/list.cc ../machine/interrupt.h \ ../machine/stats.h ../threads/alarm.h console.o: ../machine/console.cc ../lib/copyright.h \ ../machine/console.h ../lib/utility.h ../machine/callback.h \ ../threads/main.h ../lib/debug.h ../lib/sysdep.h \ /usr/include/g++-3/iostream.h /usr/include/g++-3/streambuf.h \ /usr/include/g++-3/libio.h /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h ../threads/kernel.h ../threads/thread.h \ ../machine/machine.h ../machine/translate.h ../userprog/addrspace.h \ ../filesys/filesys.h ../filesys/openfile.h ../threads/scheduler.h \ ../lib/list.h ../lib/list.cc ../machine/interrupt.h \ ../machine/stats.h ../threads/alarm.h ../machine/timer.h machine.o: ../machine/machine.cc ../lib/copyright.h \ ../machine/machine.h ../lib/utility.h ../machine/translate.h \ ../threads/main.h ../lib/debug.h ../lib/sysdep.h \ /usr/include/g++-3/iostream.h /usr/include/g++-3/streambuf.h \ /usr/include/g++-3/libio.h /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h ../threads/kernel.h ../threads/thread.h \ ../userprog/addrspace.h ../filesys/filesys.h ../filesys/openfile.h \ ../threads/scheduler.h ../lib/list.h ../lib/list.cc \ ../machine/interrupt.h ../machine/callback.h ../machine/stats.h \ ../threads/alarm.h ../machine/timer.h mipssim.o: ../machine/mipssim.cc ../lib/copyright.h ../lib/debug.h \ ../lib/utility.h ../lib/sysdep.h /usr/include/g++-3/iostream.h \ /usr/include/g++-3/streambuf.h /usr/include/g++-3/libio.h \ /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h ../machine/machine.h ../machine/translate.h \ ../machine/mipssim.h ../threads/main.h ../threads/kernel.h \ ../threads/thread.h ../userprog/addrspace.h ../filesys/filesys.h \ ../filesys/openfile.h ../threads/scheduler.h ../lib/list.h \ ../lib/list.cc ../machine/interrupt.h ../machine/callback.h \ ../machine/stats.h ../threads/alarm.h ../machine/timer.h translate.o: ../machine/translate.cc ../lib/copyright.h \ ../threads/main.h ../lib/debug.h ../lib/utility.h ../lib/sysdep.h \ /usr/include/g++-3/iostream.h /usr/include/g++-3/streambuf.h \ /usr/include/g++-3/libio.h /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h ../threads/kernel.h ../threads/thread.h \ ../machine/machine.h ../machine/translate.h ../userprog/addrspace.h \ ../filesys/filesys.h ../filesys/openfile.h ../threads/scheduler.h \ ../lib/list.h ../lib/list.cc ../machine/interrupt.h \ ../machine/callback.h ../machine/stats.h ../threads/alarm.h \ ../machine/timer.h network.o: ../machine/network.cc ../lib/copyright.h \ ../machine/network.h ../lib/utility.h ../machine/callback.h \ ../threads/main.h ../lib/debug.h ../lib/sysdep.h \ /usr/include/g++-3/iostream.h /usr/include/g++-3/streambuf.h \ /usr/include/g++-3/libio.h /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h ../threads/kernel.h ../threads/thread.h \ ../machine/machine.h ../machine/translate.h ../userprog/addrspace.h \ ../filesys/filesys.h ../filesys/openfile.h ../threads/scheduler.h \ ../lib/list.h ../lib/list.cc ../machine/interrupt.h \ ../machine/stats.h ../threads/alarm.h ../machine/timer.h disk.o: ../machine/disk.cc ../lib/copyright.h ../machine/disk.h \ ../lib/utility.h ../machine/callback.h ../lib/debug.h ../lib/sysdep.h \ /usr/include/g++-3/iostream.h /usr/include/g++-3/streambuf.h \ /usr/include/g++-3/libio.h /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h ../threads/main.h ../threads/kernel.h \ ../threads/thread.h ../machine/machine.h ../machine/translate.h \ ../userprog/addrspace.h ../filesys/filesys.h ../filesys/openfile.h \ ../threads/scheduler.h ../lib/list.h ../lib/list.cc \ ../machine/interrupt.h ../machine/stats.h ../threads/alarm.h \ ../machine/timer.h alarm.o: ../threads/alarm.cc ../lib/copyright.h ../threads/alarm.h \ ../lib/utility.h ../machine/callback.h ../machine/timer.h \ ../threads/main.h ../lib/debug.h ../lib/sysdep.h \ /usr/include/g++-3/iostream.h /usr/include/g++-3/streambuf.h \ /usr/include/g++-3/libio.h /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h ../threads/kernel.h ../threads/thread.h \ ../machine/machine.h ../machine/translate.h ../userprog/addrspace.h \ ../filesys/filesys.h ../filesys/openfile.h ../threads/scheduler.h \ ../lib/list.h ../lib/list.cc ../machine/interrupt.h \ ../machine/stats.h kernel.o: ../threads/kernel.cc ../lib/copyright.h ../lib/debug.h \ ../lib/utility.h ../lib/sysdep.h /usr/include/g++-3/iostream.h \ /usr/include/g++-3/streambuf.h /usr/include/g++-3/libio.h \ /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h ../threads/main.h ../threads/kernel.h \ ../threads/thread.h ../machine/machine.h ../machine/translate.h \ ../userprog/addrspace.h ../filesys/filesys.h ../filesys/openfile.h \ ../threads/scheduler.h ../lib/list.h ../lib/list.cc \ ../machine/interrupt.h ../machine/callback.h ../machine/stats.h \ ../threads/alarm.h ../machine/timer.h ../threads/synch.h \ ../threads/synchlist.h ../threads/synchlist.cc ../lib/libtest.h \ ../userprog/synchconsole.h ../machine/console.h \ ../filesys/synchdisk.h ../machine/disk.h ../network/post.h \ ../machine/network.h main.o: ../threads/main.cc ../lib/copyright.h ../threads/main.h \ ../lib/debug.h ../lib/utility.h ../lib/sysdep.h \ /usr/include/g++-3/iostream.h /usr/include/g++-3/streambuf.h \ /usr/include/g++-3/libio.h /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h ../threads/kernel.h ../threads/thread.h \ ../machine/machine.h ../machine/translate.h ../userprog/addrspace.h \ ../filesys/filesys.h ../filesys/openfile.h ../threads/scheduler.h \ ../lib/list.h ../lib/list.cc ../machine/interrupt.h \ ../machine/callback.h ../machine/stats.h ../threads/alarm.h \ ../machine/timer.h scheduler.o: ../threads/scheduler.cc ../lib/copyright.h ../lib/debug.h \ ../lib/utility.h ../lib/sysdep.h /usr/include/g++-3/iostream.h \ /usr/include/g++-3/streambuf.h /usr/include/g++-3/libio.h \ /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h ../threads/scheduler.h ../lib/list.h \ ../lib/list.cc ../threads/thread.h ../machine/machine.h \ ../machine/translate.h ../userprog/addrspace.h ../filesys/filesys.h \ ../filesys/openfile.h ../threads/main.h ../threads/kernel.h \ ../machine/interrupt.h ../machine/callback.h ../machine/stats.h \ ../threads/alarm.h ../machine/timer.h synch.o: ../threads/synch.cc ../lib/copyright.h ../threads/synch.h \ ../threads/thread.h ../lib/utility.h ../lib/sysdep.h \ /usr/include/g++-3/iostream.h /usr/include/g++-3/streambuf.h \ /usr/include/g++-3/libio.h /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h ../machine/machine.h ../machine/translate.h \ ../userprog/addrspace.h ../filesys/filesys.h ../filesys/openfile.h \ ../lib/list.h ../lib/debug.h ../lib/list.cc ../threads/main.h \ ../threads/kernel.h ../threads/scheduler.h ../machine/interrupt.h \ ../machine/callback.h ../machine/stats.h ../threads/alarm.h \ ../machine/timer.h synchlist.o: ../threads/synchlist.cc ../lib/copyright.h \ ../threads/synchlist.h ../lib/list.h ../lib/debug.h ../lib/utility.h \ ../lib/sysdep.h /usr/include/g++-3/iostream.h \ /usr/include/g++-3/streambuf.h /usr/include/g++-3/libio.h \ /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h ../lib/list.cc ../threads/synch.h \ ../threads/thread.h ../machine/machine.h ../machine/translate.h \ ../userprog/addrspace.h ../filesys/filesys.h ../filesys/openfile.h \ ../threads/main.h ../threads/kernel.h ../threads/scheduler.h \ ../machine/interrupt.h ../machine/callback.h ../machine/stats.h \ ../threads/alarm.h ../machine/timer.h ../threads/synchlist.cc thread.o: ../threads/thread.cc ../lib/copyright.h ../threads/thread.h \ ../lib/utility.h ../lib/sysdep.h /usr/include/g++-3/iostream.h \ /usr/include/g++-3/streambuf.h /usr/include/g++-3/libio.h \ /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h ../machine/machine.h ../machine/translate.h \ ../userprog/addrspace.h ../filesys/filesys.h ../filesys/openfile.h \ ../threads/switch.h ../threads/synch.h ../lib/list.h ../lib/debug.h \ ../lib/list.cc ../threads/main.h ../threads/kernel.h \ ../threads/scheduler.h ../machine/interrupt.h ../machine/callback.h \ ../machine/stats.h ../threads/alarm.h ../machine/timer.h addrspace.o: ../userprog/addrspace.cc ../lib/copyright.h \ ../threads/main.h ../lib/debug.h ../lib/utility.h ../lib/sysdep.h \ /usr/include/g++-3/iostream.h /usr/include/g++-3/streambuf.h \ /usr/include/g++-3/libio.h /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h ../threads/kernel.h ../threads/thread.h \ ../machine/machine.h ../machine/translate.h ../userprog/addrspace.h \ ../filesys/filesys.h ../filesys/openfile.h ../threads/scheduler.h \ ../lib/list.h ../lib/list.cc ../machine/interrupt.h \ ../machine/callback.h ../machine/stats.h ../threads/alarm.h \ ../machine/timer.h ../userprog/noff.h exception.o: ../userprog/exception.cc ../lib/copyright.h \ ../threads/main.h ../lib/debug.h ../lib/utility.h ../lib/sysdep.h \ /usr/include/g++-3/iostream.h /usr/include/g++-3/streambuf.h \ /usr/include/g++-3/libio.h /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h ../threads/kernel.h ../threads/thread.h \ ../machine/machine.h ../machine/translate.h ../userprog/addrspace.h \ ../filesys/filesys.h ../filesys/openfile.h ../threads/scheduler.h \ ../lib/list.h ../lib/list.cc ../machine/interrupt.h \ ../machine/callback.h ../machine/stats.h ../threads/alarm.h \ ../machine/timer.h ../userprog/syscall.h ../userprog/errno.h \ ../userprog/ksyscall.h synchconsole.o: ../userprog/synchconsole.cc ../lib/copyright.h \ ../userprog/synchconsole.h ../lib/utility.h ../machine/callback.h \ ../machine/console.h ../threads/synch.h ../threads/thread.h \ ../lib/sysdep.h /usr/include/g++-3/iostream.h \ /usr/include/g++-3/streambuf.h /usr/include/g++-3/libio.h \ /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h ../machine/machine.h ../machine/translate.h \ ../userprog/addrspace.h ../filesys/filesys.h ../filesys/openfile.h \ ../lib/list.h ../lib/debug.h ../lib/list.cc ../threads/main.h \ ../threads/kernel.h ../threads/scheduler.h ../machine/interrupt.h \ ../machine/stats.h ../threads/alarm.h ../machine/timer.h directory.o: ../filesys/directory.cc ../lib/copyright.h \ ../lib/utility.h ../filesys/filehdr.h ../machine/disk.h \ ../machine/callback.h ../filesys/pbitmap.h ../lib/bitmap.h \ ../filesys/openfile.h ../lib/sysdep.h /usr/include/g++-3/iostream.h \ /usr/include/g++-3/streambuf.h /usr/include/g++-3/libio.h \ /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h ../filesys/directory.h filehdr.o: ../filesys/filehdr.cc ../lib/copyright.h \ ../filesys/filehdr.h ../machine/disk.h ../lib/utility.h \ ../machine/callback.h ../filesys/pbitmap.h ../lib/bitmap.h \ ../filesys/openfile.h ../lib/sysdep.h /usr/include/g++-3/iostream.h \ /usr/include/g++-3/streambuf.h /usr/include/g++-3/libio.h \ /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h ../lib/debug.h ../filesys/synchdisk.h \ ../threads/synch.h ../threads/thread.h ../machine/machine.h \ ../machine/translate.h ../userprog/addrspace.h ../filesys/filesys.h \ ../lib/list.h ../lib/list.cc ../threads/main.h ../threads/kernel.h \ ../threads/scheduler.h ../machine/interrupt.h ../machine/stats.h \ ../threads/alarm.h ../machine/timer.h filesys.o: ../filesys/filesys.cc pbitmap.o: ../filesys/pbitmap.cc ../lib/copyright.h \ ../filesys/pbitmap.h ../lib/bitmap.h ../lib/utility.h \ ../filesys/openfile.h ../lib/sysdep.h /usr/include/g++-3/iostream.h \ /usr/include/g++-3/streambuf.h /usr/include/g++-3/libio.h \ /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h openfile.o: ../filesys/openfile.cc synchdisk.o: ../filesys/synchdisk.cc ../lib/copyright.h \ ../filesys/synchdisk.h ../machine/disk.h ../lib/utility.h \ ../machine/callback.h ../threads/synch.h ../threads/thread.h \ ../lib/sysdep.h /usr/include/g++-3/iostream.h \ /usr/include/g++-3/streambuf.h /usr/include/g++-3/libio.h \ /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h ../machine/machine.h ../machine/translate.h \ ../userprog/addrspace.h ../filesys/filesys.h ../filesys/openfile.h \ ../lib/list.h ../lib/debug.h ../lib/list.cc ../threads/main.h \ ../threads/kernel.h ../threads/scheduler.h ../machine/interrupt.h \ ../machine/stats.h ../threads/alarm.h ../machine/timer.h post.o: ../network/post.cc ../lib/copyright.h ../network/post.h \ ../lib/utility.h ../machine/callback.h ../machine/network.h \ ../threads/synchlist.h ../lib/list.h ../lib/debug.h ../lib/sysdep.h \ /usr/include/g++-3/iostream.h /usr/include/g++-3/streambuf.h \ /usr/include/g++-3/libio.h /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h ../lib/list.cc ../threads/synch.h \ ../threads/thread.h ../machine/machine.h ../machine/translate.h \ ../userprog/addrspace.h ../filesys/filesys.h ../filesys/openfile.h \ ../threads/main.h ../threads/kernel.h ../threads/scheduler.h \ ../machine/interrupt.h ../machine/stats.h ../threads/alarm.h \ ../machine/timer.h ../threads/synchlist.cc # DEPENDENCIES MUST END AT END OF FILE # IF YOU PUT STUFF HERE IT WILL GO AWAY # see make depend above

nachos/code/build.cygwin/Makefile

# Copyright (c) 1992-1996 The Regents of the University of California. # All rights reserved. See copyright.h for copyright notice and limitation # of liability and disclaimer of warranty provisions. # # This is a GNU Makefile. It must be used with the GNU make program. # At UW, the GNU make program is /software/gnu/bin/make. # In many other places it is known as "gmake". # You may wish to include /software/gnu/bin/ early in your command # search path, so that you will be using GNU make when you type "make". # # About this Makefile: # -------------------- # # This Makefile is used to build the Nachos system, which includes # the MIPS machine simulation and a simple operating system. # # There is a separate Makefile, in the "test" directory, that is # used to build the Nachos test programs (which run on the # simulated machine). # # There are several "build" directories, one for each type # of machine in the MFCF computing environment # (build.solaris, build.sunos, and build.ultrix), as well # as a build directory for Linux (build.linux) and a generic # build directory (build.other) for those who wish to try # building Nachos on other platforms. # # This Makefile appears to be located in all of the build directories. # If you edit it in one directory, the copies in all of the other # directories appear to change as well. This is the desired behaviour, # since this file is machine independent. (The file actually lives # in build.solaris, with symbolic links from the other build directories.) # # The platform-dependent parts of make's instructions are located # in the file Makefile.dep. # There is a different Makefile.dep in each build directory. # # If you are in the MFCF environment, you should not have to edit # the Makefile.dep files by hand. Any changes to the make instructions # can be made in this file (see the instructions below) - they will # apply no matter where you build Nachos. # If you are not in the MFCF environment, e.g., if you are trying # to build Nachos on Linux at home, you will probably need # to edit Makefile.dep (in the appropriate build directory) to # customize the make procedure to your environment. # # How to build Nachos for the first time: # --------------------------------------- # # (1) Make sure than you are in the build directory for the # type of machine you are logged in to (the "host" machine): # # host type examples build directory # ----------- ----------- ---------------- # # sparc/SunOS cayley,napier, build.sunos # (SunOS 4.1.3) descartes # # sparc/Solaris picard.math, build.solaris # (SunOS 5.x) hermite.math, # markov.math, # hypatia.math, # hume.math # # mips/ULTRIX cantor.math build.ultrix # (ULTRIX 4.2) noether.math # # If you are not sure what type of machine you are on, # try the command "uname -a". # # (2) Type "make depend" # - this computes file dependencies and records them # at the end of the file Makefile.dep in # your build directory. Have a look... # # (3) Type "make nachos" (or just "make"). # - make echos the commands it is executing, so that # you can observe its progress. When the # build is finished, you should have an # executable "nachos" in the build directory. # # (4) There is no 4th step. You are done. Try running "./nachos -u". # # # How to Re-build Nachos after you have changed the code: #-------------------------------------------------------- # # - The Nachos source code is located in the code subdirectories: # threads, userprog, filesys, network, and lib. You may # change the files in any of these directories, and you can # add new files and/or remove files. The "machine" subdirectory # contains the hardware simulation (which is also part of # Nachos. You may look at it, but # you may not change it, except as noted in machine/machine.h # - When you want to re-make Nachos, always do it in the # "build" directory that is appropriate for the machine # type that you are running on. # DO NOT TRY TO MAKE NACHOS IN THE SOURCE CODE DIRECTORIES. # # - IF all you have done is changed C++ code in existing files # (since the last time you made Nachos in this build directory), # THEN all you need to do to re-make Nachos is to type # # "make nachos" # # in the build directory. # # - IF you have done any of the following since the last build in # this directory: # added new .cc files or new .h files # added or deleted #include's from existing files # THEN # you must do # "make depend" # followed by # "make nachos" # # in the build directory. # # Note that is is always safe to do "make depend" followed by # "make nachos", so if you are not sure what changes you have # made, do "make depend". # # - IF you have added new files (.cc or .h) since the last build, # you should edit this Makefile before running "make depend" # and "make nachos". # For new .h files, simply update the appropriate "_H" list below. # For example, if you create a file called # "bigfile.h" in the filesys subdirectory, you should add # "../filesys/bigfile.h" to FILESYS_H, which is defined below # For new .cc files, update the appropriate "_C" and "_O" lists. # For example, if you create a file called "filetable.cc" in # the directory "userprog", you should add # "../userprog/filetable.cc" to USERPROG_C, # and you should add "filetable.o" to USERPROG_O. # Note that the entry in the "_C" list includes the subdirectory # name, while the entry on the "_O" list does not. # # Some Important Notes: # --------------------- # # * You can clean up all of the .o and other files left behind # by make by typeing "make clean" in the build directory. # * You can clean up .o and other files, as well as the nachos # executable, DISK, core, SOCKET, and other files by typing # make "distclean" # # These are good ways to save space, but the next build that # you do after cleaning will take longer than usual, since # much of the stuff you cleaned will need to be rebuilt. # # * When you build Nachos on an ULTRIX machine (in build.ultrix), # you will get lots of warning messages like this: # # openfile.o: does not have gp tables for all it's sectons # # from the loader. Ignore them. Or better yet, figure out # how to make them go away. # # The Most Important Note: # ----------------------- # # * If "make" is behaving strangely and you cannot figure out # why, you should REBUILD the program FROM SCRATCH. # Yes, it is slow. # But, there are lots of little things that can go wrong, especially # with all of these different types of machines available. # Rebuilding from scratch at least gives you a known starting # place. To rebuild from scratch, go to the appropriate # build directory and do: # # make distclean # make depend # make nachos # ################################################################ # READ THIS: CONFIGURING NACHOS # # Change DEFINES (below) to # DEFINES = -DUSE_TLB -DFILESYS_STUB # if you want the simulated machine to use its TLB # # If you want to use the real Nachos file system (based on # the simulated disk), rather than the stub, remove # the -DFILESYS_STUB from DEFINES. # # There is a a fix to the MIPS simulator to enable it to properly # handle unaligned data access. This fix is enabled by the addition # of "-DSIM_FIX" to the DEFINES. This should be enabled by default # and eventually will not require the symbol definition ################################################################ DEFINES = -DFILESYS_STUB -DRDATA -DSIM_FIX ##################################################################### # # You might want to play with the CFLAGS, but if you use -O it may # break the thread system. You might want to use -fno-inline if # you need to call some inline functions from the debugger. CFLAGS = -g -Wall -fwritable-strings $(INCPATH) $(DEFINES) $(HOSTCFLAGS) -DCHANGED LDFLAGS = ##################################################################### CPP= cpp CC = g++ LD = g++ AS = as RM = rm INCPATH = -I../network -I../filesys -I../userprog -I../threads -I../machine -I../lib PROGRAM = nachos # # Edit these lists as if you add files to the source directories. # See the instructions at the top of the file for more information. # LIB_H = ../lib/bitmap.h\ ../lib/copyright.h\ ../lib/debug.h\ ../lib/hash.h\ ../lib/libtest.h\ ../lib/list.h\ ../lib/sysdep.h\ ../lib/utility.h LIB_C = ../lib/bitmap.cc\ ../lib/debug.cc\ ../lib/hash.cc\ ../lib/libtest.cc\ ../lib/list.cc\ ../lib/sysdep.cc LIB_O = bitmap.o debug.o libtest.o sysdep.o MACHINE_H = ../machine/callback.h\ ../machine/interrupt.h\ ../machine/stats.h\ ../machine/timer.h\ ../machine/console.h\ ../machine/machine.h\ ../machine/mipssim.h\ ../machine/translate.h\ ../machine/network.h\ ../machine/disk.h MACHINE_C = ../machine/interrupt.cc\ ../machine/stats.cc\ ../machine/timer.cc\ ../machine/console.cc\ ../machine/machine.cc\ ../machine/mipssim.cc\ ../machine/translate.cc\ ../machine/network.cc\ ../machine/disk.cc MACHINE_O = interrupt.o stats.o timer.o console.o machine.o mipssim.o\ translate.o network.o disk.o THREAD_H = ../threads/alarm.h\ ../threads/kernel.h\ ../threads/main.h\ ../threads/scheduler.h\ ../threads/switch.h\ ../threads/synch.h\ ../threads/synchlist.h\ ../threads/thread.h THREAD_C = ../threads/alarm.cc\ ../threads/kernel.cc\ ../threads/main.cc\ ../threads/scheduler.cc\ ../threads/synch.cc\ ../threads/synchlist.cc\ ../threads/thread.cc THREAD_O = alarm.o kernel.o main.o scheduler.o synch.o thread.o USERPROG_H = ../userprog/addrspace.h\ ../userprog/syscall.h\ ../userprog/synchconsole.h\ ../userprog/noff.h USERPROG_C = ../userprog/addrspace.cc\ ../userprog/exception.cc\ ../userprog/synchconsole.cc USERPROG_O = addrspace.o exception.o synchconsole.o FILESYS_H =../filesys/directory.h \ ../filesys/filehdr.h\ ../filesys/filesys.h \ ../filesys/openfile.h\ ../filesys/pbitmap.h\ ../filesys/synchdisk.h FILESYS_C =../filesys/directory.cc\ ../filesys/filehdr.cc\ ../filesys/filesys.cc\ ../filesys/pbitmap.cc\ ../filesys/openfile.cc\ ../filesys/synchdisk.cc\ FILESYS_O =directory.o filehdr.o filesys.o pbitmap.o openfile.o synchdisk.o NETWORK_H = ../network/post.h NETWORK_C = ../network/post.cc NETWORK_O = post.o ################################################################## # You probably don't want to change anything below this point in # the file unless you are comfortable with GNU make and know what # you are doing... ################################################################## THREAD_S = ../threads/switch.s HFILES = $(LIB_H) $(MACHINE_H) $(THREAD_H) $(USERPROG_H) $(FILESYS_H) $(NETWORK_H) CFILES = $(LIB_C) $(MACHINE_C) $(THREAD_C) $(USERPROG_C) $(FILESYS_C) $(NETWORK_C) C_OFILES = $(LIB_O) $(MACHINE_O) $(THREAD_O) $(USERPROG_O) $(FILESYS_O) $(NETWORK_O) S_OFILES = switch.o OFILES = $(C_OFILES) $(S_OFILES) $(PROGRAM): $(OFILES) $(LD) $(OFILES) $(LDFLAGS) -o $(PROGRAM) $(C_OFILES): %.o: $(CC) $(CFLAGS) -c $< switch.o: ../threads/switch.s $(CPP) $(CPP_AS_FLAGS) -P $(INCPATH) $(HOSTCFLAGS) ../threads/switch.s > swtch.s $(AS) -o switch.o swtch.s depend: $(CFILES) $(HFILES) $(CC) $(INCPATH) $(DEFINES) $(HOSTCFLAGS) -DCHANGED -M $(CFILES) > makedep @echo '/^# DO NOT DELETE THIS LINE/+2,$$d' >eddep @echo '$$r makedep' >>eddep @echo 'w' >>eddep @echo 'q' >>eddep ed - Makefile.dep < eddep rm eddep makedep @echo '# DEPENDENCIES MUST END AT END OF FILE' >> Makefile.dep @echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >> Makefile.dep @echo '# see make depend above' >> Makefile.dep clean: $(RM) -f $(OFILES) $(RM) -f swtch.s $(RM) -f *.s *.ii distclean: clean $(RM) -f $(PROGRAM) $(RM) -f $(PROGRAM).exe $(RM) -f DISK_? $(RM) -f core $(RM) -f SOCKET_? include Makefile.dep

nachos/code/machine/callback.h

// callback.h // Data structure to allow an object to register a "callback". // On an asynchronous operation, the call to start the operation // returns immediately. When the operation completes, the called // object must somehow notify the caller of the completion. // In the general case, the called object doesn't know the type // of the caller. // // We implement this using virtual functions in C++. An object // that needs to register a callback is set up as a derived class of // the abstract base class "CallbackObj". When we pass a // pointer to the object to a lower level module, that module // calls back via "obj->CallBack()", without knowing the // type of the object being called back. // // Note that this isn't a general-purpose mechanism, // because a class can only register a single callback. // // DO NOT CHANGE -- part of the machine emulation // // Copyright (c) 1992-1996 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. // #ifndef CALLBACK_H #define CALLBACK_H #include "copyright.h" // Abstract base class for objects that register callbacks class CallBackObj { public: virtual void CallBack() = 0; protected: CallBackObj() {}; // to prevent anyone from creating // an instance of this class. Only // allow creation of instances of // classes derived from this class. virtual ~CallBackObj() {}; }; #endif

nachos/code/machine/interrupt.cc

nachos/code/machine/interrupt.cc

// interrupt.cc 
//  Routines to simulate hardware interrupts.
//
//  The hardware provides a routine (SetLevel) to enable or disable
//  interrupts.
//
//  In order to emulate the hardware, we need to keep track of all
//  interrupts the hardware devices would cause, and when they
//  are supposed to occur.  
//
//  This module also keeps track of simulated time.  Time advances
//  only when the following occur: 
//      interrupts are re-enabled
//      a user instruction is executed
//      there is nothing in the ready queue
//
//  DO NOT CHANGE -- part of the machine emulation
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include   "copyright.h"
#include   "interrupt.h"
#include   "main.h"

// String definitions for debugging messages

static   char   * intLevelNames []   =   {   "off" ,   "on" };
static   char   * intTypeNames []   =   {   "timer" ,   "disk" ,   "console write" ,  
             "console read" ,   "network send" ,  
             "network recv" };

//----------------------------------------------------------------------
// PendingInterrupt::PendingInterrupt
//  Initialize a hardware device interrupt that is to be scheduled 
//  to occur in the near future.
//
//  "callOnInt" is the object to call when the interrupt occurs
//  "time" is when (in simulated time) the interrupt is to occur
//  "kind" is the hardware device that generated the interrupt
//----------------------------------------------------------------------

PendingInterrupt :: PendingInterrupt ( CallBackObj   * callOnInt ,  
                     int  time ,   IntType  kind )
{
    callOnInterrupt  =  callOnInt ;
    when  =  time ;
    type  =  kind ;
}

//----------------------------------------------------------------------
// PendingCompare
//  Compare to interrupts based on which should occur first.
//----------------------------------------------------------------------

static   int
PendingCompare   ( PendingInterrupt   * x ,   PendingInterrupt   * y )
{
     if   ( x -> when  <  y -> when )   {   return   - 1 ;   }
     else   if   ( x -> when  >  y -> when )   {   return   1 ;   }
     else   {   return   0 ;   }
}

//----------------------------------------------------------------------
// Interrupt::Interrupt
//  Initialize the simulation of hardware device interrupts.
//  
//  Interrupts start disabled, with no interrupts pending, etc.
//----------------------------------------------------------------------

Interrupt :: Interrupt ()
{
    level  =   IntOff ;
    pending  =   new   SortedList < PendingInterrupt   *> ( PendingCompare );
    inHandler  =  FALSE ;
    yieldOnReturn  =  FALSE ;
    status  =   SystemMode ;
}

//----------------------------------------------------------------------
// Interrupt::~Interrupt
//  De-allocate the data structures needed by the interrupt simulation.
//----------------------------------------------------------------------

Interrupt ::~ Interrupt ()
{
     while   ( ! pending -> IsEmpty ())   {
     delete  pending -> RemoveFront ();
     }
     delete  pending ;
}

//----------------------------------------------------------------------
// Interrupt::ChangeLevel
//  Change interrupts to be enabled or disabled, without advancing 
//  the simulated time (normally, enabling interrupts advances the time).
//
//  Used internally.
//
//  "old" -- the old interrupt status
//  "now" -- the new interrupt status
//----------------------------------------------------------------------

void
Interrupt :: ChangeLevel ( IntStatus  old ,   IntStatus  now )
{
    level  =  now ;
    DEBUG ( dbgInt ,   "\tinterrupts: "   <<  intLevelNames [ old ]   <<   " -> "   <<  intLevelNames [ now ]);
}

//----------------------------------------------------------------------
// Interrupt::SetLevel
//  Change interrupts to be enabled or disabled, and if interrupts
//  are being enabled, advance simulated time by calling OneTick().
//
// Returns:
//  The old interrupt status.
// Parameters:
//  "now" -- the new interrupt status
//----------------------------------------------------------------------

IntStatus
Interrupt :: SetLevel ( IntStatus  now )
{
     IntStatus  old  =  level ;
    
     // interrupt handlers are prohibited from enabling interrupts
    ASSERT (( now  ==   IntOff )   ||   ( inHandler  ==  FALSE ));

     ChangeLevel ( old ,  now );            // change to new state
     if   (( now  ==   IntOn )   &&   ( old  ==   IntOff ))   {
     OneTick ();                // advance simulated time
     }
     return  old ;
}

//----------------------------------------------------------------------
// Interrupt::OneTick
//  Advance simulated time and check if there are any pending 
//  interrupts to be called. 
//
//  Two things can cause OneTick to be called:
//      interrupts are re-enabled
//      a user instruction is executed
//----------------------------------------------------------------------
void
Interrupt :: OneTick ()
{
     MachineStatus  oldStatus  =  status ;
     Statistics   * stats  =  kernel -> stats ;

// advance simulated time
     if   ( status  ==   SystemMode )   {
        stats -> totalTicks  +=   SystemTick ;
    stats -> systemTicks  +=   SystemTick ;
     }   else   {
    stats -> totalTicks  +=   UserTick ;
    stats -> userTicks  +=   UserTick ;
     }
    DEBUG ( dbgInt ,   "== Tick "   <<  stats -> totalTicks  <<   " ==" );

// check any pending interrupts are now ready to fire
     ChangeLevel ( IntOn ,   IntOff );   // first, turn off interrupts
                 // (interrupt handlers run with
                 // interrupts disabled)
     CheckIfDue ( FALSE );        // check for pending interrupts
     ChangeLevel ( IntOff ,   IntOn );   // re-enable interrupts
     if   ( yieldOnReturn )   {      // if the timer device handler asked 
                     // for a context switch, ok to do it now
    yieldOnReturn  =  FALSE ;
    status  =   SystemMode ;          // yield is a kernel routine
    kernel -> currentThread -> Yield ();
    status  =  oldStatus ;
     }
}

//----------------------------------------------------------------------
// Interrupt::YieldOnReturn
//  Called from within an interrupt handler, to cause a context switch
//  (for example, on a time slice) in the interrupted thread,
//  when the handler returns.
//
//  We can't do the context switch here, because that would switch
//  out the interrupt handler, and we want to switch out the 
//  interrupted thread.
//----------------------------------------------------------------------

void
Interrupt :: YieldOnReturn ()
{  
    ASSERT ( inHandler  ==  TRUE );   
    yieldOnReturn  =  TRUE ;  
}

//----------------------------------------------------------------------
// Interrupt::Idle
//  Routine called when there is nothing in the ready queue.
//
//  Since something has to be running in order to put a thread
//  on the ready queue, the only thing to do is to advance 
//  simulated time until the next scheduled hardware interrupt.
//
//  If there are no pending interrupts, stop.  There's nothing
//  more for us to do.
//----------------------------------------------------------------------
void
Interrupt :: Idle ()
{
    DEBUG ( dbgInt ,   "Machine idling; checking for interrupts." );
    status  =   IdleMode ;
     if   ( CheckIfDue ( TRUE ))   {   // check for any pending interrupts
    status  =   SystemMode ;
     return ;           // return in case there's now
                 // a runnable thread
     }

     // if there are no pending interrupts, and nothing is on the ready
     // queue, it is time to stop.   If the console or the network is 
     // operating, there are *always* pending interrupts, so this code
     // is not reached.  Instead, the halt must be invoked by the user program.

    DEBUG ( dbgInt ,   "Machine idle.  No interrupts to do." );
    cout  <<   "No threads ready or runnable, and no pending interrupts.\n" ;
    cout  <<   "Assuming the program completed.\n" ;
     Halt ();
}

//----------------------------------------------------------------------
// Interrupt::Halt
//  Shut down Nachos cleanly, printing out performance statistics.
//----------------------------------------------------------------------
void
Interrupt :: Halt ()
{
    cout  <<   "Machine halting!\n\n" ;
    kernel -> stats -> Print ();
     delete  kernel ;    // Never returns.
}

//----------------------------------------------------------------------
// Interrupt::Schedule
//  Arrange for the CPU to be interrupted when simulated time
//  reaches "now + when".
//
//  Implementation: just put it on a sorted list.
//
//  NOTE: the Nachos kernel should not call this routine directly.
//  Instead, it is only called by the hardware device simulators.
//
//  "toCall" is the object to call when the interrupt occurs
//  "fromNow" is how far in the future (in simulated time) the 
//       interrupt is to occur
//  "type" is the hardware device that generated the interrupt
//----------------------------------------------------------------------
void
Interrupt :: Schedule ( CallBackObj   * toCall ,   int  fromNow ,   IntType  type )
{
     int  when  =  kernel -> stats -> totalTicks  +  fromNow ;
     PendingInterrupt   * toOccur  =   new   PendingInterrupt ( toCall ,  when ,  type );

    DEBUG ( dbgInt ,   "Scheduling interrupt handler the "   <<  intTypeNames [ type ]   <<   " at time = "   <<  when );
    ASSERT ( fromNow  >   0 );

    pending -> Insert ( toOccur );
}

//----------------------------------------------------------------------
// Interrupt::CheckIfDue
//  Check if any interrupts are scheduled to occur, and if so, 
//  fire them off.
//
// Returns:
//  TRUE, if we fired off any interrupt handlers
// Params:
//  "advanceClock" -- if TRUE, there is nothing in the ready queue,
//      so we should simply advance the clock to when the next 
//      pending interrupt would occur (if any).
//----------------------------------------------------------------------
bool
Interrupt :: CheckIfDue ( bool  advanceClock )
{
     PendingInterrupt   * next ;
     Statistics   * stats  =  kernel -> stats ;

    ASSERT ( level  ==   IntOff );          // interrupts need to be disabled,
                     // to invoke an interrupt handler
     if   ( debug -> IsEnabled ( dbgInt ))   {
     DumpState ();
     }
     if   ( pending -> IsEmpty ())   {         // no pending interrupts
     return  FALSE ;    
     }        
    next  =  pending -> Front ();
     if   ( next -> when  >  stats -> totalTicks )   {
         if   ( ! advanceClock )   {          // not time yet
             return  FALSE ;
         }
         else   {                // advance the clock to next interrupt
        stats -> idleTicks  +=   ( next -> when  -  stats -> totalTicks );
        stats -> totalTicks  =  next -> when ;
         // UDelay(1000L); // rcgood - to stop nachos from spinning.
     }
     }

    DEBUG ( dbgInt ,   "Invoking interrupt handler for the " );
    DEBUG ( dbgInt ,  intTypeNames [ next -> type ]   <<   " at time "   <<  next -> when );

     if   ( kernel -> machine  !=  NULL )   {
        kernel -> machine -> DelayedLoad ( 0 ,   0 );
     }

    inHandler  =  TRUE ;
     do   {
        next  =  pending -> RemoveFront ();      // pull interrupt off list
        next -> callOnInterrupt -> CallBack (); // call the interrupt handler
     delete  next ;
     }   while   ( ! pending -> IsEmpty ()  
             &&   ( pending -> Front () -> when  <=  stats -> totalTicks ));
    inHandler  =  FALSE ;
     return  TRUE ;
}

//----------------------------------------------------------------------
// PrintPending
//  Print information about an interrupt that is scheduled to occur.
//  When, where, why, etc.
//----------------------------------------------------------------------

static   void
PrintPending   ( PendingInterrupt   * pending )
{
    cout  <<   "Interrupt handler " <<  intTypeNames [ pending -> type ];
    cout  <<   ", scheduled at "   <<  pending -> when ;
}

//----------------------------------------------------------------------
// DumpState
//  Print the complete interrupt state - the status, and all interrupts
//  that are scheduled to occur in the future.
//----------------------------------------------------------------------

void
Interrupt :: DumpState ()
{
    cout  <<   "Time: "   <<  kernel -> stats -> totalTicks ;
    cout  <<   ", interrupts "   <<  intLevelNames [ level ]   <<   "\n" ;
    cout  <<   "Pending interrupts:\n" ;
    pending -> Apply ( PrintPending );
    cout  <<   "\nEnd of pending interrupts\n" ;
}

nachos/code/machine/network.h

// network.h // Data structures to emulate a physical network connection. // The network provides the abstraction of ordered, unreliable, // fixed-size packet delivery to other machines on the network. // // You may note that the interface to the network is similar to // the console device -- both are full duplex channels. // // DO NOT CHANGE -- part of the machine emulation // // Copyright (c) 1992-1996 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef NETWORK_H #define NETWORK_H #include "copyright.h" #include "utility.h" #include "callback.h" // Network address -- uniquely identifies a machine. This machine's ID // is given on the command line. typedef int NetworkAddress; // The following class defines the network packet header. // The packet header is prepended to the data payload by the Network driver, // before the packet is sent over the wire. The format on the wire is: // packet header (PacketHeader) // data (containing MailHeader from the PostOffice!) class PacketHeader { public: NetworkAddress to; // Destination machine ID NetworkAddress from; // source machine ID unsigned length; // bytes of packet data, excluding the // packet header (but including the // MailHeader prepended by the post office) }; #define MaxWireSize 64 // largest packet that can go out on the wire #define MaxPacketSize (MaxWireSize - sizeof(struct PacketHeader)) // data "payload" of the largest packet // The following two classes defines a physical network device. The network // is capable of delivering fixed sized packets, in order but unreliably, // to other machines connected to the network. // // The "reliability" of the network can be specified to the constructor. // This number, between 0 and 1, is the chance that the network will lose // a packet. Note that you can change the seed for the random number // generator, by changing the arguments to RandomInit() in Initialize(). // The random number generator is used to choose which packets to drop. class NetworkInput : public CallBackObj{ public: NetworkInput(CallBackObj *toCall); // Allocate and initialize network input driver ~NetworkInput(); // De-allocate the network input driver data PacketHeader Receive(char* data); // Poll the network for incoming messages. // If there is a packet waiting, copy the // packet into "data" and return the header. // If no packet is waiting, return a header // with length 0. void CallBack(); // A packet may have arrived. private: int sock; // UNIX socket number for incoming packets char sockName[32]; // File name corresponding to UNIX socket CallBackObj *callWhenAvail; // Interrupt handler, signalling packet has // arrived. bool packetAvail; // Packet has arrived, can be pulled off of // network PacketHeader inHdr; // Information about arrived packet char inbox[MaxPacketSize]; // Data for arrived packet }; class NetworkOutput : public CallBackObj { public: NetworkOutput(double reliability, CallBackObj *toCall); // Allocate and initialize network output driver ~NetworkOutput(); // De-allocate the network input driver data void Send(PacketHeader hdr, char* data); // Send the packet data to a remote machine, // specified by "hdr". Returns immediately. // "callWhenDone" is invoked once the next // packet can be sent. Note that callWhenDone // is called whether or not the packet is // dropped, and note that the "from" field of // the PacketHeader is filled in automatically // by Send(). void CallBack(); // Interrupt handler, called when message is // sent private: int sock; // UNIX socket number for outgoing packets double chanceToWork; // Likelihood packet will be dropped CallBackObj *callWhenDone; // Interrupt handler, signalling next packet // can be sent. bool sendBusy; // Packet is being sent. }; #endif // NETWORK_H

nachos/code/machine/mipssim.h

// mipssim.h // Internal data structures for simulating the MIPS instruction set. // // DO NOT CHANGE -- part of the machine emulation // // Copyright (c) 1992-1993 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef MIPSSIM_H #define MIPSSIM_H #include "copyright.h" /* * OpCode values. The names are straight from the MIPS * manual except for the following special ones: * * OP_UNIMP - means that this instruction is legal, but hasn't * been implemented in the simulator yet. * OP_RES - means that this is a reserved opcode (it isn't * supported by the architecture). */ #define OP_ADD 1 #define OP_ADDI 2 #define OP_ADDIU 3 #define OP_ADDU 4 #define OP_AND 5 #define OP_ANDI 6 #define OP_BEQ 7 #define OP_BGEZ 8 #define OP_BGEZAL 9 #define OP_BGTZ 10 #define OP_BLEZ 11 #define OP_BLTZ 12 #define OP_BLTZAL 13 #define OP_BNE 14 #define OP_DIV 16 #define OP_DIVU 17 #define OP_J 18 #define OP_JAL 19 #define OP_JALR 20 #define OP_JR 21 #define OP_LB 22 #define OP_LBU 23 #define OP_LH 24 #define OP_LHU 25 #define OP_LUI 26 #define OP_LW 27 #define OP_LWL 28 #define OP_LWR 29 #define OP_MFHI 31 #define OP_MFLO 32 #define OP_MTHI 34 #define OP_MTLO 35 #define OP_MULT 36 #define OP_MULTU 37 #define OP_NOR 38 #define OP_OR 39 #define OP_ORI 40 #define OP_RFE 41 #define OP_SB 42 #define OP_SH 43 #define OP_SLL 44 #define OP_SLLV 45 #define OP_SLT 46 #define OP_SLTI 47 #define OP_SLTIU 48 #define OP_SLTU 49 #define OP_SRA 50 #define OP_SRAV 51 #define OP_SRL 52 #define OP_SRLV 53 #define OP_SUB 54 #define OP_SUBU 55 #define OP_SW 56 #define OP_SWL 57 #define OP_SWR 58 #define OP_XOR 59 #define OP_XORI 60 #define OP_SYSCALL 61 #define OP_UNIMP 62 #define OP_RES 63 #define MaxOpcode 63 /* * Miscellaneous definitions: */ #define IndexToAddr(x) ((x) << 2) #define SIGN_BIT 0x80000000 #define R31 31 /* * The table below is used to translate bits 31:26 of the instruction * into a value suitable for the "opCode" field of a MemWord structure, * or into a special value for further decoding. */ #define SPECIAL 100 #define BCOND 101 #define IFMT 1 #define JFMT 2 #define RFMT 3 struct OpInfo { int opCode; /* Translated op code. */ int format; /* Format type (IFMT or JFMT or RFMT) */ }; static OpInfo opTable[] = { {SPECIAL, RFMT}, {BCOND, IFMT}, {OP_J, JFMT}, {OP_JAL, JFMT}, {OP_BEQ, IFMT}, {OP_BNE, IFMT}, {OP_BLEZ, IFMT}, {OP_BGTZ, IFMT}, {OP_ADDI, IFMT}, {OP_ADDIU, IFMT}, {OP_SLTI, IFMT}, {OP_SLTIU, IFMT}, {OP_ANDI, IFMT}, {OP_ORI, IFMT}, {OP_XORI, IFMT}, {OP_LUI, IFMT}, {OP_UNIMP, IFMT}, {OP_UNIMP, IFMT}, {OP_UNIMP, IFMT}, {OP_UNIMP, IFMT}, {OP_RES, IFMT}, {OP_RES, IFMT}, {OP_RES, IFMT}, {OP_RES, IFMT}, {OP_RES, IFMT}, {OP_RES, IFMT}, {OP_RES, IFMT}, {OP_RES, IFMT}, {OP_RES, IFMT}, {OP_RES, IFMT}, {OP_RES, IFMT}, {OP_RES, IFMT}, {OP_LB, IFMT}, {OP_LH, IFMT}, {OP_LWL, IFMT}, {OP_LW, IFMT}, {OP_LBU, IFMT}, {OP_LHU, IFMT}, {OP_LWR, IFMT}, {OP_RES, IFMT}, {OP_SB, IFMT}, {OP_SH, IFMT}, {OP_SWL, IFMT}, {OP_SW, IFMT}, {OP_RES, IFMT}, {OP_RES, IFMT}, {OP_SWR, IFMT}, {OP_RES, IFMT}, {OP_UNIMP, IFMT}, {OP_UNIMP, IFMT}, {OP_UNIMP, IFMT}, {OP_UNIMP, IFMT}, {OP_RES, IFMT}, {OP_RES, IFMT}, {OP_RES, IFMT}, {OP_RES, IFMT}, {OP_UNIMP, IFMT}, {OP_UNIMP, IFMT}, {OP_UNIMP, IFMT}, {OP_UNIMP, IFMT}, {OP_RES, IFMT}, {OP_RES, IFMT}, {OP_RES, IFMT}, {OP_RES, IFMT} }; /* * The table below is used to convert the "funct" field of SPECIAL * instructions into the "opCode" field of a MemWord. */ static int specialTable[] = { OP_SLL, OP_RES, OP_SRL, OP_SRA, OP_SLLV, OP_RES, OP_SRLV, OP_SRAV, OP_JR, OP_JALR, OP_RES, OP_RES, OP_SYSCALL, OP_UNIMP, OP_RES, OP_RES, OP_MFHI, OP_MTHI, OP_MFLO, OP_MTLO, OP_RES, OP_RES, OP_RES, OP_RES, OP_MULT, OP_MULTU, OP_DIV, OP_DIVU, OP_RES, OP_RES, OP_RES, OP_RES, OP_ADD, OP_ADDU, OP_SUB, OP_SUBU, OP_AND, OP_OR, OP_XOR, OP_NOR, OP_RES, OP_RES, OP_SLT, OP_SLTU, OP_RES, OP_RES, OP_RES, OP_RES, OP_RES, OP_RES, OP_RES, OP_RES, OP_RES, OP_RES, OP_RES, OP_RES, OP_RES, OP_RES, OP_RES, OP_RES, OP_RES, OP_RES, OP_RES, OP_RES }; // Stuff to help print out each instruction, for debugging enum RegType { NONE, RS, RT, RD, EXTRA }; struct OpString { char *format; // Printed version of instruction RegType args[3]; }; static struct OpString opStrings[] = { {"Shouldn't happen", {NONE, NONE, NONE}}, {"ADD r%d,r%d,r%d", {RD, RS, RT}}, {"ADDI r%d,r%d,%d", {RT, RS, EXTRA}}, {"ADDIU r%d,r%d,%d", {RT, RS, EXTRA}}, {"ADDU r%d,r%d,r%d", {RD, RS, RT}}, {"AND r%d,r%d,r%d", {RD, RS, RT}}, {"ANDI r%d,r%d,%d", {RT, RS, EXTRA}}, {"BEQ r%d,r%d,%d", {RS, RT, EXTRA}}, {"BGEZ r%d,%d", {RS, EXTRA, NONE}}, {"BGEZAL r%d,%d", {RS, EXTRA, NONE}}, {"BGTZ r%d,%d", {RS, EXTRA, NONE}}, {"BLEZ r%d,%d", {RS, EXTRA, NONE}}, {"BLTZ r%d,%d", {RS, EXTRA, NONE}}, {"BLTZAL r%d,%d", {RS, EXTRA, NONE}}, {"BNE r%d,r%d,%d", {RS, RT, EXTRA}}, {"Shouldn't happen", {NONE, NONE, NONE}}, {"DIV r%d,r%d", {RS, RT, NONE}}, {"DIVU r%d,r%d", {RS, RT, NONE}}, {"J %d", {EXTRA, NONE, NONE}}, {"JAL %d", {EXTRA, NONE, NONE}}, {"JALR r%d,r%d", {RD, RS, NONE}}, {"JR r%d,r%d", {RD, RS, NONE}}, {"LB r%d,%d(r%d)", {RT, EXTRA, RS}}, {"LBU r%d,%d(r%d)", {RT, EXTRA, RS}}, {"LH r%d,%d(r%d)", {RT, EXTRA, RS}}, {"LHU r%d,%d(r%d)", {RT, EXTRA, RS}}, {"LUI r%d,%d", {RT, EXTRA, NONE}}, {"LW r%d,%d(r%d)", {RT, EXTRA, RS}}, {"LWL r%d,%d(r%d)", {RT, EXTRA, RS}}, {"LWR r%d,%d(r%d)", {RT, EXTRA, RS}}, {"Shouldn't happen", {NONE, NONE, NONE}}, {"MFHI r%d", {RD, NONE, NONE}}, {"MFLO r%d", {RD, NONE, NONE}}, {"Shouldn't happen", {NONE, NONE, NONE}}, {"MTHI r%d", {RS, NONE, NONE}}, {"MTLO r%d", {RS, NONE, NONE}}, {"MULT r%d,r%d", {RS, RT, NONE}}, {"MULTU r%d,r%d", {RS, RT, NONE}}, {"NOR r%d,r%d,r%d", {RD, RS, RT}}, {"OR r%d,r%d,r%d", {RD, RS, RT}}, {"ORI r%d,r%d,%d", {RT, RS, EXTRA}}, {"RFE", {NONE, NONE, NONE}}, {"SB r%d,%d(r%d)", {RT, EXTRA, RS}}, {"SH r%d,%d(r%d)", {RT, EXTRA, RS}}, {"SLL r%d,r%d,%d", {RD, RT, EXTRA}}, {"SLLV r%d,r%d,r%d", {RD, RT, RS}}, {"SLT r%d,r%d,r%d", {RD, RS, RT}}, {"SLTI r%d,r%d,%d", {RT, RS, EXTRA}}, {"SLTIU r%d,r%d,%d", {RT, RS, EXTRA}}, {"SLTU r%d,r%d,r%d", {RD, RS, RT}}, {"SRA r%d,r%d,%d", {RD, RT, EXTRA}}, {"SRAV r%d,r%d,r%d", {RD, RT, RS}}, {"SRL r%d,r%d,%d", {RD, RT, EXTRA}}, {"SRLV r%d,r%d,r%d", {RD, RT, RS}}, {"SUB r%d,r%d,r%d", {RD, RS, RT}}, {"SUBU r%d,r%d,r%d", {RD, RS, RT}}, {"SW r%d,%d(r%d)", {RT, EXTRA, RS}}, {"SWL r%d,%d(r%d)", {RT, EXTRA, RS}}, {"SWR r%d,%d(r%d)", {RT, EXTRA, RS}}, {"XOR r%d,r%d,r%d", {RD, RS, RT}}, {"XORI r%d,r%d,%d", {RT, RS, EXTRA}}, {"SYSCALL", {NONE, NONE, NONE}}, {"Unimplemented", {NONE, NONE, NONE}}, {"Reserved", {NONE, NONE, NONE}} }; #endif // MIPSSIM_H

nachos/code/machine/timer.h

// timer.h // Data structures to emulate a hardware timer. // // A hardware timer generates a CPU interrupt every X milliseconds. // This means it can be used for implementing time-slicing, or for // having a thread go to sleep for a specific period of time. // // We emulate a hardware timer by scheduling an interrupt to occur // every time stats->totalTicks has increased by TimerTicks. // // In order to introduce some randomness into time-slicing, if "doRandom" // is set, then the interrupt comes after a random number of ticks. // // DO NOT CHANGE -- part of the machine emulation // // Copyright (c) 1992-1996 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef TIMER_H #define TIMER_H #include "copyright.h" #include "utility.h" #include "callback.h" // The following class defines a hardware timer. class Timer : public CallBackObj { public: Timer(bool doRandom, CallBackObj *toCall); // Initialize the timer, and callback to "toCall" // every time slice. virtual ~Timer() {} void Disable() { disable = TRUE; } // Turn timer device off, so it doesn't // generate any more interrupts. private: bool randomize; // set if we need to use a random timeout delay CallBackObj *callPeriodically; // call this every TimerTicks time units bool disable; // turn off the timer device after next // interrupt. void CallBack(); // called internally when the hardware // timer generates an interrupt void SetInterrupt(); // cause an interrupt to occur in the // the future after a fixed or random // delay }; #endif // TIMER_H

nachos/code/machine/machine.cc

nachos/code/machine/machine.cc

// machine.cc 
//  Routines for simulating the execution of user programs.
//
//  DO NOT CHANGE -- part of the machine emulation
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include   "copyright.h"
#include   "machine.h"
#include   "main.h"

// Textual names of the exceptions that can be generated by user program
// execution, for debugging.
static   char *  exceptionNames []   =   {   "no exception" ,   "syscall" ,  
                 "page fault/no TLB entry" ,   "page read only" ,
                 "bus error" ,   "address error" ,   "overflow" ,
                 "illegal instruction"   };

//----------------------------------------------------------------------
// CheckEndian
//  Check to be sure that the host really uses the format it says it 
//  does, for storing the bytes of an integer.  Stop on error.
//----------------------------------------------------------------------

static
void   CheckEndian ()
{
     union  checkit  {
         char  charword [ 4 ];
         unsigned   int  intword ;
     }  check ;

    check . charword [ 0 ]   =   1 ;
    check . charword [ 1 ]   =   2 ;
    check . charword [ 2 ]   =   3 ;
    check . charword [ 3 ]   =   4 ;

#ifdef  HOST_IS_BIG_ENDIAN
    ASSERT  ( check . intword  ==   0x01020304 );
#else
    ASSERT  ( check . intword  ==   0x04030201 );
#endif
}

//----------------------------------------------------------------------
// Machine::Machine
//  Initialize the simulation of user program execution.
//
//  "debug" -- if TRUE, drop into the debugger after each user instruction
//      is executed.
//----------------------------------------------------------------------

Machine :: Machine ( bool  debug )
{
     int  i ;

     for   ( =   0 ;  i  <   NumTotalRegs ;  i ++ )
        registers [ i ]   =   0 ;
    mainMemory  =   new   char [ MemorySize ];
     for   ( =   0 ;  i  <   MemorySize ;  i ++ )
        mainMemory [ i ]   =   0 ;
#ifdef  USE_TLB
    tlb  =   new   TranslationEntry [ TLBSize ];
     for   ( =   0 ;  i  <   TLBSize ;  i ++ )
    tlb [ i ]. valid  =  FALSE ;
    pageTable  =  NULL ;
#else     // use linear page table
    tlb  =  NULL ;
    pageTable  =  NULL ;
#endif

    singleStep  =  debug ;
     CheckEndian ();
}

//----------------------------------------------------------------------
// Machine::~Machine
//  De-allocate the data structures used to simulate user program execution.
//----------------------------------------------------------------------

Machine ::~ Machine ()
{
     delete   []  mainMemory ;
     if   ( tlb  !=  NULL )
         delete   []  tlb ;
}

//----------------------------------------------------------------------
// Machine::RaiseException
//  Transfer control to the Nachos kernel from user mode, because
//  the user program either invoked a system call, or some exception
//  occured (such as the address translation failed).
//
//  "which" -- the cause of the kernel trap
//  "badVaddr" -- the virtual address causing the trap, if appropriate
//----------------------------------------------------------------------

void
Machine :: RaiseException ( ExceptionType  which ,   int  badVAddr )
{
    DEBUG ( dbgMach ,   "Exception: "   <<  exceptionNames [ which ]);
    
    registers [ BadVAddrReg ]   =  badVAddr ;
     DelayedLoad ( 0 ,   0 );            // finish anything in progress
    kernel -> interrupt -> setStatus ( SystemMode );
     ExceptionHandler ( which );          // interrupts are enabled at this point
    kernel -> interrupt -> setStatus ( UserMode );
}

//----------------------------------------------------------------------
// Machine::Debugger
//  Primitive debugger for user programs.  Note that we can't use
//  gdb to debug user programs, since gdb doesn't run on top of Nachos.
//  It could, but you'd have to implement *a lot* more system calls
//  to get it to work!
//
//  So just allow single-stepping, and printing the contents of memory.
//----------------------------------------------------------------------

void   Machine :: Debugger ()
{
     char   * buf  =   new   char [ 80 ];
     int  num ;
     bool  done  =  FALSE ;

    kernel -> interrupt -> DumpState ();
     DumpState ();
     while   ( ! done )   {
       // read commands until we should proceed with more execution
       // prompt for input, giving current simulation time in the prompt
      cout  <<  kernel -> stats -> totalTicks  <<   ">" ;
       // read one line of input (80 chars max)
      cin . get ( buf ,   80 );
       if   ( sscanf ( buf ,   "%d" ,   & num )   ==   1 )   {
    runUntilTime  =  num ;
    done  =  TRUE ;
       }
       else   {
    runUntilTime  =   0 ;
     switch   ( * buf )   {
     case   '\0' :
      done  =  TRUE ;
       break ;
     case   'c' :
      singleStep  =  FALSE ;
      done  =  TRUE ;
       break ;
     case   '?' :
      cout  <<   "Machine commands:\n" ;
      cout  <<   "    <return>  execute one instruction\n" ;
      cout  <<   "    <number>  run until the given timer tick\n" ;
      cout  <<   "    c         run until completion\n" ;
      cout  <<   "    ?         print help message\n" ;
       break ;
     default :
      cout  <<   "Unknown command: "   <<  buf  <<   "\n" ;
      cout  <<   "Type ? for help.\n" ;
     }
       }
       // consume the newline delimiter, which does not get
       // eaten by cin.get(buf,80) above.
      buf [ 0 ]   =  cin . get ();
     }
     delete   []  buf ;
}
 
//----------------------------------------------------------------------
// Machine::DumpState
//  Print the user program's CPU state.  We might print the contents
//  of memory, but that seemed like overkill.
//----------------------------------------------------------------------

void
Machine :: DumpState ()
{
     int  i ;
    
    cout  <<   "Machine registers:\n" ;
     for   ( =   0 ;  i  <   NumGPRegs ;  i ++ )   {
     switch   ( i )   {
       case   StackReg :
        cout  <<   "\tSP("   <<  i  <<   "):\t"   <<  registers [ i ];
         break ;
        
       case   RetAddrReg :
        cout  <<   "\tRA("   <<  i  <<   "):\t"   <<  registers [ i ];
         break ;
      
       default :
        cout  <<   "\t"   <<  i  <<   ":\t"   <<  registers [ i ];
         break ;
     }
     if   (( %   4 )   ==   3 )   {  cout  <<   "\n" ;   }
     }
    
    cout  <<   "\tHi:\t"   <<  registers [ HiReg ];
    cout  <<   "\tLo:\t"   <<  registers [ LoReg ];
    cout  <<   "\tPC:\t"   <<  registers [ PCReg ];
    cout  <<   "\tNextPC:\t"   <<  registers [ NextPCReg ];
    cout  <<   "\tPrevPC:\t"   <<  registers [ PrevPCReg ];
    cout  <<   "\tLoad:\t"   <<  registers [ LoadReg ];
    cout  <<   "\tLoadV:\t"   <<  registers [ LoadValueReg ]   <<   "\n" ;
}

//----------------------------------------------------------------------
// Machine::ReadRegister/WriteRegister
//      Fetch or write the contents of a user program register.
//----------------------------------------------------------------------

int  
Machine :: ReadRegister ( int  num )
{
    ASSERT (( num  >=   0 )   &&   ( num  <   NumTotalRegs ));
     return  registers [ num ];
}

void  
Machine :: WriteRegister ( int  num ,   int   value )
{
    ASSERT (( num  >=   0 )   &&   ( num  <   NumTotalRegs ));
    registers [ num ]   =   value ;
}

nachos/code/machine/interrupt.h

// interrupt.h // Data structures to emulate low-level interrupt hardware. // // The hardware provides a routine (SetLevel) to enable or disable // interrupts. // // In order to emulate the hardware, we need to keep track of all // interrupts the hardware devices would cause, and when they // are supposed to occur. // // This module also keeps track of simulated time. Time advances // only when the following occur: // interrupts are re-enabled // a user instruction is executed // there is nothing in the ready queue // // As a result, unlike real hardware, interrupts (and thus time-slice // context switches) cannot occur anywhere in the code where interrupts // are enabled, but rather only at those places in the code where // simulated time advances (so that it becomes time to invoke an // interrupt in the hardware simulation). // // NOTE: this means that incorrectly synchronized code may work // fine on this hardware simulation (even with randomized time slices), // but it wouldn't work on real hardware. // // DO NOT CHANGE -- part of the machine emulation // // Copyright (c) 1992-1996 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef INTERRUPT_H #define INTERRUPT_H #include "copyright.h" #include "list.h" #include "callback.h" // Interrupts can be disabled (IntOff) or enabled (IntOn) enum IntStatus { IntOff, IntOn }; // Nachos can be running kernel code (SystemMode), user code (UserMode), // or there can be no runnable thread, because the ready list // is empty (IdleMode). enum MachineStatus {IdleMode, SystemMode, UserMode}; // IntType records which hardware device generated an interrupt. // In Nachos, we support a hardware timer device, a disk, a console // display and keyboard, and a network. enum IntType { TimerInt, DiskInt, ConsoleWriteInt, ConsoleReadInt, NetworkSendInt, NetworkRecvInt}; // The following class defines an interrupt that is scheduled // to occur in the future. The internal data structures are // left public to make it simpler to manipulate. class PendingInterrupt { public: PendingInterrupt(CallBackObj *callOnInt, int time, IntType kind); // initialize an interrupt that will // occur in the future CallBackObj *callOnInterrupt;// The object (in the hardware device // emulator) to call when the interrupt occurs int when; // When the interrupt is supposed to fire IntType type; // for debugging }; // The following class defines the data structures for the simulation // of hardware interrupts. We record whether interrupts are enabled // or disabled, and any hardware interrupts that are scheduled to occur // in the future. class Interrupt { public: Interrupt(); // initialize the interrupt simulation ~Interrupt(); // de-allocate data structures IntStatus SetLevel(IntStatus level); // Disable or enable interrupts // and return previous setting. void Enable() { (void) SetLevel(IntOn); } // Enable interrupts. IntStatus getLevel() {return level;} // Return whether interrupts // are enabled or disabled void Idle(); // The ready queue is empty, roll // simulated time forward until the // next interrupt void Halt(); // quit and print out stats void YieldOnReturn(); // cause a context switch on return // from an interrupt handler MachineStatus getStatus() { return status; } void setStatus(MachineStatus st) { status = st; } // idle, kernel, user void DumpState(); // Print interrupt state // NOTE: the following are internal to the hardware simulation code. // DO NOT call these directly. I should make them "private", // but they need to be public since they are called by the // hardware device simulators. void Schedule(CallBackObj *callTo, int when, IntType type); // Schedule an interrupt to occur // at time "when". This is called // by the hardware device simulators. void OneTick(); // Advance simulated time private: IntStatus level; // are interrupts enabled or disabled? SortedList<PendingInterrupt *> *pending; // the list of interrupts scheduled // to occur in the future bool inHandler; // TRUE if we are running an interrupt handler bool yieldOnReturn; // TRUE if we are to context switch // on return from the interrupt handler MachineStatus status; // idle, kernel mode, user mode // these functions are internal to the interrupt simulation code bool CheckIfDue(bool advanceClock); // Check if any interrupts are supposed // to occur now, and if so, do them void ChangeLevel(IntStatus old, // SetLevel, without advancing the IntStatus now); // simulated time }; #endif // INTERRRUPT_H

nachos/code/machine/translate.h

// translate.h // Data structures for managing the translation from // virtual page # -> physical page #, used for managing // physical memory on behalf of user programs. // // The data structures in this file are "dual-use" - they // serve both as a page table entry, and as an entry in // a software-managed translation lookaside buffer (TLB). // Either way, each entry is of the form: // <virtual page #, physical page #>. // // DO NOT CHANGE -- part of the machine emulation // // Copyright (c) 1992-1993 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef TLB_H #define TLB_H #include "copyright.h" #include "utility.h" // The following class defines an entry in a translation table -- either // in a page table or a TLB. Each entry defines a mapping from one // virtual page to one physical page. // In addition, there are some extra bits for access control (valid and // read-only) and some bits for usage information (use and dirty). class TranslationEntry { public: int virtualPage; // The page number in virtual memory. int physicalPage; // The page number in real memory (relative to the // start of "mainMemory" bool valid; // If this bit is set, the translation is ignored. // (In other words, the entry hasn't been initialized.) bool readOnly; // If this bit is set, the user program is not allowed // to modify the contents of the page. bool use; // This bit is set by the hardware every time the // page is referenced or modified. bool dirty; // This bit is set by the hardware every time the // page is modified. }; #endif

nachos/code/machine/console.h

// console.h // Data structures to simulate the behavior of a terminal // I/O device. A terminal has two parts -- a keyboard input, // and a display output, each of which produces/accepts // characters sequentially. // // The console hardware device is asynchronous. When a character is // written to the device, the routine returns immediately, and an // interrupt handler is called later when the I/O completes. // For reads, an interrupt handler is called when a character arrives. // // In either case, the serial line connecting the computer // to the console has limited bandwidth (like a modem!), and so // each character takes measurable time. // // The user of the device registers itself to be called "back" when // the read/write interrupts occur. There is a separate interrupt // for read and write, and the device is "duplex" -- a character // can be outgoing and incoming at the same time. // // DO NOT CHANGE -- part of the machine emulation // // Copyright (c) 1992-1996 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef CONSOLE_H #define CONSOLE_H #include "copyright.h" #include "utility.h" #include "callback.h" // The following two classes define the input (and output) side of a // hardware console device. Input (and output) to the device is simulated // by reading (and writing) to the UNIX file "readFile" (and "writeFile"). // // Since input (and output) to the device is asynchronous, the interrupt // handler "callWhenAvail" is called when a character has arrived to be // read in (and "callWhenDone" is called when an output character has been // "put" so that the next character can be written). // // In practice, usually a single hardware thing that does both // serial input and serial output. But conceptually simpler to // use two objects. class ConsoleInput : public CallBackObj { public: ConsoleInput(char *readFile, CallBackObj *toCall); // initialize hardware console input ~ConsoleInput(); // clean up console emulation char GetChar(); // Poll the console input. If a char is // available, return it. Otherwise, return EOF. // "callWhenAvail" is called whenever there is // a char to be gotten void CallBack(); // Invoked when a character arrives // from the keyboard. private: int readFileNo; // UNIX file emulating the keyboard CallBackObj *callWhenAvail; // Interrupt handler to call when // there is a char to be read char incoming; // Contains the character to be read, // if there is one available. // Otherwise contains EOF. }; class ConsoleOutput : public CallBackObj { public: ConsoleOutput(char *writeFile, CallBackObj *toCall); // initialize hardware console output ~ConsoleOutput(); // clean up console emulation void PutChar(char ch); // Write "ch" to the console display, // and return immediately. "callWhenDone" // will called when the I/O completes. void CallBack(); // Invoked when next character can be put // out to the display. private: int writeFileNo; // UNIX file emulating the display CallBackObj *callWhenDone; // Interrupt handler to call when // the next char can be put bool putBusy; // Is a PutChar operation in progress? // If so, you can't do another one! }; #endif // CONSOLE_H

nachos/code/machine/translate.cc

nachos/code/machine/translate.cc

// translate.cc 
//  Routines to translate virtual addresses to physical addresses.
//  Software sets up a table of legal translations.  We look up
//  in the table on every memory reference to find the true physical
//  memory location.
//
// Two types of translation are supported here.
//
//  Linear page table -- the virtual page # is used as an index
//  into the table, to find the physical page #.
//
//  Translation lookaside buffer -- associative lookup in the table
//  to find an entry with the same virtual page #.  If found,
//  this entry is used for the translation.
//  If not, it traps to software with an exception. 
//
//  In practice, the TLB is much smaller than the amount of physical
//  memory (16 entries is common on a machine that has 1000's of
//  pages).  Thus, there must also be a backup translation scheme
//  (such as page tables), but the hardware doesn't need to know
//  anything at all about that.
//
//  Note that the contents of the TLB are specific to an address space.
//  If the address space changes, so does the contents of the TLB!
//
// DO NOT CHANGE -- part of the machine emulation
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include   "copyright.h"
#include   "main.h"

// Routines for converting Words and Short Words to and from the
// simulated machine's format of little endian.  These end up
// being NOPs when the host machine is also little endian (DEC and Intel).

unsigned   int
WordToHost ( unsigned   int  word )   {
#ifdef  HOST_IS_BIG_ENDIAN
      register   unsigned   long  result ;
     result  =   ( word  >>   24 )   &   0x000000ff ;
     result  |=   ( word  >>   8 )   &   0x0000ff00 ;
     result  |=   ( word  <<   8 )   &   0x00ff0000 ;
     result  |=   ( word  <<   24 )   &   0xff000000 ;
      return  result ;
#else  
      return  word ;
#endif   /* HOST_IS_BIG_ENDIAN */
}

unsigned   short
ShortToHost ( unsigned   short  shortword )   {
#ifdef  HOST_IS_BIG_ENDIAN
      register   unsigned   short  result ;
     result  =   ( shortword  <<   8 )   &   0xff00 ;
     result  |=   ( shortword  >>   8 )   &   0x00ff ;
      return  result ;
#else  
      return  shortword ;
#endif   /* HOST_IS_BIG_ENDIAN */
}

unsigned   int
WordToMachine ( unsigned   int  word )   {   return   WordToHost ( word );   }

unsigned   short
ShortToMachine ( unsigned   short  shortword )   {   return   ShortToHost ( shortword );   }


//----------------------------------------------------------------------
// Machine::ReadMem
//      Read "size" (1, 2, or 4) bytes of virtual memory at "addr" into 
//  the location pointed to by "value".
//
//      Returns FALSE if the translation step from virtual to physical memory
//      failed.
//
//  "addr" -- the virtual address to read from
//  "size" -- the number of bytes to read (1, 2, or 4)
//  "value" -- the place to write the result
//----------------------------------------------------------------------

bool
Machine :: ReadMem ( int  addr ,   int  size ,   int   * value )
{
     int  data ;
     ExceptionType  exception ;
     int  physicalAddress ;
    
    DEBUG ( dbgAddr ,   "Reading VA "   <<  addr  <<   ", size "   <<  size );
    
    exception  =   Translate ( addr ,   & physicalAddress ,  size ,  FALSE );
     if   ( exception  !=   NoException )   {
     RaiseException ( exception ,  addr );
     return  FALSE ;
     }
     switch   ( size )   {
       case   1 :
    data  =  mainMemory [ physicalAddress ];
     * value   =  data ;
     break ;
    
       case   2 :
    data  =   * ( unsigned   short   * )   & mainMemory [ physicalAddress ];
     * value   =   ShortToHost ( data );
     break ;
    
       case   4 :
    data  =   * ( unsigned   int   * )   & mainMemory [ physicalAddress ];
     * value   =   WordToHost ( data );
     break ;

       default :  ASSERT ( FALSE );
     }
    
    DEBUG ( dbgAddr ,   "\tvalue read = "   <<   * value );
     return   ( TRUE );
}

//----------------------------------------------------------------------
// Machine::WriteMem
//      Write "size" (1, 2, or 4) bytes of the contents of "value" into
//  virtual memory at location "addr".
//
//      Returns FALSE if the translation step from virtual to physical memory
//      failed.
//
//  "addr" -- the virtual address to write to
//  "size" -- the number of bytes to be written (1, 2, or 4)
//  "value" -- the data to be written
//----------------------------------------------------------------------

bool
Machine :: WriteMem ( int  addr ,   int  size ,   int   value )
{
     ExceptionType  exception ;
     int  physicalAddress ;
     
    DEBUG ( dbgAddr ,   "Writing VA "   <<  addr  <<   ", size "   <<  size  <<   ", value "   <<   value );

    exception  =   Translate ( addr ,   & physicalAddress ,  size ,  TRUE );
     if   ( exception  !=   NoException )   {
     RaiseException ( exception ,  addr );
     return  FALSE ;
     }
     switch   ( size )   {
       case   1 :
    mainMemory [ physicalAddress ]   =   ( unsigned   char )   ( value   &   0xff );
     break ;

       case   2 :
     * ( unsigned   short   * )   & mainMemory [ physicalAddress ]
         =   ShortToMachine (( unsigned   short )   ( value   &   0xffff ));
     break ;
      
       case   4 :
     * ( unsigned   int   * )   & mainMemory [ physicalAddress ]
         =   WordToMachine (( unsigned   int )   value );
     break ;
    
       default :  ASSERT ( FALSE );
     }
    
     return  TRUE ;
}

//----------------------------------------------------------------------
// Machine::Translate
//  Translate a virtual address into a physical address, using 
//  either a page table or a TLB.  Check for alignment and all sorts 
//  of other errors, and if everything is ok, set the use/dirty bits in 
//  the translation table entry, and store the translated physical 
//  address in "physAddr".  If there was an error, returns the type
//  of the exception.
//
//  "virtAddr" -- the virtual address to translate
//  "physAddr" -- the place to store the physical address
//  "size" -- the amount of memory being read or written
//  "writing" -- if TRUE, check the "read-only" bit in the TLB
//----------------------------------------------------------------------

ExceptionType
Machine :: Translate ( int  virtAddr ,   int *  physAddr ,   int  size ,   bool  writing )
{
     int  i ;
     unsigned   int  vpn ,  offset ;
     TranslationEntry   * entry ;
     unsigned   int  pageFrame ;

    DEBUG ( dbgAddr ,   "\tTranslate "   <<  virtAddr  <<   ( writing  ?   " , write"   :   " , read" ));

// check for alignment errors
     if   ((( size  ==   4 )   &&   ( virtAddr  &   0x3 ))   ||   (( size  ==   2 )   &&   ( virtAddr  &   0x1 ))){
    DEBUG ( dbgAddr ,   "Alignment problem at "   <<  virtAddr  <<   ", size "   <<  size );
     return   AddressErrorException ;
     }
    
     // we must have either a TLB or a page table, but not both!
    ASSERT ( tlb  ==  NULL  ||  pageTable  ==  NULL );    
    ASSERT ( tlb  !=  NULL  ||  pageTable  !=  NULL );    

// calculate the virtual page number, and offset within the page,
// from the virtual address
    vpn  =   ( unsigned )  virtAddr  /   PageSize ;
    offset  =   ( unsigned )  virtAddr  %   PageSize ;
    
     if   ( tlb  ==  NULL )   {        // => page table => vpn is index into table
     if   ( vpn  >=  pageTableSize )   {
        DEBUG ( dbgAddr ,   "Illegal virtual page # "   <<  virtAddr );
         return   AddressErrorException ;
     }   else   if   ( ! pageTable [ vpn ]. valid )   {
        DEBUG ( dbgAddr ,   "Invalid virtual page # "   <<  virtAddr );
         return   PageFaultException ;
     }
    entry  =   & pageTable [ vpn ];
     }   else   {
         for   ( entry  =  NULL ,  i  =   0 ;  i  <   TLBSize ;  i ++ )
             if   ( tlb [ i ]. valid  &&   ( tlb [ i ]. virtualPage  ==   (( int ) vpn )))   {
        entry  =   & tlb [ i ];              // FOUND!
         break ;
         }
     if   ( entry  ==  NULL )   {                  // not found
            DEBUG ( dbgAddr ,   "Invalid TLB entry for this virtual page!" );
             return   PageFaultException ;        // really, this is a TLB fault,
                         // the page may be in memory,
                         // but not in the TLB
     }
     }

     if   ( entry -> readOnly  &&  writing )   {     // trying to write to a read-only page
    DEBUG ( dbgAddr ,   "Write to read-only page at "   <<  virtAddr );
     return   ReadOnlyException ;
     }
    pageFrame  =  entry -> physicalPage ;

     // if the pageFrame is too big, there is something really wrong! 
     // An invalid translation was loaded into the page table or TLB. 
     if   ( pageFrame  >=   NumPhysPages )   {  
    DEBUG ( dbgAddr ,   "Illegal pageframe "   <<  pageFrame );
     return   BusErrorException ;
     }
    entry -> use  =  TRUE ;        // set the use, dirty bits
     if   ( writing )
    entry -> dirty  =  TRUE ;
     * physAddr  =  pageFrame  *   PageSize   +  offset ;
    ASSERT (( * physAddr  >=   0 )   &&   (( * physAddr  +  size )   <=   MemorySize ));
    DEBUG ( dbgAddr ,   "phys addr = "   <<   * physAddr );
     return   NoException ;
}

nachos/code/machine/timer.cc

nachos/code/machine/timer.cc

// timer.cc 
//  Routines to emulate a hardware timer device.
//
//      A hardware timer generates a CPU interrupt every X milliseconds.
//      This means it can be used for implementing time-slicing.
//
//      We emulate a hardware timer by scheduling an interrupt to occur
//      every time stats->totalTicks has increased by TimerTicks.
//
//      In order to introduce some randomness into time-slicing, if "doRandom"
//      is set, then the interrupt is comes after a random number of ticks.
//
//  Remember -- nothing in here is part of Nachos.  It is just
//  an emulation for the hardware that Nachos is running on top of.
//
//  DO NOT CHANGE -- part of the machine emulation
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include   "copyright.h"
#include   "timer.h"
#include   "main.h"
#include   "sysdep.h"

//----------------------------------------------------------------------
// Timer::Timer
//      Initialize a hardware timer device.  Save the place to call
//  on each interrupt, and then arrange for the timer to start
//  generating interrupts.
//
//      "doRandom" -- if true, arrange for the interrupts to occur
//      at random, instead of fixed, intervals.
//      "toCall" is the interrupt handler to call when the timer expires.
//----------------------------------------------------------------------

Timer :: Timer ( bool  doRandom ,   CallBackObj   * toCall )
{
    randomize  =  doRandom ;
    callPeriodically  =  toCall ;
    disable  =  FALSE ;
     SetInterrupt ();
}

//----------------------------------------------------------------------
// Timer::CallBack
//      Routine called when interrupt is generated by the hardware 
//  timer device.  Schedule the next interrupt, and invoke the
//  interrupt handler.
//----------------------------------------------------------------------
void  
Timer :: CallBack ()  
{
     // invoke the Nachos interrupt handler for this device
    callPeriodically -> CallBack ();
    
     SetInterrupt ();   // do last, to let software interrupt handler
                 // decide if it wants to disable future interrupts
}

//----------------------------------------------------------------------
// Timer::SetInterrupt
//      Cause a timer interrupt to occur in the future, unless
//  future interrupts have been disabled.  The delay is either
//  fixed or random.
//----------------------------------------------------------------------

void
Timer :: SetInterrupt ()  
{
     if   ( ! disable )   {
        int  delay  =   TimerTicks ;
    
        if   ( randomize )   {
         delay  =   1   +   ( RandomNumber ()   %   ( TimerTicks   *   2 ));
         }
        // schedule the next timer device interrupt
       kernel -> interrupt -> Schedule ( this ,  delay ,   TimerInt );
     }
}

nachos/code/machine/stats.cc

nachos/code/machine/stats.cc

// stats.h 
//  Routines for managing statistics about Nachos performance.
//
// DO NOT CHANGE -- these stats are maintained by the machine emulation.
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include   "copyright.h"
#include   "debug.h"
#include   "stats.h"

//----------------------------------------------------------------------
// Statistics::Statistics
//  Initialize performance metrics to zero, at system startup.
//----------------------------------------------------------------------

Statistics :: Statistics ()
{
    totalTicks  =  idleTicks  =  systemTicks  =  userTicks  =   0 ;
    numDiskReads  =  numDiskWrites  =   0 ;
    numConsoleCharsRead  =  numConsoleCharsWritten  =   0 ;
    numPageFaults  =  numPacketsSent  =  numPacketsRecvd  =   0 ;
}

//----------------------------------------------------------------------
// Statistics::Print
//  Print performance metrics, when we've finished everything
//  at system shutdown.
//----------------------------------------------------------------------

void
Statistics :: Print ()
{
    cout  <<   "Ticks: total "   <<  totalTicks  <<   ", idle "   <<  idleTicks ;
        cout  <<   ", system "   <<  systemTicks  <<   ", user "   <<  userTicks  << "\n" ;
    cout  <<   "Disk I/O: reads "   <<  numDiskReads ;
        cout  <<   ", writes "   <<  numDiskWrites  <<   "\n" ;
        cout  <<   "Console I/O: reads "   <<  numConsoleCharsRead ;
    cout  <<   ", writes "   <<  numConsoleCharsWritten  <<   "\n" ;
    cout  <<   "Paging: faults "   <<  numPageFaults  <<   "\n" ;
    cout  <<   "Network I/O: packets received "   <<  numPacketsRecvd ;
        cout  <<   ", sent "   <<  numPacketsSent  <<   "\n" ;
}

nachos/code/machine/disk.h

// disk.h // Data structures to emulate a physical disk. A physical disk // can accept (one at a time) requests to read/write a disk sector; // when the request is satisfied, the CPU gets an interrupt, and // the next request can be sent to the disk. // // Disk contents are preserved across machine crashes, but if // a file system operation (eg, create a file) is in progress when the // system shuts down, the file system may be corrupted. // // DO NOT CHANGE -- part of the machine emulation // // Copyright (c) 1992-1993 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef DISK_H #define DISK_H #include "copyright.h" #include "utility.h" #include "callback.h" // The following class defines a physical disk I/O device. The disk // has a single surface, split up into "tracks", and each track split // up into "sectors" (the same number of sectors on each track, and each // sector has the same number of bytes of storage). // // Addressing is by sector number -- each sector on the disk is given // a unique number: track * SectorsPerTrack + offset within a track. // // As with other I/O devices, the raw physical disk is an asynchronous device -- // requests to read or write portions of the disk return immediately, // and an interrupt is invoked later to signal that the operation completed. // // The physical disk is in fact simulated via operations on a UNIX file. // // To make life a little more realistic, the simulated time for // each operation reflects a "track buffer" -- RAM to store the contents // of the current track as the disk head passes by. The idea is that the // disk always transfers to the track buffer, in case that data is requested // later on. This has the benefit of eliminating the need for // "skip-sector" scheduling -- a read request which comes in shortly after // the head has passed the beginning of the sector can be satisfied more // quickly, because its contents are in the track buffer. Most // disks these days now come with a track buffer. // // The track buffer simulation can be disabled by compiling with -DNOTRACKBUF const int SectorSize = 128; // number of bytes per disk sector const int SectorsPerTrack = 32; // number of sectors per disk track const int NumTracks = 32; // number of tracks per disk const int NumSectors = (SectorsPerTrack * NumTracks); // total # of sectors per disk class Disk : public CallBackObj { public: Disk(CallBackObj *toCall); // Create a simulated disk. // Invoke toCall->CallBack() // when each request completes. ~Disk(); // Deallocate the disk. void ReadRequest(int sectorNumber, char* data); // Read/write an single disk sector. // These routines send a request to // the disk and return immediately. // Only one request allowed at a time! void WriteRequest(int sectorNumber, char* data); void CallBack(); // Invoked when disk request // finishes. In turn calls, callWhenDone. int ComputeLatency(int newSector, bool writing); // Return how long a request to // newSector will take: // (seek + rotational delay + transfer) private: int fileno; // UNIX file number for simulated disk char diskname[32]; // name of simulated disk's file CallBackObj *callWhenDone; // Invoke when any disk request finishes bool active; // Is a disk operation in progress? int lastSector; // The previous disk request int bufferInit; // When the track buffer started // being loaded int TimeToSeek(int newSector, int *rotate); // time to get to the new track int ModuloDiff(int to, int from); // # sectors between to and from void UpdateLast(int newSector); }; #endif // DISK_H

nachos/code/machine/network.cc

nachos/code/machine/network.cc

// network.cc 
//  Routines to simulate a network interface, using UNIX sockets
//  to deliver packets between multiple invocations of nachos.
//
//  DO NOT CHANGE -- part of the machine emulation
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include   "copyright.h"
#include   "network.h"
#include   "main.h"

//-----------------------------------------------------------------------
// NetworkInput::NetworkInput
//  Initialize the simulation for the network input
//
//      "toCall" is the interrupt handler to call when packet arrives
//-----------------------------------------------------------------------

NetworkInput :: NetworkInput ( CallBackObj   * toCall )
{
     // set up the stuff to emulate asynchronous interrupts
    callWhenAvail  =  toCall ;
    packetAvail  =  FALSE ;
    inHdr . length  =   0 ;
    
    sock  =   OpenSocket ();
    sprintf ( sockName ,   "SOCKET_%d" ,  kernel -> hostName );
     AssignNameToSocket ( sockName ,  sock );        // Bind socket to a filename 
                          // in the current directory.

     // start polling for incoming packets
    kernel -> interrupt -> Schedule ( this ,   NetworkTime ,   NetworkRecvInt );
}

//-----------------------------------------------------------------------
// NetworkInput::NetworkInput
//  Deallocate the simulation for the network input
//      (basically, deallocate the input mailbox)
//-----------------------------------------------------------------------

NetworkInput ::~ NetworkInput ()
{
     CloseSocket ( sock );
     DeAssignNameToSocket ( sockName );
}

//-----------------------------------------------------------------------
// NetworkInput::CallBack
//  Simulator calls this when a packet may be available to
//  be read in from the simulated network.
//
//      First check to make sure packet is available & there's space to
//  pull it in.  Then invoke the "callBack" registered by whoever 
//  wants the packet.
//-----------------------------------------------------------------------

void
NetworkInput :: CallBack ()
{
     // schedule the next time to poll for a packet
    kernel -> interrupt -> Schedule ( this ,   NetworkTime ,   NetworkRecvInt );

     if   ( inHdr . length  !=   0 )    // do nothing if packet is already buffered
     return ;      
     if   ( ! PollSocket ( sock ))    // do nothing if no packet to be read
     return ;

     // otherwise, read packet in
     char   * buffer  =   new   char [ MaxWireSize ];
     ReadFromSocket ( sock ,  buffer ,   MaxWireSize );

     // divide packet into header and data
    inHdr  =   * ( PacketHeader   * ) buffer ;
    ASSERT (( inHdr . to  ==  kernel -> hostName )   &&   ( inHdr . length  <=   MaxPacketSize ));
    bcopy ( buffer  +   sizeof ( PacketHeader ),  inbox ,  inHdr . length );
     delete   []  buffer  ;

    DEBUG ( dbgNet ,   "Network received packet from "   <<  inHdr . from  <<   ", length "   <<  inHdr . length );
    kernel -> stats -> numPacketsRecvd ++ ;

     // tell post office that the packet has arrived
    callWhenAvail -> CallBack ();
}

//-----------------------------------------------------------------------
// NetworkInput::Receive
//  Read a packet, if one is buffered
//-----------------------------------------------------------------------

PacketHeader
NetworkInput :: Receive ( char *  data )
{
     PacketHeader  hdr  =  inHdr ;

    inHdr . length  =   0 ;
     if   ( hdr . length  !=   0 )   {
        bcopy ( inbox ,  data ,  hdr . length );
     }
     return  hdr ;
}

//-----------------------------------------------------------------------
// NetworkOutput::NetworkOutput
//  Initialize the simulation for sending network packets
//
//      "reliability" says whether we drop packets to emulate unreliable links
//      "toCall" is the interrupt handler to call when next packet can be sent
//-----------------------------------------------------------------------

NetworkOutput :: NetworkOutput ( double  reliability ,   CallBackObj   * toCall )
{
     if   ( reliability  <   0 )  chanceToWork  =   0 ;
     else   if   ( reliability  >   1 )  chanceToWork  =   1 ;
     else  chanceToWork  =  reliability ;

     // set up the stuff to emulate asynchronous interrupts
    callWhenDone  =  toCall ;
    sendBusy  =  FALSE ;
    sock  =   OpenSocket ();
}

//-----------------------------------------------------------------------
// NetworkOutput::~NetworkOutput
//  Deallocate the simulation for sending network packets
//-----------------------------------------------------------------------

NetworkOutput ::~ NetworkOutput ()
{
     CloseSocket ( sock );
}

//-----------------------------------------------------------------------
// NetworkOutput::CallBack
//  Called by simulator when another packet can be sent.
//-----------------------------------------------------------------------

void
NetworkOutput :: CallBack ()
{
    sendBusy  =  FALSE ;
    kernel -> stats -> numPacketsSent ++ ;
    callWhenDone -> CallBack ();
}

//-----------------------------------------------------------------------
// NetworkOutput::Send
//  Send a packet into the simulated network, to the destination in hdr.
//  Concatenate hdr and data, and schedule an interrupt to tell the user 
//  when the next packet can be sent 
//
//  Note we always pad out a packet to MaxWireSize before putting it into
//  the socket, because it's simpler at the receive end.
//-----------------------------------------------------------------------

void
NetworkOutput :: Send ( PacketHeader  hdr ,   char *  data )
{
     char  toName [ 32 ];

    sprintf ( toName ,   "SOCKET_%d" ,   ( int ) hdr . to );
    
    ASSERT (( sendBusy  ==  FALSE )   &&   ( hdr . length  >   0 )   &&  
     ( hdr . length  <=   MaxPacketSize )   &&   ( hdr . from  ==  kernel -> hostName ));
    DEBUG ( dbgNet ,   "Sending to addr "   <<  hdr . to  <<   ", length "   <<  hdr . length );

    kernel -> interrupt -> Schedule ( this ,   NetworkTime ,   NetworkSendInt );

     if   ( RandomNumber ()   %   100   >=  chanceToWork  *   100 )   {   // emulate a lost packet
    DEBUG ( dbgNet ,   "oops, lost it!" );
     return ;
     }

     // concatenate hdr and data into a single buffer, and send it out
     char   * buffer  =   new   char [ MaxWireSize ];
     * ( PacketHeader   * ) buffer  =  hdr ;
    bcopy ( data ,  buffer  +   sizeof ( PacketHeader ),  hdr . length );
     SendToSocket ( sock ,  buffer ,   MaxWireSize ,  toName );
     delete   []  buffer ;
}

nachos/code/machine/mipssim.cc

nachos/code/machine/mipssim.cc

// mipssim.cc -- simulate a MIPS R2/3000 processor
//
//   This code has been adapted from Ousterhout's MIPSSIM package.
//   Byte ordering is little-endian, so we can be compatible with
//   DEC RISC systems.
//
//   DO NOT CHANGE -- part of the machine emulation
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

// Simulation fixes done by Peter E Reissner, class of Winter 1994/95 (York)
// I've not been able to test this extensively.
// Ported to newer version of Nachos at Waterloo by Scott Graham (Mar 99).


#include   "copyright.h"

#include   "debug.h"
#include   "machine.h"
#include   "mipssim.h"
#include   "main.h"

static   void   Mult ( int  a ,   int  b ,   bool  signedArith ,   int *  hiPtr ,   int *  loPtr );

// The following class defines an instruction, represented in both
//  undecoded binary form
//      decoded to identify
//      operation to do
//      registers to act on
//      any immediate operand value

class   Instruction   {
   public :
     void   Decode ();    // decode the binary representation of the instruction

     unsigned   int   value ;   // binary representation of the instruction

     char  opCode ;       // Type of instruction.  This is NOT the same as the
                  // opcode field from the instruction: see defs in mips.h
     char  rs ,  rt ,  rd ;   // Three registers from instruction.
     int  extra ;         // Immediate or target or shamt field or offset.
                      // Immediates are sign-extended.
};

//----------------------------------------------------------------------
// Machine::Run
//  Simulate the execution of a user-level program on Nachos.
//  Called by the kernel when the program starts up; never returns.
//
//  This routine is re-entrant, in that it can be called multiple
//  times concurrently -- one for each thread executing user code.
//----------------------------------------------------------------------

void
Machine :: Run ()
{
     Instruction   * instr  =   new   Instruction ;    // storage for decoded instruction

     if   ( debug -> IsEnabled ( 'm' ))   {
        cout  <<   "Starting program in thread: "   <<  kernel -> currentThread -> getName ();
    cout  <<   ", at time: "   <<  kernel -> stats -> totalTicks  <<   "\n" ;
     }
    kernel -> interrupt -> setStatus ( UserMode );
     for   (;;)   {
         OneInstruction ( instr );
    kernel -> interrupt -> OneTick ();
     if   ( singleStep  &&   ( runUntilTime  <=  kernel -> stats -> totalTicks ))
       Debugger ();
     }
}


//----------------------------------------------------------------------
// TypeToReg
//  Retrieve the register # referred to in an instruction. 
//----------------------------------------------------------------------

static   int  
TypeToReg ( RegType  reg ,   Instruction   * instr )
{
     switch   ( reg )   {
       case  RS :
     return  instr -> rs ;
       case  RT :
     return  instr -> rt ;
       case  RD :
     return  instr -> rd ;
       case  EXTRA :
     return  instr -> extra ;
       default :
     return   - 1 ;
     }
}

//----------------------------------------------------------------------
// Machine::OneInstruction
//  Execute one instruction from a user-level program
//
//  If there is any kind of exception or interrupt, we invoke the 
//  exception handler, and when it returns, we return to Run(), which
//  will re-invoke us in a loop.  This allows us to
//  re-start the instruction execution from the beginning, in
//  case any of our state has changed.  On a syscall,
//  the OS software must increment the PC so execution begins
//  at the instruction immediately after the syscall. 
//
//  This routine is re-entrant, in that it can be called multiple
//  times concurrently -- one for each thread executing user code.
//  We get re-entrancy by never caching any data -- we always re-start the
//  simulation from scratch each time we are called (or after trapping
//  back to the Nachos kernel on an exception or interrupt), and we always
//  store all data back to the machine registers and memory before
//  leaving.  This allows the Nachos kernel to control our behavior
//  by controlling the contents of memory, the translation table,
//  and the register set.
//----------------------------------------------------------------------

void
Machine :: OneInstruction ( Instruction   * instr )
{
#ifdef  SIM_FIX
     int  byte ;         // described in Kane for LWL,LWR,...
#endif

     int  raw ;
     int  nextLoadReg  =   0 ;     
     int  nextLoadValue  =   0 ;    // record delayed load operation, to apply
                 // in the future

     // Fetch instruction 
     if   ( ! ReadMem ( registers [ PCReg ],   4 ,   & raw ))
     return ;           // exception occurred
    instr -> value   =  raw ;
    instr -> Decode ();

     if   ( debug -> IsEnabled ( 'm' ))   {
         struct   OpString   * str  =   & opStrings [ instr -> opCode ];
     char  buf [ 80 ];

        ASSERT ( instr -> opCode  <=   MaxOpcode );
        cout  <<   "At PC = "   <<  registers [ PCReg ];
    sprintf ( buf ,  str -> format ,   TypeToReg ( str -> args [ 0 ],  instr ),
          TypeToReg ( str -> args [ 1 ],  instr ),   TypeToReg ( str -> args [ 2 ],  instr ));
        cout  <<   "\t"   <<  buf  <<   "\n" ;
     }
    
     // Compute next pc, but don't install in case there's an error or branch.
     int  pcAfter  =  registers [ NextPCReg ]   +   4 ;
     int  sum ,  diff ,  tmp ,   value ;
     unsigned   int  rs ,  rt ,  imm ;

     // Execute the instruction (cf. Kane's book)
     switch   ( instr -> opCode )   {
    
       case  OP_ADD :
    sum  =  registers [ instr -> rs ]   +  registers [ instr -> rt ];
     if   ( ! (( registers [ instr -> rs ]   ^  registers [ instr -> rt ])   &  SIGN_BIT )   &&
         (( registers [ instr -> rs ]   ^  sum )   &  SIGN_BIT ))   {
         RaiseException ( OverflowException ,   0 );
         return ;
     }
    registers [ instr -> rd ]   =  sum ;
     break ;
    
       case  OP_ADDI :
    sum  =  registers [ instr -> rs ]   +  instr -> extra ;
     if   ( ! (( registers [ instr -> rs ]   ^  instr -> extra )   &  SIGN_BIT )   &&
         (( instr -> extra  ^  sum )   &  SIGN_BIT ))   {
         RaiseException ( OverflowException ,   0 );
         return ;
     }
    registers [ instr -> rt ]   =  sum ;
     break ;
    
       case  OP_ADDIU :
    registers [ instr -> rt ]   =  registers [ instr -> rs ]   +  instr -> extra ;
     break ;
    
       case  OP_ADDU :
    registers [ instr -> rd ]   =  registers [ instr -> rs ]   +  registers [ instr -> rt ];
     break ;
    
       case  OP_AND :
    registers [ instr -> rd ]   =  registers [ instr -> rs ]   &  registers [ instr -> rt ];
     break ;
    
       case  OP_ANDI :
    registers [ instr -> rt ]   =  registers [ instr -> rs ]   &   ( instr -> extra  &   0xffff );
     break ;
    
       case  OP_BEQ :
     if   ( registers [ instr -> rs ]   ==  registers [ instr -> rt ])
        pcAfter  =  registers [ NextPCReg ]   +   IndexToAddr ( instr -> extra );
     break ;
    
       case  OP_BGEZAL :
    registers [ R31 ]   =  registers [ NextPCReg ]   +   4 ;
       case  OP_BGEZ :
     if   ( ! ( registers [ instr -> rs ]   &  SIGN_BIT ))
        pcAfter  =  registers [ NextPCReg ]   +   IndexToAddr ( instr -> extra );
     break ;
    
       case  OP_BGTZ :
     if   ( registers [ instr -> rs ]   >   0 )
        pcAfter  =  registers [ NextPCReg ]   +   IndexToAddr ( instr -> extra );
     break ;
    
       case  OP_BLEZ :
     if   ( registers [ instr -> rs ]   <=   0 )
        pcAfter  =  registers [ NextPCReg ]   +   IndexToAddr ( instr -> extra );
     break ;
    
       case  OP_BLTZAL :
    registers [ R31 ]   =  registers [ NextPCReg ]   +   4 ;
       case  OP_BLTZ :
     if   ( registers [ instr -> rs ]   &  SIGN_BIT )
        pcAfter  =  registers [ NextPCReg ]   +   IndexToAddr ( instr -> extra );
     break ;
    
       case  OP_BNE :
     if   ( registers [ instr -> rs ]   !=  registers [ instr -> rt ])
        pcAfter  =  registers [ NextPCReg ]   +   IndexToAddr ( instr -> extra );
     break ;
    
       case  OP_DIV :
     if   ( registers [ instr -> rt ]   ==   0 )   {
        registers [ LoReg ]   =   0 ;
        registers [ HiReg ]   =   0 ;
     }   else   {
        registers [ LoReg ]   =   registers [ instr -> rs ]   /  registers [ instr -> rt ];
        registers [ HiReg ]   =  registers [ instr -> rs ]   %  registers [ instr -> rt ];
     }
     break ;
    
       case  OP_DIVU :    
      rs  =   ( unsigned   int )  registers [ instr -> rs ];
      rt  =   ( unsigned   int )  registers [ instr -> rt ];
       if   ( rt  ==   0 )   {
          registers [ LoReg ]   =   0 ;
          registers [ HiReg ]   =   0 ;
       }   else   {
          tmp  =  rs  /  rt ;
          registers [ LoReg ]   =   ( int )  tmp ;
          tmp  =  rs  %  rt ;
          registers [ HiReg ]   =   ( int )  tmp ;
       }
       break ;
    
       case  OP_JAL :
    registers [ R31 ]   =  registers [ NextPCReg ]   +   4 ;
       case  OP_J :
    pcAfter  =   ( pcAfter  &   0xf0000000 )   |   IndexToAddr ( instr -> extra );
     break ;
    
       case  OP_JALR :
    registers [ instr -> rd ]   =  registers [ NextPCReg ]   +   4 ;
       case  OP_JR :
    pcAfter  =  registers [ instr -> rs ];
     break ;
    
       case  OP_LB :
       case  OP_LBU :
    tmp  =  registers [ instr -> rs ]   +  instr -> extra ;
     if   ( ! ReadMem ( tmp ,   1 ,   & value ))
         return ;

     if   (( value   &   0x80 )   &&   ( instr -> opCode  ==  OP_LB ))
         value   |=   0xffffff00 ;
     else
         value   &=   0xff ;
    nextLoadReg  =  instr -> rt ;
    nextLoadValue  =   value ;
     break ;
    
       case  OP_LH :
       case  OP_LHU :     
    tmp  =  registers [ instr -> rs ]   +  instr -> extra ;
     if   ( tmp  &   0x1 )   {
         RaiseException ( AddressErrorException ,  tmp );
         return ;
     }
     if   ( ! ReadMem ( tmp ,   2 ,   & value ))
         return ;

     if   (( value   &   0x8000 )   &&   ( instr -> opCode  ==  OP_LH ))
         value   |=   0xffff0000 ;
     else
         value   &=   0xffff ;
    nextLoadReg  =  instr -> rt ;
    nextLoadValue  =   value ;
     break ;
        
       case  OP_LUI :
    DEBUG ( dbgMach ,   "Executing: LUI r"   <<  instr -> rt  <<   ", "   <<  instr -> extra );
    registers [ instr -> rt ]   =  instr -> extra  <<   16 ;
     break ;
    
       case  OP_LW :
    tmp  =  registers [ instr -> rs ]   +  instr -> extra ;
     if   ( tmp  &   0x3 )   {
         RaiseException ( AddressErrorException ,  tmp );
         return ;
     }
     if   ( ! ReadMem ( tmp ,   4 ,   & value ))
         return ;
    nextLoadReg  =  instr -> rt ;
    nextLoadValue  =   value ;
     break ;
        
       case  OP_LWL :     
    tmp  =  registers [ instr -> rs ]   +  instr -> extra ;

#ifdef  SIM_FIX
     // The only difference between this code and the BIG ENDIAN code
         // is that the ReadMem call is guaranteed an aligned access as it
         // should be (Kane's book hides the fact that all memory access
         // are done using aligned loads - what the instruction asks for
         // is a arbitrary) This is the whole purpose of LWL and LWR etc.
         // Then the switch uses  3 - (tmp & 0x3)  instead of (tmp & 0x3)

        byte  =  tmp  &   0x3 ;
         // DEBUG('P', "Addr 0x%X\n",tmp-byte);

         if   ( ! ReadMem ( tmp - byte ,   4 ,   & value ))
             return ;
#else
     // ReadMem assumes all 4 byte requests are aligned on an even 
     // word boundary.  Also, the little endian/big endian swap code would
         // fail (I think) if the other cases are ever exercised.
    ASSERT (( tmp  &   0x3 )   ==   0 );   

     if   ( ! ReadMem ( tmp ,   4 ,   & value ))
         return ;
#endif

     if   ( registers [ LoadReg ]   ==  instr -> rt )
        nextLoadValue  =  registers [ LoadValueReg ];
     else
        nextLoadValue  =  registers [ instr -> rt ];
#ifdef  SIM_FIX
     switch   ( 3   -  byte )  
#else
     switch   ( tmp  &   0x3 )
#endif
       {
       case   0 :
        nextLoadValue  =   value ;
         break ;
       case   1 :
        nextLoadValue  =   ( nextLoadValue  &   0xff )   |   ( value   <<   8 );
         break ;
       case   2 :
        nextLoadValue  =   ( nextLoadValue  &   0xffff )   |   ( value   <<   16 );
         break ;
       case   3 :
        nextLoadValue  =   ( nextLoadValue  &   0xffffff )   |   ( value   <<   24 );
         break ;
     }
    nextLoadReg  =  instr -> rt ;
     break ;
        
       case  OP_LWR :
    tmp  =  registers [ instr -> rs ]   +  instr -> extra ;

#ifdef  SIM_FIX
         // The only difference between this code and the BIG ENDIAN code
         // is that the ReadMem call is guaranteed an aligned access as it
         // should be (Kane's book hides the fact that all memory access
         // are done using aligned loads - what the instruction asks 
         // for is a arbitrary) This is the whole purpose of LWL and LWR etc.
         // Then the switch uses  3 - (tmp & 0x3)  instead of (tmp & 0x3)

        byte  =  tmp  &   0x3 ;
         // DEBUG('P', "Addr 0x%X\n",tmp-byte);

         if   ( ! ReadMem ( tmp - byte ,   4 ,   & value ))
             return ;
#else
     // ReadMem assumes all 4 byte requests are aligned on an even 
     // word boundary.  Also, the little endian/big endian swap code would
         // fail (I think) if the other cases are ever exercised.
    ASSERT (( tmp  &   0x3 )   ==   0 );   

     if   ( ! ReadMem ( tmp ,   4 ,   & value ))
         return ;
#endif

     if   ( registers [ LoadReg ]   ==  instr -> rt )
        nextLoadValue  =  registers [ LoadValueReg ];
     else
        nextLoadValue  =  registers [ instr -> rt ];

#ifdef  SIM_FIX
     switch   ( 3   -  byte )  
#else
     switch   ( tmp  &   0x3 )
#endif
       {
       case   0 :
        nextLoadValue  =   ( nextLoadValue  &   0xffffff00 )   |
         (( value   >>   24 )   &   0xff );
         break ;
       case   1 :
        nextLoadValue  =   ( nextLoadValue  &   0xffff0000 )   |
         (( value   >>   16 )   &   0xffff );
         break ;
       case   2 :
        nextLoadValue  =   ( nextLoadValue  &   0xff000000 )
         |   (( value   >>   8 )   &   0xffffff );
         break ;
       case   3 :
        nextLoadValue  =   value ;
         break ;
     }
    nextLoadReg  =  instr -> rt ;
     break ;
        
       case  OP_MFHI :
    registers [ instr -> rd ]   =  registers [ HiReg ];
     break ;
    
       case  OP_MFLO :
    registers [ instr -> rd ]   =  registers [ LoReg ];
     break ;
    
       case  OP_MTHI :
    registers [ HiReg ]   =  registers [ instr -> rs ];
     break ;
    
       case  OP_MTLO :
    registers [ LoReg ]   =  registers [ instr -> rs ];
     break ;
    
       case  OP_MULT :
     Mult ( registers [ instr -> rs ],  registers [ instr -> rt ],  TRUE ,
          & registers [ HiReg ],   & registers [ LoReg ]);
     break ;
    
       case  OP_MULTU :
     Mult ( registers [ instr -> rs ],  registers [ instr -> rt ],  FALSE ,
          & registers [ HiReg ],   & registers [ LoReg ]);
     break ;
    
       case  OP_NOR :
    registers [ instr -> rd ]   =   ~ ( registers [ instr -> rs ]   |  registers [ instr -> rt ]);
     break ;
    
       case  OP_OR :
    registers [ instr -> rd ]   =  registers [ instr -> rs ]   |  registers [ instr -> rt ];
     break ;
    
       case  OP_ORI :
    registers [ instr -> rt ]   =  registers [ instr -> rs ]   |   ( instr -> extra  &   0xffff );
     break ;
    
       case  OP_SB :
     if   ( ! WriteMem (( unsigned )  
         ( registers [ instr -> rs ]   +  instr -> extra ),   1 ,  registers [ instr -> rt ]))
         return ;
     break ;
    
       case  OP_SH :
     if   ( ! WriteMem (( unsigned )  
         ( registers [ instr -> rs ]   +  instr -> extra ),   2 ,  registers [ instr -> rt ]))
         return ;
     break ;
    
       case  OP_SLL :
    registers [ instr -> rd ]   =  registers [ instr -> rt ]   <<  instr -> extra ;
     break ;
    
       case  OP_SLLV :
    registers [ instr -> rd ]   =  registers [ instr -> rt ]   <<
         ( registers [ instr -> rs ]   &   0x1f );
     break ;
    
       case  OP_SLT :
     if   ( registers [ instr -> rs ]   <  registers [ instr -> rt ])
        registers [ instr -> rd ]   =   1 ;
     else
        registers [ instr -> rd ]   =   0 ;
     break ;
    
       case  OP_SLTI :
     if   ( registers [ instr -> rs ]   <  instr -> extra )
        registers [ instr -> rt ]   =   1 ;
     else
        registers [ instr -> rt ]   =   0 ;
     break ;
    
       case  OP_SLTIU :       
    rs  =  registers [ instr -> rs ];
    imm  =  instr -> extra ;
     if   ( rs  <  imm )
        registers [ instr -> rt ]   =   1 ;
     else
        registers [ instr -> rt ]   =   0 ;
     break ;
        
       case  OP_SLTU :    
    rs  =  registers [ instr -> rs ];
    rt  =  registers [ instr -> rt ];
     if   ( rs  <  rt )
        registers [ instr -> rd ]   =   1 ;
     else
        registers [ instr -> rd ]   =   0 ;
     break ;
        
       case  OP_SRA :
    registers [ instr -> rd ]   =  registers [ instr -> rt ]   >>  instr -> extra ;
     break ;
    
       case  OP_SRAV :
    registers [ instr -> rd ]   =  registers [ instr -> rt ]   >>
         ( registers [ instr -> rs ]   &   0x1f );
     break ;
    
       case  OP_SRL :
    tmp  =  registers [ instr -> rt ];
    tmp  >>=  instr -> extra ;
    registers [ instr -> rd ]   =  tmp ;
     break ;
    
       case  OP_SRLV :
    tmp  =  registers [ instr -> rt ];
    tmp  >>=   ( registers [ instr -> rs ]   &   0x1f );
    registers [ instr -> rd ]   =  tmp ;
     break ;
    
       case  OP_SUB :     
    diff  =  registers [ instr -> rs ]   -  registers [ instr -> rt ];
     if   ((( registers [ instr -> rs ]   ^  registers [ instr -> rt ])   &  SIGN_BIT )   &&
         (( registers [ instr -> rs ]   ^  diff )   &  SIGN_BIT ))   {
         RaiseException ( OverflowException ,   0 );
         return ;
     }
    registers [ instr -> rd ]   =  diff ;
     break ;
        
       case  OP_SUBU :
    registers [ instr -> rd ]   =  registers [ instr -> rs ]   -  registers [ instr -> rt ];
     break ;
    
       case  OP_SW :
     if   ( ! WriteMem (( unsigned )  
         ( registers [ instr -> rs ]   +  instr -> extra ),   4 ,  registers [ instr -> rt ]))
         return ;
     break ;
    
       case  OP_SWL :     
    tmp  =  registers [ instr -> rs ]   +  instr -> extra ;

#ifdef  SIM_FIX
         // The only difference between this code and the BIG ENDIAN code
         // is that the ReadMem call is guaranteed an aligned access as it
         // should be (Kane's book hides the fact that all memory access
         // are done using aligned loads - what the instruction asks for
         // is a arbitrary) This is the whole purpose of LWL and LWR etc.

        byte  =  tmp  &   0x3 ;
         // DEBUG('P', "Addr 0x%X\n",tmp-byte);
         if   ( ! ReadMem ( tmp - byte ,   4 ,   & value ))
             return ;

         // DEBUG('P', "Value 0x%X\n",value);
#else

     // The little endian/big endian swap code would
         // fail (I think) if the other cases are ever exercised.
    ASSERT (( tmp  &   0x3 )   ==   0 );   

     if   ( ! ReadMem (( tmp  &   ~ 0x3 ),   4 ,   & value ))
         return ;
#endif

#ifdef  SIM_FIX
     switch (   3   -  byte  )
#else
       switch   ( tmp  &   0x3 )  
#endif   // SIM_FIX
         {
       case   0 :
         value   =  registers [ instr -> rt ];
         break ;
       case   1 :
         value   =   ( value   &   0xff000000 )   |   (( registers [ instr -> rt ]   >>   8 )   &
                         0xffffff );
         break ;
       case   2 :
         value   =   ( value   &   0xffff0000 )   |   (( registers [ instr -> rt ]   >>   16 )   &
                         0xffff );
         break ;
       case   3 :
         value   =   ( value   &   0xffffff00 )   |   (( registers [ instr -> rt ]   >>   24 )   &
                         0xff );
         break ;
     }
#ifndef  SIM_FIX
         if   ( ! WriteMem (( tmp  &   ~ 0x3 ),   4 ,   value ))
             return ;
#else
         // DEBUG('P', "Value 0x%X\n",value);

         if   ( ! WriteMem (( tmp  -  byte ),   4 ,   value ))
             return ;
#endif   // SIM_FIX
     break ;
        
       case  OP_SWR :     
    tmp  =  registers [ instr -> rs ]   +  instr -> extra ;

#ifndef  SIM_FIX
         // The little endian/big endian swap code would
         // fail (I think) if the other cases are ever exercised.
        ASSERT (( tmp  &   0x3 )   ==   0 );   

         if   ( ! ReadMem (( tmp  &   ~ 0x3 ),   4 ,   & value ))
             return ;
#else
         // The only difference between this code and the BIG ENDIAN code
         // is that the ReadMem call is guaranteed an aligned access as 
         // it should be (Kane's book hides the fact that all memory 
         // access are done using aligned loads - what the instruction 
         // asks for is a arbitrary) This is the whole purpose of LWL 
         // and LWR etc.

        byte  =  tmp  &   0x3 ;
         // DEBUG('P', "Addr 0x%X\n",tmp-byte);

         if   ( ! ReadMem ( tmp - byte ,   4 ,   & value ))
             return ;
         // DEBUG('P', "Value 0x%X\n",value);
#endif   // SIM_FIX

#ifndef  SIM_FIX
         switch   ( tmp  &   0x3 )  
#else
       switch (   3   -  byte  )  
#endif   // SIM_FIX
         {
         case   0 :
         value   =   ( value   &   0xffffff )   |   ( registers [ instr -> rt ]   <<   24 );
         break ;
       case   1 :
         value   =   ( value   &   0xffff )   |   ( registers [ instr -> rt ]   <<   16 );
         break ;
       case   2 :
         value   =   ( value   &   0xff )   |   ( registers [ instr -> rt ]   <<   8 );
         break ;
       case   3 :
         value   =  registers [ instr -> rt ];
         break ;
     }

#ifndef  SIM_FIX
         if   ( ! WriteMem (( tmp  &   ~ 0x3 ),   4 ,   value ))
             return ;
#else
         // DEBUG('P', "Value 0x%X\n",value);

         if   ( ! WriteMem (( tmp  -  byte ),   4 ,   value ))
             return ;
#endif   // SIM_FIX


     break ;
        
       case  OP_SYSCALL :
     RaiseException ( SyscallException ,   0 );
     return ;  
    
       case  OP_XOR :
    registers [ instr -> rd ]   =  registers [ instr -> rs ]   ^  registers [ instr -> rt ];
     break ;
    
       case  OP_XORI :
    registers [ instr -> rt ]   =  registers [ instr -> rs ]   ^   ( instr -> extra  &   0xffff );
     break ;
    
       case  OP_RES :
       case  OP_UNIMP :
     RaiseException ( IllegalInstrException ,   0 );
     return ;
    
       default :
    ASSERT ( FALSE );
     }
    
     // Now we have successfully executed the instruction.
    
     // Do any delayed load operation
     DelayedLoad ( nextLoadReg ,  nextLoadValue );
    
     // Advance program counters.
    registers [ PrevPCReg ]   =  registers [ PCReg ];      // for debugging, in case we
                         // are jumping into lala-land
    registers [ PCReg ]   =  registers [ NextPCReg ];
    registers [ NextPCReg ]   =  pcAfter ;
}

//----------------------------------------------------------------------
// Machine::DelayedLoad
//  Simulate effects of a delayed load.
//
//  NOTE -- RaiseException/CheckInterrupts must also call DelayedLoad,
//  since any delayed load must get applied before we trap to the kernel.
//----------------------------------------------------------------------

void
Machine :: DelayedLoad ( int  nextReg ,   int  nextValue )
{
    registers [ registers [ LoadReg ]]   =  registers [ LoadValueReg ];
    registers [ LoadReg ]   =  nextReg ;
    registers [ LoadValueReg ]   =  nextValue ;
    registers [ 0 ]   =   0 ;     // and always make sure R0 stays zero.
}

//----------------------------------------------------------------------
// Instruction::Decode
//  Decode a MIPS instruction 
//----------------------------------------------------------------------

void
Instruction :: Decode ()
{
     OpInfo   * opPtr ;
    
    rs  =   ( value   >>   21 )   &   0x1f ;
    rt  =   ( value   >>   16 )   &   0x1f ;
    rd  =   ( value   >>   11 )   &   0x1f ;
    opPtr  =   & opTable [( value   >>   26 )   &   0x3f ];
    opCode  =  opPtr -> opCode ;
     if   ( opPtr -> format  ==  IFMT )   {
    extra  =   value   &   0xffff ;
     if   ( extra  &   0x8000 )   {
           extra  |=   0xffff0000 ;
     }
     }   else   if   ( opPtr -> format  ==  RFMT )   {
    extra  =   ( value   >>   6 )   &   0x1f ;
     }   else   {
    extra  =   value   &   0x3ffffff ;
     }
     if   ( opCode  ==  SPECIAL )   {
    opCode  =  specialTable [ value   &   0x3f ];
     }   else   if   ( opCode  ==  BCOND )   {
     int  i  =   value   &   0x1f0000 ;

     if   ( ==   0 )   {
            opCode  =  OP_BLTZ ;
     }   else   if   ( ==   0x10000 )   {
            opCode  =  OP_BGEZ ;
     }   else   if   ( ==   0x100000 )   {
            opCode  =  OP_BLTZAL ;
     }   else   if   ( ==   0x110000 )   {
            opCode  =  OP_BGEZAL ;
     }   else   {
            opCode  =  OP_UNIMP ;
     }
     }
}

//----------------------------------------------------------------------
// Mult
//  Simulate R2000 multiplication.
//  The words at *hiPtr and *loPtr are overwritten with the
//  double-length result of the multiplication.
//----------------------------------------------------------------------

static   void
Mult ( int  a ,   int  b ,   bool  signedArith ,   int *  hiPtr ,   int *  loPtr )
{
     if   (( ==   0 )   ||   ( ==   0 ))   {
     * hiPtr  =   * loPtr  =   0 ;
     return ;
     }

     // Compute the sign of the result, then make everything positive
     // so unsigned computation can be done in the main loop.
     bool  negative  =  FALSE ;
     if   ( signedArith )   {
     if   ( <   0 )   {
        negative  =   ! negative ;
        a  =   - a ;
     }
     if   ( <   0 )   {
        negative  =   ! negative ;
        b  =   - b ;
     }
     }

     // Compute the result in unsigned arithmetic (check a's bits one at
     // a time, and add in a shifted value of b).
     unsigned   int  bLo  =  b ;
     unsigned   int  bHi  =   0 ;
     unsigned   int  lo  =   0 ;
     unsigned   int  hi  =   0 ;
     for   ( int  i  =   0 ;  i  <   32 ;  i ++ )   {
     if   ( &   1 )   {
        lo  +=  bLo ;
         if   ( lo  <  bLo )    // Carry out of the low bits?
        hi  +=   1 ;
        hi  +=  bHi ;
         if   (( &   0xfffffffe )   ==   0 )
         break ;
     }
    bHi  <<=   1 ;
     if   ( bLo  &   0x80000000 )
        bHi  |=   1 ;
    
    bLo  <<=   1 ;
    a  >>=   1 ;
     }

     // If the result is supposed to be negative, compute the two's
     // complement of the double-word result.
     if   ( negative )   {
    hi  =   ~ hi ;
    lo  =   ~ lo ;
    lo ++ ;
     if   ( lo  ==   0 )
        hi ++ ;
     }
    
     * hiPtr  =   ( int )  hi ;
     * loPtr  =   ( int )  lo ;
}

nachos/code/machine/stats.h

// stats.h // Data structures for gathering statistics about Nachos performance. // // DO NOT CHANGE -- these stats are maintained by the machine emulation // // // Copyright (c) 1992-1993 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef STATS_H #define STATS_H #include "copyright.h" // The following class defines the statistics that are to be kept // about Nachos behavior -- how much time (ticks) elapsed, how // many user instructions executed, etc. // // The fields in this class are public to make it easier to update. class Statistics { public: int totalTicks; // Total time running Nachos int idleTicks; // Time spent idle (no threads to run) int systemTicks; // Time spent executing system code int userTicks; // Time spent executing user code // (this is also equal to # of // user instructions executed) int numDiskReads; // number of disk read requests int numDiskWrites; // number of disk write requests int numConsoleCharsRead; // number of characters read from the keyboard int numConsoleCharsWritten; // number of characters written to the display int numPageFaults; // number of virtual memory page faults int numPacketsSent; // number of packets sent over the network int numPacketsRecvd; // number of packets received over the network Statistics(); // initialize everything to zero void Print(); // print collected statistics }; // Constants used to reflect the relative time an operation would // take in a real system. A "tick" is a just a unit of time -- if you // like, a microsecond. // // Since Nachos kernel code is directly executed, and the time spent // in the kernel measured by the number of calls to enable interrupts, // these time constants are none too exact. const int UserTick = 1; // advance for each user-level instruction const int SystemTick = 10; // advance each time interrupts are enabled const int RotationTime = 500; // time disk takes to rotate one sector const int SeekTime = 500; // time disk takes to seek past one track const int ConsoleTime = 100; // time to read or write one character const int NetworkTime = 100; // time to send or receive one packet const int TimerTicks = 100; // (average) time between timer interrupts #endif // STATS_H

nachos/code/machine/console.cc

nachos/code/machine/console.cc

// console.cc 
//  Routines to simulate a serial port to a console device.
//  A console has input (a keyboard) and output (a display).
//  These are each simulated by operations on UNIX files.
//  The simulated device is asynchronous, so we have to invoke 
//  the interrupt handler (after a simulated delay), to signal that 
//  a byte has arrived and/or that a written byte has departed.
//
//  DO NOT CHANGE -- part of the machine emulation
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include   "copyright.h"
#include   "console.h"
#include   "main.h"

//----------------------------------------------------------------------
// ConsoleInput::ConsoleInput
//  Initialize the simulation of the input for a hardware console device.
//
//  "readFile" -- UNIX file simulating the keyboard (NULL -> use stdin)
//  "toCall" is the interrupt handler to call when a character arrives
//      from the keyboard
//----------------------------------------------------------------------

ConsoleInput :: ConsoleInput ( char   * readFile ,   CallBackObj   * toCall )
{
     if   ( readFile  ==  NULL )
    readFileNo  =   0 ;                   // keyboard = stdin
     else
        readFileNo  =   OpenForReadWrite ( readFile ,  TRUE );    // should be read-only

     // set up the stuff to emulate asynchronous interrupts
    callWhenAvail  =  toCall ;
    incoming  =  EOF ;

     // start polling for incoming keystrokes
    kernel -> interrupt -> Schedule ( this ,   ConsoleTime ,   ConsoleReadInt );
}

//----------------------------------------------------------------------
// ConsoleInput::~ConsoleInput
//  Clean up console input emulation
//----------------------------------------------------------------------

ConsoleInput ::~ ConsoleInput ()
{
     if   ( readFileNo  !=   0 )
     Close ( readFileNo );
}


//----------------------------------------------------------------------
// ConsoleInput::CallBack()
//  Simulator calls this when a character may be available to be
//  read in from the simulated keyboard (eg, the user typed something).
//
//  First check to make sure character is available.
//  Then invoke the "callBack" registered by whoever wants the character.
//----------------------------------------------------------------------

void
ConsoleInput :: CallBack ()
{
   char  c ;
   int  readCount ;

    ASSERT ( incoming  ==  EOF );
     if   ( ! PollFile ( readFileNo ))   {   // nothing to be read
         // schedule the next time to poll for a packet
        kernel -> interrupt -> Schedule ( this ,   ConsoleTime ,   ConsoleReadInt );
     }   else   {  
         // otherwise, try to read a character
        readCount  =   ReadPartial ( readFileNo ,   & c ,   sizeof ( char ));
     if   ( readCount  ==   0 )   {
        // this seems to happen at end of file, when the
        // console input is a regular file
        // don't schedule an interrupt, since there will never
        // be any more input
        // just do nothing....
     }
     else   {
       // save the character and notify the OS that
       // it is available
      ASSERT ( readCount  ==   sizeof ( char ));
      incoming  =  c ;
      kernel -> stats -> numConsoleCharsRead ++ ;
     }
    callWhenAvail -> CallBack ();
     }
}

//----------------------------------------------------------------------
// ConsoleInput::GetChar()
//  Read a character from the input buffer, if there is any there.
//  Either return the character, or EOF if none buffered.
//----------------------------------------------------------------------

char
ConsoleInput :: GetChar ()
{
    char  ch  =  incoming ;

    if   ( incoming  !=  EOF )   {     // schedule when next char will arrive
       kernel -> interrupt -> Schedule ( this ,   ConsoleTime ,   ConsoleReadInt );
    }
   incoming  =  EOF ;
    return  ch ;
}



//----------------------------------------------------------------------
// ConsoleOutput::ConsoleOutput
//  Initialize the simulation of the output for a hardware console device.
//
//  "writeFile" -- UNIX file simulating the display (NULL -> use stdout)
//  "toCall" is the interrupt handler to call when a write to 
//  the display completes.
//----------------------------------------------------------------------

ConsoleOutput :: ConsoleOutput ( char   * writeFile ,   CallBackObj   * toCall )
{
     if   ( writeFile  ==  NULL )
    writeFileNo  =   1 ;                  // display = stdout
     else
        writeFileNo  =   OpenForWrite ( writeFile );

    callWhenDone  =  toCall ;
    putBusy  =  FALSE ;
}

//----------------------------------------------------------------------
// ConsoleOutput::~ConsoleOutput
//  Clean up console output emulation
//----------------------------------------------------------------------

ConsoleOutput ::~ ConsoleOutput ()
{
     if   ( writeFileNo  !=   1 )
     Close ( writeFileNo );
}

//----------------------------------------------------------------------
// ConsoleOutput::CallBack()
//  Simulator calls this when the next character can be output to the
//  display.
//----------------------------------------------------------------------

void
ConsoleOutput :: CallBack ()
{
    putBusy  =  FALSE ;
    kernel -> stats -> numConsoleCharsWritten ++ ;
    callWhenDone -> CallBack ();
}

//----------------------------------------------------------------------
// ConsoleOutput::PutChar()
//  Write a character to the simulated display, schedule an interrupt 
//  to occur in the future, and return.
//----------------------------------------------------------------------

void
ConsoleOutput :: PutChar ( char  ch )
{
    ASSERT ( putBusy  ==  FALSE );
     WriteFile ( writeFileNo ,   & ch ,   sizeof ( char ));
    putBusy  =  TRUE ;
    kernel -> interrupt -> Schedule ( this ,   ConsoleTime ,   ConsoleWriteInt );
}

nachos/code/machine/machine.h

// machine.h // Data structures for simulating the execution of user programs // running on top of Nachos. // // User programs are loaded into "mainMemory"; to Nachos, // this looks just like an array of bytes. Of course, the Nachos // kernel is in memory too -- but as in most machines these days, // the kernel is loaded into a separate memory region from user // programs, and accesses to kernel memory are not translated or paged. // // In Nachos, user programs are executed one instruction at a time, // by the simulator. Each memory reference is translated, checked // for errors, etc. // // DO NOT CHANGE EXCEPT AS NOTED BELOW -- part of the machine emulation // // Copyright (c) 1992-1996 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef MACHINE_H #define MACHINE_H #include "copyright.h" #include "utility.h" #include "translate.h" // Definitions related to the size, and format of user memory const int PageSize = 128; // set the page size equal to // the disk sector size, for simplicity // // You are allowed to change this value. // Doing so will change the number of pages of physical memory // available on the simulated machine. // const int NumPhysPages = 128; const int MemorySize = (NumPhysPages * PageSize); const int TLBSize = 4; // if there is a TLB, make it small enum ExceptionType { NoException, // Everything ok! SyscallException, // A program executed a system call. PageFaultException, // No valid translation found ReadOnlyException, // Write attempted to page marked // "read-only" BusErrorException, // Translation resulted in an // invalid physical address AddressErrorException, // Unaligned reference or one that // was beyond the end of the // address space OverflowException, // Integer overflow in add or sub. IllegalInstrException, // Unimplemented or reserved instr. NumExceptionTypes }; // User program CPU state. The full set of MIPS registers, plus a few // more because we need to be able to start/stop a user program between // any two instructions (thus we need to keep track of things like load // delay slots, etc.) #define StackReg 29 // User's stack pointer #define RetAddrReg 31 // Holds return address for procedure calls #define NumGPRegs 32 // 32 general purpose registers on MIPS #define HiReg 32 // Double register to hold multiply result #define LoReg 33 #define PCReg 34 // Current program counter #define NextPCReg 35 // Next program counter (for branch delay) #define PrevPCReg 36 // Previous program counter (for debugging) #define LoadReg 37 // The register target of a delayed load. #define LoadValueReg 38 // The value to be loaded by a delayed load. #define BadVAddrReg 39 // The failing virtual address on an exception #define NumTotalRegs 40 // The following class defines the simulated host workstation hardware, as // seen by user programs -- the CPU registers, main memory, etc. // User programs shouldn't be able to tell that they are running on our // simulator or on the real hardware, except // we don't support floating point instructions // the system call interface to Nachos is not the same as UNIX // (10 system calls in Nachos vs. 200 in UNIX!) // If we were to implement more of the UNIX system calls, we ought to be // able to run Nachos on top of Nachos! // // The procedures in this class are defined in machine.cc, mipssim.cc, and // translate.cc. class Instruction; class Interrupt; class Machine { public: Machine(bool debug); // Initialize the simulation of the hardware // for running user programs ~Machine(); // De-allocate the data structures // Routines callable by the Nachos kernel void Run(); // Run a user program int ReadRegister(int num); // read the contents of a CPU register void WriteRegister(int num, int value); // store a value into a CPU register // Data structures accessible to the Nachos kernel -- main memory and the // page table/TLB. // // Note that *all* communication between the user program and the kernel // are in terms of these data structures (plus the CPU registers). char *mainMemory; // physical memory to store user program, // code and data, while executing // NOTE: the hardware translation of virtual addresses in the user program // to physical addresses (relative to the beginning of "mainMemory") // can be controlled by one of: // a traditional linear page table // a software-loaded translation lookaside buffer (tlb) -- a cache of // mappings of virtual page #'s to physical page #'s // // If "tlb" is NULL, the linear page table is used // If "tlb" is non-NULL, the Nachos kernel is responsible for managing // the contents of the TLB. But the kernel can use any data structure // it wants (eg, segmented paging) for handling TLB cache misses. // // For simplicity, both the page table pointer and the TLB pointer are // public. However, while there can be multiple page tables (one per address // space, stored in memory), there is only one TLB (implemented in hardware). // Thus the TLB pointer should be considered as *read-only*, although // the contents of the TLB are free to be modified by the kernel software. TranslationEntry *tlb; // this pointer should be considered // "read-only" to Nachos kernel code TranslationEntry *pageTable; unsigned int pageTableSize; bool ReadMem(int addr, int size, int* value); bool WriteMem(int addr, int size, int value); // Read or write 1, 2, or 4 bytes of virtual // memory (at addr). Return FALSE if a // correct translation couldn't be found. private: // Routines internal to the machine simulation -- DO NOT call these directly void DelayedLoad(int nextReg, int nextVal); // Do a pending delayed load (modifying a reg) void OneInstruction(Instruction *instr); // Run one instruction of a user program. ExceptionType Translate(int virtAddr, int* physAddr, int size,bool writing); // Translate an address, and check for // alignment. Set the use and dirty bits in // the translation entry appropriately, // and return an exception code if the // translation couldn't be completed. void RaiseException(ExceptionType which, int badVAddr); // Trap to the Nachos kernel, because of a // system call or other exception. void Debugger(); // invoke the user program debugger void DumpState(); // print the user CPU and memory state // Internal data structures int registers[NumTotalRegs]; // CPU registers, for executing user programs bool singleStep; // drop back into the debugger after each // simulated instruction int runUntilTime; // drop back into the debugger when simulated // time reaches this value friend class Interrupt; // calls DelayedLoad() }; extern void ExceptionHandler(ExceptionType which); // Entry point into Nachos for handling // user system calls and exceptions // Defined in exception.cc // Routines for converting Words and Short Words to and from the // simulated machine's format of little endian. If the host machine // is little endian (DEC and Intel), these end up being NOPs. // // What is stored in each format: // host byte ordering: // kernel data structures // user registers // simulated machine byte ordering: // contents of main memory unsigned int WordToHost(unsigned int word); unsigned short ShortToHost(unsigned short shortword); unsigned int WordToMachine(unsigned int word); unsigned short ShortToMachine(unsigned short shortword); #endif // MACHINE_H

nachos/code/machine/disk.cc

nachos/code/machine/disk.cc

// disk.cc 
//  Routines to simulate a physical disk device; reading and writing
//  to the disk is simulated as reading and writing to a UNIX file.
//  See disk.h for details about the behavior of disks (and
//  therefore about the behavior of this simulation).
//
//  Disk operations are asynchronous, so we have to invoke an interrupt
//  handler when the simulated operation completes.
//
//  DO NOT CHANGE -- part of the machine emulation
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include   "copyright.h"
#include   "disk.h"
#include   "debug.h"
#include   "sysdep.h"
#include   "main.h"

// We put a magic number at the front of the UNIX file representing the
// disk, to make it less likely we will accidentally treat a useful file 
// as a disk (which would probably trash the file's contents).

const   int   MagicNumber   =   0x456789ab ;
const   int   MagicSize   =   sizeof ( int );
const   int   DiskSize   =   ( MagicSize   +   ( NumSectors   *   SectorSize ));


//----------------------------------------------------------------------
// Disk::Disk()
//  Initialize a simulated disk.  Open the UNIX file (creating it
//  if it doesn't exist), and check the magic number to make sure it's 
//  ok to treat it as Nachos disk storage.
//
//  "toCall" -- object to call when disk read/write request completes
//----------------------------------------------------------------------

Disk :: Disk ( CallBackObj   * toCall )
{
     int  magicNum ;
     int  tmp  =   0 ;

    DEBUG ( dbgDisk ,   "Initializing the disk." );
    callWhenDone  =  toCall ;
    lastSector  =   0 ;
    bufferInit  =   0 ;
    
    sprintf ( diskname , "DISK_%d" , kernel -> hostName );
    fileno  =   OpenForReadWrite ( diskname ,  FALSE );
     if   ( fileno  >=   0 )   {            // file exists, check magic number 
     Read ( fileno ,   ( char   * )   & magicNum ,   MagicSize );
    ASSERT ( magicNum  ==   MagicNumber );
     }   else   {                  // file doesn't exist, create it
        fileno  =   OpenForWrite ( diskname );
    magicNum  =   MagicNumber ;   
     WriteFile ( fileno ,   ( char   * )   & magicNum ,   MagicSize );   // write magic number

     // need to write at end of file, so that reads will not return EOF
         Lseek ( fileno ,   DiskSize   -   sizeof ( int ),   0 );    
     WriteFile ( fileno ,   ( char   * ) & tmp ,   sizeof ( int ));   
     }
    active  =  FALSE ;
}

//----------------------------------------------------------------------
// Disk::~Disk()
//  Clean up disk simulation, by closing the UNIX file representing the
//  disk.
//----------------------------------------------------------------------

Disk ::~ Disk ()
{
     Close ( fileno );
}

//----------------------------------------------------------------------
// Disk::PrintSector()
//  Dump the data in a disk read/write request, for debugging.
//----------------------------------------------------------------------

static   void
PrintSector   ( bool  writing ,   int  sector ,   char   * data )
{
     int   * =   ( int   * )  data ;

     if   ( writing )
        cout  <<   "Writing sector: "   <<  sector  <<   "\n" ;  
     else
        cout  <<   "Reading sector: "   <<  sector  <<   "\n" ;  
     for   ( unsigned   int  i  =   0 ;  i  <   ( SectorSize / sizeof ( int ));  i ++ )   {
    cout  <<  p [ i ]   <<   " " ;
     }
    cout  <<   "\n" ;  
}

//----------------------------------------------------------------------
// Disk::ReadRequest/WriteRequest
//  Simulate a request to read/write a single disk sector
//     Do the read/write immediately to the UNIX file
//     Set up an interrupt handler to be called later,
//        that will notify the caller when the simulator says
//        the operation has completed.
//
//  Note that a disk only allows an entire sector to be read/written,
//  not part of a sector.
//
//  "sectorNumber" -- the disk sector to read/write
//  "data" -- the bytes to be written, the buffer to hold the incoming bytes
//----------------------------------------------------------------------

void
Disk :: ReadRequest ( int  sectorNumber ,   char *  data )
{
     int  ticks  =   ComputeLatency ( sectorNumber ,  FALSE );

    ASSERT ( ! active );                  // only one request at a time
    ASSERT (( sectorNumber  >=   0 )   &&   ( sectorNumber  <   NumSectors ));
    
    DEBUG ( dbgDisk ,   "Reading from sector "   <<  sectorNumber );
     Lseek ( fileno ,   SectorSize   *  sectorNumber  +   MagicSize ,   0 );
     Read ( fileno ,  data ,   SectorSize );
     if   ( debug -> IsEnabled ( 'd' ))
     PrintSector ( FALSE ,  sectorNumber ,  data );
    
    active  =  TRUE ;
     UpdateLast ( sectorNumber );
    kernel -> stats -> numDiskReads ++ ;
    kernel -> interrupt -> Schedule ( this ,  ticks ,   DiskInt );
}

void
Disk :: WriteRequest ( int  sectorNumber ,   char *  data )
{
     int  ticks  =   ComputeLatency ( sectorNumber ,  TRUE );

    ASSERT ( ! active );
    ASSERT (( sectorNumber  >=   0 )   &&   ( sectorNumber  <   NumSectors ));
    
    DEBUG ( dbgDisk ,   "Writing to sector "   <<  sectorNumber );
     Lseek ( fileno ,   SectorSize   *  sectorNumber  +   MagicSize ,   0 );
     WriteFile ( fileno ,  data ,   SectorSize );
     if   ( debug -> IsEnabled ( 'd' ))
     PrintSector ( TRUE ,  sectorNumber ,  data );
    
    active  =  TRUE ;
     UpdateLast ( sectorNumber );
    kernel -> stats -> numDiskWrites ++ ;
    kernel -> interrupt -> Schedule ( this ,  ticks ,   DiskInt );
}

//----------------------------------------------------------------------
// Disk::CallBack()
//  Called by the machine simulation when the disk interrupt occurs.
//----------------------------------------------------------------------

void
Disk :: CallBack   ()
{  
    active  =  FALSE ;
    callWhenDone -> CallBack ();
}

//----------------------------------------------------------------------
// Disk::TimeToSeek()
//  Returns how long it will take to position the disk head over the correct
//  track on the disk.  Since when we finish seeking, we are likely
//  to be in the middle of a sector that is rotating past the head,
//  we also return how long until the head is at the next sector boundary.
//  
//      Disk seeks at one track per SeekTime ticks (cf. stats.h)
//      and rotates at one sector per RotationTime ticks
//----------------------------------------------------------------------

int
Disk :: TimeToSeek ( int  newSector ,   int   * rotation )  
{
     int  newTrack  =  newSector  /   SectorsPerTrack ;
     int  oldTrack  =  lastSector  /   SectorsPerTrack ;
     int  seek  =  abs ( newTrack  -  oldTrack )   *   SeekTime ;
                 // how long will seek take?
     int  over  =   ( kernel -> stats -> totalTicks  +  seek )   %   RotationTime ;  
                 // will we be in the middle of a sector when
                 // we finish the seek?

     * rotation  =   0 ;
     if   ( over  >   0 )         // if so, need to round up to next full sector
     * rotation  =   RotationTime   -  over ;
     return  seek ;
}

//----------------------------------------------------------------------
// Disk::ModuloDiff()
//  Return number of sectors of rotational delay between target sector
//  "to" and current sector position "from"
//----------------------------------------------------------------------

int  
Disk :: ModuloDiff ( int  to ,   int  from )
{
     int  toOffset  =  to  %   SectorsPerTrack ;
     int  fromOffset  =  from  %   SectorsPerTrack ;

     return   (( toOffset  -  fromOffset )   +   SectorsPerTrack )   %   SectorsPerTrack ;
}

//----------------------------------------------------------------------
// Disk::ComputeLatency()
//  Return how long will it take to read/write a disk sector, from
//  the current position of the disk head.
//
//      Latency = seek time + rotational latency + transfer time
//      Disk seeks at one track per SeekTime ticks (cf. stats.h)
//      and rotates at one sector per RotationTime ticks
//
//      To find the rotational latency, we first must figure out where the 
//      disk head will be after the seek (if any).  We then figure out
//      how long it will take to rotate completely past newSector after 
//  that point.
//
//      The disk also has a "track buffer"; the disk continuously reads
//      the contents of the current disk track into the buffer.  This allows 
//      read requests to the current track to be satisfied more quickly.
//      The contents of the track buffer are discarded after every seek to 
//      a new track.
//----------------------------------------------------------------------

int
Disk :: ComputeLatency ( int  newSector ,   bool  writing )
{
     int  rotation ;
     int  seek  =   TimeToSeek ( newSector ,   & rotation );
     int  timeAfter  =  kernel -> stats -> totalTicks  +  seek  +  rotation ;

#ifndef  NOTRACKBUF   // turn this on if you don't want the track buffer stuff
     // check if track buffer applies
     if   (( writing  ==  FALSE )   &&   ( seek  ==   0 )  
         &&   ((( timeAfter  -  bufferInit )   /   RotationTime )  
                 >   ModuloDiff ( newSector ,  bufferInit  /   RotationTime )))   {
        DEBUG ( dbgDisk ,   "Request latency = "   <<   RotationTime );
     return   RotationTime ;   // time to transfer sector from the track buffer
     }
#endif

    rotation  +=   ModuloDiff ( newSector ,  timeAfter  /   RotationTime )   *   RotationTime ;

    DEBUG ( dbgDisk ,   "Request latency = "   <<   ( seek  +  rotation  +   RotationTime ));
     return ( seek  +  rotation  +   RotationTime );
}

//----------------------------------------------------------------------
// Disk::UpdateLast
//      Keep track of the most recently requested sector.  So we can know
//  what is in the track buffer.
//----------------------------------------------------------------------

void
Disk :: UpdateLast ( int  newSector )
{
     int  rotate ;
     int  seek  =   TimeToSeek ( newSector ,   & rotate );
    
     if   ( seek  !=   0 )
    bufferInit  =  kernel -> stats -> totalTicks  +  seek  +  rotate ;
    lastSector  =  newSector ;
    DEBUG ( dbgDisk ,   "Updating last sector = "   <<  lastSector  <<   " , "   <<  bufferInit );
}

nachos/code/build.macosx/Makefile.dep

################################################################## # Machine Dependencies - this file is included automatically # into the main Makefile # ################################################################## HOSTCFLAGS = -DHOST_IS_BIG_ENDIAN -DPowerPC -DBSD -DAIX -DApplePowerPC CPP_AS_FLAGS = -D_ASM CPP = cpp #----------------------------------------------------------------- # Do not put anything below this point - it will be destroyed by # "make depend" # # DO NOT DELETE THIS LINE -- make depend uses it # DEPENDENCIES MUST END AT END OF FILE # IF YOU PUT STUFF HERE IT WILL GO AWAY # see make depend above

nachos/code/build.macosx/Makefile

# Copyright (c) 1992-1996 The Regents of the University of California. # All rights reserved. See copyright.h for copyright notice and limitation # of liability and disclaimer of warranty provisions. # # This is a GNU Makefile. It must be used with the GNU make program. # At UW, the GNU make program is /software/gnu/bin/make. # In many other places it is known as "gmake". # You may wish to include /software/gnu/bin/ early in your command # search path, so that you will be using GNU make when you type "make". # # About this Makefile: # -------------------- # # This Makefile is used to build the Nachos system, which includes # the MIPS machine simulation and a simple operating system. # # There is a separate Makefile, in the "test" directory, that is # used to build the Nachos test programs (which run on the # simulated machine). # # There are several "build" directories, one for each type # of machine in the MFCF computing environment # (build.solaris, build.sunos, and build.ultrix), as well # as a build directory for Linux (build.linux) and a generic # build directory (build.other) for those who wish to try # building Nachos on other platforms. # # This Makefile appears to be located in all of the build directories. # If you edit it in one directory, the copies in all of the other # directories appear to change as well. This is the desired behaviour, # since this file is machine independent. (The file actually lives # in build.solaris, with symbolic links from the other build directories.) # # The platform-dependent parts of make's instructions are located # in the file Makefile.dep. # There is a different Makefile.dep in each build directory. # # If you are in the MFCF environment, you should not have to edit # the Makefile.dep files by hand. Any changes to the make instructions # can be made in this file (see the instructions below) - they will # apply no matter where you build Nachos. # If you are not in the MFCF environment, e.g., if you are trying # to build Nachos on Linux at home, you will probably need # to edit Makefile.dep (in the appropriate build directory) to # customize the make procedure to your environment. # # How to build Nachos for the first time: # --------------------------------------- # # (1) Make sure than you are in the build directory for the # type of machine you are logged in to (the "host" machine): # # host type examples build directory # ----------- ----------- ---------------- # # sparc/SunOS cayley,napier, build.sunos # (SunOS 4.1.3) descartes # # sparc/Solaris picard.math, build.solaris # (SunOS 5.x) hermite.math, # markov.math, # hypatia.math, # hume.math # # mips/ULTRIX cantor.math build.ultrix # (ULTRIX 4.2) noether.math # # If you are not sure what type of machine you are on, # try the command "uname -a". # # (2) Type "make depend" # - this computes file dependencies and records them # at the end of the file Makefile.dep in # your build directory. Have a look... # # (3) Type "make nachos" (or just "make"). # - make echos the commands it is executing, so that # you can observe its progress. When the # build is finished, you should have an # executable "nachos" in the build directory. # # (4) There is no 4th step. You are done. Try running "./nachos -u". # # # How to Re-build Nachos after you have changed the code: #-------------------------------------------------------- # # - The Nachos source code is located in the code subdirectories: # threads, userprog, filesys, network, and lib. You may # change the files in any of these directories, and you can # add new files and/or remove files. The "machine" subdirectory # contains the hardware simulation (which is also part of # Nachos. You may look at it, but # you may not change it, except as noted in machine/machine.h # - When you want to re-make Nachos, always do it in the # "build" directory that is appropriate for the machine # type that you are running on. # DO NOT TRY TO MAKE NACHOS IN THE SOURCE CODE DIRECTORIES. # # - IF all you have done is changed C++ code in existing files # (since the last time you made Nachos in this build directory), # THEN all you need to do to re-make Nachos is to type # # "make nachos" # # in the build directory. # # - IF you have done any of the following since the last build in # this directory: # added new .cc files or new .h files # added or deleted #include's from existing files # THEN # you must do # "make depend" # followed by # "make nachos" # # in the build directory. # # Note that is is always safe to do "make depend" followed by # "make nachos", so if you are not sure what changes you have # made, do "make depend". # # - IF you have added new files (.cc or .h) since the last build, # you should edit this Makefile before running "make depend" # and "make nachos". # For new .h files, simply update the appropriate "_H" list below. # For example, if you create a file called # "bigfile.h" in the filesys subdirectory, you should add # "../filesys/bigfile.h" to FILESYS_H, which is defined below # For new .cc files, update the appropriate "_C" and "_O" lists. # For example, if you create a file called "filetable.cc" in # the directory "userprog", you should add # "../userprog/filetable.cc" to USERPROG_C, # and you should add "filetable.o" to USERPROG_O. # Note that the entry in the "_C" list includes the subdirectory # name, while the entry on the "_O" list does not. # # Some Important Notes: # --------------------- # # * You can clean up all of the .o and other files left behind # by make by typeing "make clean" in the build directory. # * You can clean up .o and other files, as well as the nachos # executable, DISK, core, SOCKET, and other files by typing # make "distclean" # # These are good ways to save space, but the next build that # you do after cleaning will take longer than usual, since # much of the stuff you cleaned will need to be rebuilt. # # * When you build Nachos on an ULTRIX machine (in build.ultrix), # you will get lots of warning messages like this: # # openfile.o: does not have gp tables for all it's sectons # # from the loader. Ignore them. Or better yet, figure out # how to make them go away. # # The Most Important Note: # ----------------------- # # * If "make" is behaving strangely and you cannot figure out # why, you should REBUILD the program FROM SCRATCH. # Yes, it is slow. # But, there are lots of little things that can go wrong, especially # with all of these different types of machines available. # Rebuilding from scratch at least gives you a known starting # place. To rebuild from scratch, go to the appropriate # build directory and do: # # make distclean # make depend # make nachos # ################################################################ # READ THIS: CONFIGURING NACHOS # # Change DEFINES (below) to # DEFINES = -DUSE_TLB -DFILESYS_STUB # if you want the simulated machine to use its TLB # # If you want to use the real Nachos file system (based on # the simulated disk), rather than the stub, remove # the -DFILESYS_STUB from DEFINES. # # There is a a fix to the MIPS simulator to enable it to properly # handle unaligned data access. This fix is enabled by the addition # of "-DSIM_FIX" to the DEFINES. This should be enabled by default # and eventually will not require the symbol definition ################################################################ DEFINES = -DFILESYS_STUB -DRDATA -DSIM_FIX ##################################################################### # # You might want to play with the CFLAGS, but if you use -O it may # break the thread system. You might want to use -fno-inline if # you need to call some inline functions from the debugger. CFLAGS = -g -Wall -fwritable-strings $(INCPATH) $(DEFINES) $(HOSTCFLAGS) -DCHANGED LDFLAGS = ##################################################################### CPP=/lib/cpp CC = g++ LD = g++ AS = as RM = /bin/rm INCPATH = -I../network -I../filesys -I../userprog -I../threads -I../machine -I../lib PROGRAM = nachos # # Edit these lists as if you add files to the source directories. # See the instructions at the top of the file for more information. # LIB_H = ../lib/bitmap.h\ ../lib/copyright.h\ ../lib/debug.h\ ../lib/hash.h\ ../lib/libtest.h\ ../lib/list.h\ ../lib/sysdep.h\ ../lib/utility.h LIB_C = ../lib/bitmap.cc\ ../lib/debug.cc\ ../lib/hash.cc\ ../lib/libtest.cc\ ../lib/list.cc\ ../lib/sysdep.cc LIB_O = bitmap.o debug.o libtest.o sysdep.o MACHINE_H = ../machine/callback.h\ ../machine/interrupt.h\ ../machine/stats.h\ ../machine/timer.h\ ../machine/console.h\ ../machine/machine.h\ ../machine/mipssim.h\ ../machine/translate.h\ ../machine/network.h\ ../machine/disk.h MACHINE_C = ../machine/interrupt.cc\ ../machine/stats.cc\ ../machine/timer.cc\ ../machine/console.cc\ ../machine/machine.cc\ ../machine/mipssim.cc\ ../machine/translate.cc\ ../machine/network.cc\ ../machine/disk.cc MACHINE_O = interrupt.o stats.o timer.o console.o machine.o mipssim.o\ translate.o network.o disk.o THREAD_H = ../threads/alarm.h\ ../threads/kernel.h\ ../threads/main.h\ ../threads/scheduler.h\ ../threads/switch.h\ ../threads/synch.h\ ../threads/synchlist.h\ ../threads/thread.h THREAD_C = ../threads/alarm.cc\ ../threads/kernel.cc\ ../threads/main.cc\ ../threads/scheduler.cc\ ../threads/synch.cc\ ../threads/synchlist.cc\ ../threads/thread.cc THREAD_O = alarm.o kernel.o main.o scheduler.o synch.o thread.o USERPROG_H = ../userprog/addrspace.h\ ../userprog/syscall.h\ ../userprog/synchconsole.h\ ../userprog/noff.h USERPROG_C = ../userprog/addrspace.cc\ ../userprog/exception.cc\ ../userprog/synchconsole.cc USERPROG_O = addrspace.o exception.o synchconsole.o FILESYS_H =../filesys/directory.h \ ../filesys/filehdr.h\ ../filesys/filesys.h \ ../filesys/openfile.h\ ../filesys/pbitmap.h\ ../filesys/synchdisk.h FILESYS_C =../filesys/directory.cc\ ../filesys/filehdr.cc\ ../filesys/filesys.cc\ ../filesys/pbitmap.cc\ ../filesys/openfile.cc\ ../filesys/synchdisk.cc\ FILESYS_O =directory.o filehdr.o filesys.o pbitmap.o openfile.o synchdisk.o NETWORK_H = ../network/post.h NETWORK_C = ../network/post.cc NETWORK_O = post.o ################################################################## # You probably don't want to change anything below this point in # the file unless you are comfortable with GNU make and know what # you are doing... ################################################################## THREAD_S = ../threads/switch.s HFILES = $(LIB_H) $(MACHINE_H) $(THREAD_H) $(USERPROG_H) $(FILESYS_H) $(NETWORK_H) CFILES = $(LIB_C) $(MACHINE_C) $(THREAD_C) $(USERPROG_C) $(FILESYS_C) $(NETWORK_C) C_OFILES = $(LIB_O) $(MACHINE_O) $(THREAD_O) $(USERPROG_O) $(FILESYS_O) $(NETWORK_O) S_OFILES = switch.o OFILES = $(C_OFILES) $(S_OFILES) $(PROGRAM): $(OFILES) $(LD) $(OFILES) $(LDFLAGS) -o $(PROGRAM) $(C_OFILES): %.o: $(CC) $(CFLAGS) -c $< switch.o: ../threads/switch.s $(CPP) $(CPP_AS_FLAGS) -P $(INCPATH) $(HOSTCFLAGS) ../threads/switch.s > swtch.s $(AS) -o switch.o swtch.s depend: $(CFILES) $(HFILES) $(CC) $(INCPATH) $(DEFINES) $(HOSTCFLAGS) -DCHANGED -M $(CFILES) > makedep @echo '/^# DO NOT DELETE THIS LINE/+2,$$d' >eddep @echo '$$r makedep' >>eddep @echo 'w' >>eddep @echo 'q' >>eddep ed - Makefile.dep < eddep rm eddep makedep @echo '# DEPENDENCIES MUST END AT END OF FILE' >> Makefile.dep @echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >> Makefile.dep @echo '# see make depend above' >> Makefile.dep clean: $(RM) -f $(OFILES) $(RM) -f swtch.s distclean: clean $(RM) -f $(PROGRAM) $(RM) -f DISK_? $(RM) -f core $(RM) -f SOCKET_? include Makefile.dep

nachos/code/lib/copyright.h

/* Copyright (c) 1992-1996 The Regents of the University of California. All rights reserved. Permission to use, copy, modify, and distribute this software and its documentation for any purpose, without fee, and without written agreement is hereby granted, provided that the above copyright notice and the following two paragraphs appear in all copies of this software. IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */ #ifdef MAIN /* include the copyright message in every executable */ static char *copyright = "Copyright (c) 1992-1993 The Regents of the University of California. All rights reserved."; #endif // MAIN

nachos/code/lib/bitmap.h

// bitmap.h // Data structures defining a bitmap -- an array of bits each of which // can be either on or off. // // Represented as an array of unsigned integers, on which we do // modulo arithmetic to find the bit we are interested in. // // The bitmap can be parameterized with with the number of bits being // managed. // // Copyright (c) 1992-1996 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef BITMAP_H #define BITMAP_H #include "copyright.h" #include "utility.h" // Definitions helpful for representing a bitmap as an array of integers const int BitsInByte = 8; const int BitsInWord = sizeof(unsigned int) * BitsInByte; // The following class defines a "bitmap" -- an array of bits, // each of which can be independently set, cleared, and tested. // // Most useful for managing the allocation of the elements of an array -- // for instance, disk sectors, or main memory pages. // Each bit represents whether the corresponding sector or page is // in use or free. class Bitmap { public: Bitmap(int numItems); // Initialize a bitmap, with "numItems" bits // initially, all bits are cleared. ~Bitmap(); // De-allocate bitmap void Mark(int which); // Set the "nth" bit void Clear(int which); // Clear the "nth" bit bool Test(int which) const; // Is the "nth" bit set? int FindAndSet(); // Return the # of a clear bit, and as a side // effect, set the bit. // If no bits are clear, return -1. int NumClear() const; // Return the number of clear bits void Print() const; // Print contents of bitmap void SelfTest(); // Test whether bitmap is working protected: int numBits; // number of bits in the bitmap int numWords; // number of words of bitmap storage // (rounded up if numBits is not a // multiple of the number of bits in // a word) unsigned int *map; // bit storage }; #endif // BITMAP_H

nachos/code/lib/libtest.cc

nachos/code/lib/libtest.cc

// libtest.cc 
//  Driver code to call self-test routines for standard library
//  classes -- bitmaps, lists, sorted lists, and hash tables.
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include   "copyright.h"
#include   "libtest.h"
#include   "bitmap.h"
#include   "list.h"
#include   "hash.h"
#include   "sysdep.h"

//----------------------------------------------------------------------
// IntCompare
//  Compare two integers together.  Serves as the comparison
//  function for testing SortedLists
//----------------------------------------------------------------------

static   int  
IntCompare ( int  x ,   int  y )   {
     if   ( <  y )   return   - 1 ;
     else   if   ( ==  y )   return   0 ;
     else   return   1 ;
}

//----------------------------------------------------------------------
// HashInt, HashKey
//  Compute a hash function on an integer.  Serves as the
//  hashing function for testing HashTables.
//----------------------------------------------------------------------

static   unsigned   int  
HashInt ( int  key )   {
     return   ( unsigned   int )  key ;
}

//----------------------------------------------------------------------
// HashKey
//  Convert a string into an integer.  Serves as the function
//  to retrieve the key from the item in the hash table, for
//  testing HashTables.  Should be able to use "atoi" directly,
//  but some compilers complain about that.
//----------------------------------------------------------------------

static   int  
HashKey ( char   * str )   {
     return  atoi ( str );
}

// Array of values to be inserted into a List or SortedList. 
static   int  listTestVector []   =   {   9 ,   5 ,   7   };

// Array of values to be inserted into the HashTable
// There are enough here to force a ReHash().
static   char   * hashTestVector []   =   {   "0" ,   "1" ,   "2" ,   "3" ,   "4" ,   "5" ,   "6" ,
      "7" ,   "8" ,   "9" ,   "10" ,   "11" ,   "12" ,   "13" ,   "14" };

//----------------------------------------------------------------------
// LibSelfTest
//  Run self tests on bitmaps, lists, sorted lists, and 
//  hash tables.
//----------------------------------------------------------------------

void
LibSelfTest   ()   {
     Bitmap   * map  =   new   Bitmap ( 200 );
     List < int >   * list  =   new   List < int > ;
     SortedList < int >   * sortList  =   new   SortedList < int > ( IntCompare );
     HashTable < int ,   char   *>   * hashTable  =  
     new   HashTable < int ,   char   *> ( HashKey ,   HashInt );
    
        
    map -> SelfTest ();
    list -> SelfTest ( listTestVector ,   sizeof ( listTestVector ) / sizeof ( int ));
    sortList -> SelfTest ( listTestVector ,   sizeof ( listTestVector ) / sizeof ( int ));
    hashTable -> SelfTest ( hashTestVector ,   sizeof ( hashTestVector ) / sizeof ( char   * ));

     delete  map ;
     delete  list ;
     delete  sortList ;
     delete  hashTable ;
}

nachos/code/lib/debug.cc

nachos/code/lib/debug.cc

// debug.cc 
//  Debugging routines.  Allows users to control whether to 
//  print DEBUG statements, based on a command line argument.
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include   "copyright.h"
#include   "utility.h"
#include   "debug.h"  
#include   "string.h"

//----------------------------------------------------------------------
// Debug::Debug
//      Initialize so that only DEBUG messages with a flag in flagList 
//  will be printed.
//
//  If the flag is "+", we enable all DEBUG messages.
//
//  "flagList" is a string of characters for whose DEBUG messages are 
//      to be enabled.
//----------------------------------------------------------------------

Debug :: Debug ( char   * flagList )
{
    enableFlags  =  flagList ;
}


//----------------------------------------------------------------------
// Debug::IsEnabled
//      Return TRUE if DEBUG messages with "flag" are to be printed.
//----------------------------------------------------------------------

bool
Debug :: IsEnabled ( char  flag )
{
     if   ( enableFlags  !=  NULL )   {
     return   (( strchr ( enableFlags ,  flag )   !=   0 )  
         ||   ( strchr ( enableFlags ,   '+' )   !=   0 ));
     }   else   {
         return  FALSE ;
     }
}

nachos/code/lib/list.cc

nachos/code/lib/list.cc

// list.cc 
//      Routines to manage a singly linked list of "things".
//  Lists are implemented as templates so that we can store
//  anything on the list in a type-safe manner.
//
//  A "ListElement" is allocated for each item to be put on the
//  list; it is de-allocated when the item is removed. This means
//      we don't need to keep a "next" pointer in every object we
//      want to put on a list.
// 
//      NOTE: Mutual exclusion must be provided by the caller.
//      If you want a synchronized list, you must use the routines 
//  in synchlist.cc.
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include   "copyright.h"

//----------------------------------------------------------------------
// ListElement<T>::ListElement
//  Initialize a list element, so it can be added somewhere on a list.
//
//  "itm" is the thing to be put on the list.
//----------------------------------------------------------------------

template   < class  T >
ListElement < T >:: ListElement ( T itm )
{
     item  =  itm ;
     next  =  NULL ;     // always initialize to something!
}


//----------------------------------------------------------------------
// List<T>::List
//  Initialize a list, empty to start with.
//  Elements can now be added to the list.
//----------------------------------------------------------------------

template   < class  T >
List < T >:: List ()
{  
    first  =  last  =  NULL ;  
    numInList  =   0 ;
}

//----------------------------------------------------------------------
// List<T>::~List
//  Prepare a list for deallocation.  
//      This does *NOT* free list elements, nor does it
//      free the data those elements point to.
//      Normally, the list should be empty when this is called.
//----------------------------------------------------------------------

template   < class  T >
List < T >::~ List ()
{  
}

//----------------------------------------------------------------------
// List<T>::Append
//      Append an "item" to the end of the list.
//      
//  Allocate a ListElement to keep track of the item.
//      If the list is empty, then this will be the only element.
//  Otherwise, put it at the end.
//
//  "item" is the thing to put on the list.
//----------------------------------------------------------------------

template   < class  T >
void
List < T >:: Append ( T item )
{
     ListElement < T >   * element  =   new   ListElement < T > ( item );

    ASSERT ( ! this -> IsInList ( item ));
     if   ( IsEmpty ())   {          // list is empty
    first  =  element ;
    last  =  element ;
     }   else   {              // else put it after last
    last -> next  =  element ;
    last  =  element ;
     }
    numInList ++ ;
    ASSERT ( this -> IsInList ( item ));
}

//----------------------------------------------------------------------
// List<T>::Prepend
//  Same as Append, only put "item" on the front.
//----------------------------------------------------------------------

template   < class  T >
void
List < T >:: Prepend ( T item )
{
     ListElement < T >   * element  =   new   ListElement < T > ( item );

    ASSERT ( ! this -> IsInList ( item ));
     if   ( IsEmpty ())   {          // list is empty
    first  =  element ;
    last  =  element ;
     }   else   {              // else put it before first
    element -> next  =  first ;
    first  =  element ;
     }
    numInList ++ ;
    ASSERT ( this -> IsInList ( item ));
}

//----------------------------------------------------------------------
// List<T>::RemoveFront
//      Remove the first "item" from the front of the list.
//  List must not be empty.
// 
// Returns:
//  The removed item.
//----------------------------------------------------------------------

template   < class  T >
T
List < T >:: RemoveFront ()
{
     ListElement < T >   * element  =  first ;
    T thing ;

    ASSERT ( ! IsEmpty ());

    thing  =  first -> item ;
     if   ( first  ==  last )   {      // list had one item, now has none 
        first  =  NULL ;
    last  =  NULL ;
     }   else   {
        first  =  element -> next ;
     }
    numInList -- ;
     delete  element ;
     return  thing ;
}

//----------------------------------------------------------------------
// List<T>::Remove
//      Remove a specific item from the list.  Must be in the list!
//----------------------------------------------------------------------

template   < class  T >
void
List < T >:: Remove ( T item )
{
     ListElement < T >   * prev ,   * ptr ;
    T removed ;

    ASSERT ( this -> IsInList ( item ));

     // if first item on list is match, then remove from front
     if   ( item  ==  first -> item )   {   
        removed  =   RemoveFront ();
        ASSERT ( item  ==  removed );
     }   else   {
    prev  =  first ;
         for   ( ptr  =  first -> next ;  ptr  !=  NULL ;  prev  =  ptr ,  ptr  =  ptr -> next )   {
             if   ( item  ==  ptr -> item )   {
        prev -> next  =  ptr -> next ;
         if   ( prev -> next  ==  NULL )   {
            last  =  prev ;
         }
         delete  ptr ;
        numInList -- ;
         break ;
         }
         }
    ASSERT ( ptr  !=  NULL );      // should always find item!
     }
   ASSERT ( ! this -> IsInList ( item ));
}

//----------------------------------------------------------------------
// List<T>::IsInList
//      Return TRUE if the item is in the list.
//----------------------------------------------------------------------

template   < class  T >
bool
List < T >:: IsInList ( T item )   const
{  
     ListElement < T >   * ptr ;

     for   ( ptr  =  first ;  ptr  !=  NULL ;  ptr  =  ptr -> next )   {
         if   ( item  ==  ptr -> item )   {
             return  TRUE ;
         }
     }
     return  FALSE ;
}


//----------------------------------------------------------------------
// List<T>::Apply
//      Apply function to every item on a list.
//
//  "func" -- the function to apply
//----------------------------------------------------------------------

template   < class  T >
void
List < T >:: Apply ( void   ( * func )( T ))   const
{  
     ListElement < T >   * ptr ;

     for   ( ptr  =  first ;  ptr  !=  NULL ;  ptr  =  ptr -> next )   {
         ( * func )( ptr -> item );
     }
}


//----------------------------------------------------------------------
// SortedList::Insert
//      Insert an "item" into a list, so that the list elements are
//  sorted in increasing order.
//      
//  Allocate a ListElement to keep track of the item.
//      If the list is empty, then this will be the only element.
//  Otherwise, walk through the list, one element at a time,
//  to find where the new item should be placed.
//
//  "item" is the thing to put on the list. 
//----------------------------------------------------------------------

template   < class  T >
void
SortedList < T >:: Insert ( T item )
{
     ListElement < T >   * element  =   new   ListElement < T > ( item );
     ListElement < T >   * ptr ;          // keep track

    ASSERT ( ! this -> IsInList ( item ));
     if   ( this -> IsEmpty ())   {            // if list is empty, put at front
         this -> first  =  element ;
         this -> last  =  element ;
     }   else   if   ( compare ( item ,   this -> first -> item )   <   0 )   {    // item goes at front 
    element -> next  =   this -> first ;
     this -> first  =  element ;
     }   else   {          // look for first elt in list bigger than item
         for   ( ptr  =   this -> first ;  ptr -> next  !=  NULL ;  ptr  =  ptr -> next )   {
             if   ( compare ( item ,  ptr -> next -> item )   <   0 )   {
        element -> next  =  ptr -> next ;
            ptr -> next  =  element ;
         this -> numInList ++ ;
         return ;
         }
     }
     this -> last -> next  =  element ;       // item goes at end of list
     this -> last  =  element ;
     }
     this -> numInList ++ ;
    ASSERT ( this -> IsInList ( item ));
}

//----------------------------------------------------------------------
// List::SanityCheck
//      Test whether this is still a legal list.
//
//  Tests: do I get to last starting from first?
//         does the list have the right # of elements?
//----------------------------------------------------------------------

template   < class  T >
void  
List < T >:: SanityCheck ()   const
{
     ListElement < T >   * ptr ;
     int  numFound ;

     if   ( first  ==  NULL )   {
    ASSERT (( numInList  ==   0 )   &&   ( last  ==  NULL ));
     }   else   if   ( first  ==  last )   {
    ASSERT (( numInList  ==   1 )   &&   ( last -> next  ==  NULL ));
     }   else   {
         for   ( numFound  =   1 ,  ptr  =  first ;  ptr  !=  last ;  ptr  =  ptr -> next )   {
        numFound ++ ;
            ASSERT ( numFound  <=  numInList );    // prevent infinite loop
         }
        ASSERT ( numFound  ==  numInList );
        ASSERT ( last -> next  ==  NULL );
     }
}

//----------------------------------------------------------------------
// List::SelfTest
//      Test whether this module is working.
//----------------------------------------------------------------------

template   < class  T >
void  
List < T >:: SelfTest ( * p ,   int  numEntries )
{
     int  i ;
     ListIterator < T >   * iterator  =   new   ListIterator < T > ( this );

     SanityCheck ();
     // check various ways that list is empty
    ASSERT ( IsEmpty ()   &&   ( first  ==  NULL ));
     for   (;   ! iterator -> IsDone ();  iterator -> Next ())   {
    ASSERTNOTREACHED ();   // nothing on list
     }

     for   ( =   0 ;  i  <  numEntries ;  i ++ )   {
      Append ( p [ i ]);
     ASSERT ( this -> IsInList ( p [ i ]));
     ASSERT ( ! IsEmpty ());
      }
      SanityCheck ();

      // should be able to get out everything we put in
      for   ( =   0 ;  i  <  numEntries ;  i ++ )   {
      Remove ( p [ i ]);
         ASSERT ( ! this -> IsInList ( p [ i ]));
      }
     ASSERT ( IsEmpty ());
      SanityCheck ();
      delete  iterator ;
}

//----------------------------------------------------------------------
// SortedList::SanityCheck
//      Test whether this is still a legal sorted list.
//
//  Test: is the list sorted?
//----------------------------------------------------------------------

template   < class  T >
void  
SortedList < T >:: SanityCheck ()   const
{
     ListElement < T >   * prev ,   * ptr ;

     List < T >:: SanityCheck ();
     if   ( this -> first  !=   this -> last )   {
         for   ( prev  =   this -> first ,  ptr  =   this -> first -> next ;  ptr  !=  NULL ;  
                        prev  =  ptr ,  ptr  =  ptr -> next )   {
            ASSERT ( compare ( prev -> item ,  ptr -> item )   <=   0 );
         }
     }
}

//----------------------------------------------------------------------
// SortedList::SelfTest
//      Test whether this module is working.
//----------------------------------------------------------------------

template   < class  T >
void  
SortedList < T >:: SelfTest ( * p ,   int  numEntries )
{
     int  i ;
    T  * =   new  T [ numEntries ];

     List < T >:: SelfTest ( p ,  numEntries );

     for   ( =   0 ;  i  <  numEntries ;  i ++ )   {
      Insert ( p [ i ]);
     ASSERT ( this -> IsInList ( p [ i ]));
      }
      SanityCheck ();

      // should be able to get out everything we put in
      for   ( =   0 ;  i  <  numEntries ;  i ++ )   {
     q [ i ]   =   this -> RemoveFront ();
         ASSERT ( ! this -> IsInList ( q [ i ]));
      }
     ASSERT ( this -> IsEmpty ());

      // make sure everything came out in the right order
      for   ( =   0 ;  i  <   ( numEntries  -   1 );  i ++ )   {
     ASSERT ( compare ( q [ i ],  q [ +   1 ])   <=   0 );
      }
      SanityCheck ();

      delete  q ;
}

nachos/code/lib/debug.h

// debug.h // Data structures for debugging routines. // // The debugging routines allow the user to turn on selected // debugging messages, controllable from the command line arguments // passed to Nachos (-d). You are encouraged to add your own // debugging flags. Please.... // // Copyright (c) 1992-1996 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef DEBUG_H #define DEBUG_H #include "copyright.h" #include "utility.h" #include "sysdep.h" // The pre-defined debugging flags are: const char dbgAll = '+'; // turn on all debug messages const char dbgThread = 't'; // threads const char dbgSynch = 's'; // locks, semaphores, condition vars const char dbgInt = 'i'; // interrupt emulation const char dbgMach = 'm'; // machine emulation const char dbgDisk = 'd'; // disk emulation const char dbgFile = 'f'; // file system const char dbgAddr = 'a'; // address spaces const char dbgNet = 'n'; // network emulation const char dbgSys = 'u'; // systemcall class Debug { public: Debug(char *flagList); bool IsEnabled(char flag); private: char *enableFlags; // controls which DEBUG messages are printed }; extern Debug *debug; //---------------------------------------------------------------------- // DEBUG // If flag is enabled, print a message. //---------------------------------------------------------------------- #define DEBUG(flag,expr) \ if (!debug->IsEnabled(flag)) {} else { \ cerr << expr << "\n"; \ } //---------------------------------------------------------------------- // ASSERT // If condition is false, print a message and dump core. // Useful for documenting assumptions in the code. // // NOTE: needs to be a #define, to be able to print the location // where the error occurred. //---------------------------------------------------------------------- #define ASSERT(condition) \ if (condition) {} else { \ cerr << "Assertion failed: line " << __LINE__ << " file " << __FILE__ << "\n"; \ Abort(); \ } //---------------------------------------------------------------------- // ASSERTNOTREACHED // Print a message and dump core (equivalent to ASSERT(FALSE) without // making the compiler whine). Useful for documenting when // code should not be reached. // // NOTE: needs to be a #define, to be able to print the location // where the error occurred. //---------------------------------------------------------------------- #define ASSERTNOTREACHED() \ { \ cerr << "Assertion failed: line " << __LINE__ << " file " << __FILE__ << "\n"; \ Abort(); \ } //---------------------------------------------------------------------- // ASSERTUNIMPLEMENTED // Print a message that unimplemented code is executed and dump core //---------------------------------------------------------------------- #define UNIMPLEMENTED() \ { \ cerr << "Reached UNIMPLEMENTED function " << __FUNCTION__ << " in file: " \ << __FILE__ << " line: " << __LINE__ << ".\n"; \ } #endif // DEBUG_H

nachos/code/lib/hash.cc

nachos/code/lib/hash.cc

// hash.cc 
//      Routines to manage a self-expanding hash table of arbitrary things.
//  The hashing function is supplied by the objects being put into
//  the table; we use chaining to resolve hash conflicts.
//
//  The hash table is implemented as an array of sorted lists,
//  and we expand the hash table if the number of elements in the table
//  gets too big.
// 
//      NOTE: Mutual exclusion must be provided by the caller.
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

const   int   InitialBuckets   =   4 ;     // how big a hash table do we start with
const   int   ResizeRatio   =   3 ;    // when do we grow the hash table?
const   int   IncreaseSizeBy   =   4 ;     // how much do we grow table when needed?

#include   "copyright.h"

//----------------------------------------------------------------------
// HashTable<Key,T>::HashTable
//  Initialize a hash table, empty to start with.
//  Elements can now be added to the table.
//----------------------------------------------------------------------

template   < class   Key ,   class  T >
HashTable < Key , T >:: HashTable ( Key   ( * get )( T x ),   unsigned   ( * hFunc )( Key  x ))
{  
    numItems  =   0 ;
     InitBuckets ( InitialBuckets );
    getKey  =  get ;
    hash  =  hFunc ;
}

//----------------------------------------------------------------------
// HashTable<Key,T>::InitBuckets
//  Initialize the bucket array for a hash table.
//  Called by the constructor and by ReHash().
//----------------------------------------------------------------------

template   < class   Key ,   class  T >
void
HashTable < Key , T >:: InitBuckets ( int  sz )
{  
    numBuckets  =  sz ;
    buckets  =   new   Bucket [ numBuckets ];
     for   ( int  i  =   0 ;  i  <  sz ;  i ++ )   {
        buckets [ i ]   =   new   List < T > ;
     }
}

//----------------------------------------------------------------------
// HashTable<T>::~HashTable
//  Prepare a hash table for deallocation.  
//----------------------------------------------------------------------

template   < class   Key ,   class  T >
HashTable < Key , T >::~ HashTable ()
{  
    ASSERT ( IsEmpty ());        // make sure table is empty
     DeleteBuckets ( buckets ,  numBuckets );
}

//----------------------------------------------------------------------
// HashTable<Key,T>::DeleteBuckets
//  De-Initialize the bucket array for a hash table.
//  Called by the destructor and by ReHash().
//----------------------------------------------------------------------

template   < class   Key ,   class  T >
void
HashTable < Key , T >:: DeleteBuckets ( List < T >   ** table ,   int  sz )
{  
     for   ( int  i  =   0 ;  i  <  sz ;  i ++ )   {
         delete  table [ i ];
     }
     delete   []  table ;
}

//----------------------------------------------------------------------
// HashTable<Key,T>::HashValue
//      Return hash table bucket that would contain key.
//----------------------------------------------------------------------

template   < class   Key ,   class  T >
int
HashTable < Key ,  T >:: HashValue ( Key  key )   const  
{
     int  result  =   ( * hash )( key )   %  numBuckets ;
    ASSERT ( result  >=   0   &&  result  <  numBuckets );
     return  result ;
}

//----------------------------------------------------------------------
// HashTable<Key,T>::Insert
//      Put an item into the hashtable.
//      
//  Resize the table if the # of elements / # of buckets is too big.
//  Then allocate a HashElement to keep track of the key, item pair,
//  and add it to the right bucket.
//
//  "key" is the key we'll use to find this item.
//  "item" is the thing to put in the table.
//----------------------------------------------------------------------

template   < class   Key ,   class  T >
void
HashTable < Key , T >:: Insert ( T item )
{
     Key  key  =  getKey ( item );

    ASSERT ( ! IsInTable ( key ));

     if   (( numItems  /  numBuckets )   >=   ResizeRatio )   {
     ReHash ();
     }

    buckets [ HashValue ( key )] -> Append ( item );
    numItems ++ ;

    ASSERT ( IsInTable ( key ));
}

//----------------------------------------------------------------------
// HashTable<Key,T>::ReHash
//      Increase the size of the hashtable, by 
//    (i) making a new table
//    (ii) moving all the elements into the new table
//    (iii) deleting the old table
//----------------------------------------------------------------------

template   < class   Key ,   class  T >
void
HashTable < Key , T >:: ReHash ()
{
     Bucket   * oldTable  =  buckets ;
     int  oldSize  =  numBuckets ;
    T item ;

     SanityCheck ();
     InitBuckets ( numBuckets  *   IncreaseSizeBy );

     for   ( int  i  =   0 ;  i  <  oldSize ;  i ++ )   {
     while   ( ! oldTable [ i ] -> IsEmpty ())   {
        item  =  oldTable [ i ] -> RemoveFront ();
        buckets [ HashValue ( getKey ( item ))] -> Append ( item );
         }
     }
     DeleteBuckets ( oldTable ,  oldSize );
     SanityCheck ();
}

//----------------------------------------------------------------------
// HashTable<Key,T>::FindInBucket
//      Find an item in a hash table bucket, from it's key
//
//  "bucket" -- the list storing the item, if it's in the table 
//  "key" -- the key uniquely identifying the item
// 
// Returns:
//  Whether item is found, and if found, the item.
//----------------------------------------------------------------------

template   < class   Key ,   class  T >
bool
HashTable < Key , T >:: FindInBucket ( int  bucket ,  
                 Key  key ,  T  * itemPtr )   const
{
     ListIterator < T >  iterator ( buckets [ bucket ]);

     for   (;   ! iterator . IsDone ();  iterator . Next ())   {
     if   ( key  ==  getKey ( iterator . Item ()))   {   // found!
         * itemPtr  =  iterator . Item ();
         return  TRUE ;
         }
     }
     * itemPtr  =  NULL ;
     return  FALSE ;
}

//----------------------------------------------------------------------
// HashTable<Key,T>::Find
//      Find an item from the hash table.
// 
// Returns:
//  The item or NULL if not found. 
//----------------------------------------------------------------------

template   < class   Key ,   class  T >
bool
HashTable < Key , T >:: Find ( Key  key ,  T  * itemPtr )   const
{
     int  bucket  =   HashValue ( key );
    
     return   FindInBucket ( bucket ,  key ,  itemPtr );  
}

//----------------------------------------------------------------------
// HashTable<Key,T>::Remove
//      Remove an item from the hash table. The item must be in the table.
// 
// Returns:
//  The removed item.
//----------------------------------------------------------------------

template   < class   Key ,   class  T >
T
HashTable < Key , T >:: Remove ( Key  key )
{
     int  bucket  =   HashValue ( key );
    T item ;
     bool  found  =   FindInBucket ( bucket ,  key ,   & item );  

    ASSERT ( found );    // item must be in table

    buckets [ bucket ] -> Remove ( item );
    numItems -- ;

    ASSERT ( ! IsInTable ( key ));
     return  item ;
}


//----------------------------------------------------------------------
// HashTable<Key,T>::Apply
//      Apply function to every item in the hash table.
//
//  "func" -- the function to apply
//----------------------------------------------------------------------

template   < class   Key , class  T >
void
HashTable < Key , T >:: Apply ( void   ( * func )( T ))   const
{
     for   ( int  bucket  =   0 ;  bucket  <  numBuckets ;  bucket ++ )   {
        buckets [ bucket ] -> Apply ( func );
     }
}

//----------------------------------------------------------------------
// HashTable<Key,T>::FindNextFullBucket
//      Find the next bucket in the hash table that has any items in it.
//
//  "bucket" -- where to start looking for full buckets
//----------------------------------------------------------------------

template   < class   Key , class  T >
int
HashTable < Key , T >:: FindNextFullBucket ( int  bucket )   const
{  
     for   (;  bucket  <  numBuckets ;  bucket ++ )   {
     if   ( ! buckets [ bucket ] -> IsEmpty ())   {
          break ;
     }
     }
     return  bucket ;
}

//----------------------------------------------------------------------
// HashTable<Key,T>::SanityCheck
//      Test whether this is still a legal hash table.
//
//  Tests: are all the buckets legal?
//         does the table have the right # of elements?
//         do all the elements hash to where they are stored?
//----------------------------------------------------------------------

template   < class   Key ,   class  T >
void  
HashTable < Key , T >:: SanityCheck ()   const
{
     int  numFound  =   0 ;
     ListIterator < T >   * iterator ;

     for   ( int  i  =   0 ;  i  <  numBuckets ;  i ++ )   {
    buckets [ i ] -> SanityCheck ();
    numFound  +=  buckets [ i ] -> NumInList ();
    iterator  =   new   ListIterator < T > ( buckets [ i ]);
         for   (;   ! iterator -> IsDone ();  iterator -> Next ())   {
        ASSERT ( ==   HashValue ( getKey ( iterator -> Item ())));
         }
         delete  iterator ;
     }
    ASSERT ( numItems  ==  numFound );

}

//----------------------------------------------------------------------
// HashTable<Key,T>::SelfTest
//      Test whether this module is working.
//----------------------------------------------------------------------

template   < class   Key ,   class  T >
void  
HashTable < Key , T >:: SelfTest ( * p ,   int  numEntries )
{
     int  i ;
     HashIterator < Key ,  T >   * iterator  =   new   HashIterator < Key , T > ( this );
    
     SanityCheck ();
    ASSERT ( IsEmpty ());    // check that table is empty in various ways
     for   (;   ! iterator -> IsDone ();  iterator -> Next ())   {
    ASSERTNOTREACHED ();
     }
     delete  iterator ;

     for   ( =   0 ;  i  <  numEntries ;  i ++ )   {
         Insert ( p [ i ]);
        ASSERT ( IsInTable ( getKey ( p [ i ])));
        ASSERT ( ! IsEmpty ());
     }
    
     // should be able to get out everything we put in
     for   ( =   0 ;  i  <  numEntries ;  i ++ )   {   
        ASSERT ( Remove ( getKey ( p [ i ]))   ==  p [ i ]);
     }

    ASSERT ( IsEmpty ());
     SanityCheck ();
}


//----------------------------------------------------------------------
// HashIterator<Key,T>::HashIterator
//      Initialize a data structure to allow us to step through
//  every entry in a has table.
//----------------------------------------------------------------------

template   < class   Key ,   class  T >
HashIterator < Key , T >:: HashIterator ( HashTable < Key , T >   * tbl )  
{  
    table  =  tbl ;
    bucket  =  table -> FindNextFullBucket ( 0 );
    bucketIter  =  NULL ;
     if   ( bucket  <  table -> numBuckets )   {
    bucketIter  =   new   ListIterator < T > ( table -> buckets [ bucket ]);
     }
}

//----------------------------------------------------------------------
// HashIterator<Key,T>::Next
//      Update iterator to point to the next item in the table.
//----------------------------------------------------------------------

template   < class   Key , class  T >
void
HashIterator < Key , T >:: Next ()  
{  
    bucketIter -> Next ();
     if   ( bucketIter -> IsDone ())   {
     delete  bucketIter ;
    bucketIter  =  NULL ;
        bucket  =  table -> FindNextFullBucket ( ++ bucket );
         if   ( bucket  <  table -> numBuckets )   {
        bucketIter  =   new   ListIterator < T > ( table -> buckets [ bucket ]);
         }
     }
}

nachos/code/lib/list.h

// list.h // Data structures to manage LISP-like lists. // // As in LISP, a list can contain any type of data structure // as an item on the list: thread control blocks, // pending interrupts, etc. Allocation and deallocation of the // items on the list are to be done by the caller. // // Copyright (c) 1992-1996 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef LIST_H #define LIST_H #include "copyright.h" #include "debug.h" // The following class defines a "list element" -- which is // used to keep track of one item on a list. It is equivalent to a // LISP cell, with a "car" ("next") pointing to the next element on the list, // and a "cdr" ("item") pointing to the item on the list. // // This class is private to this module (and classes that inherit // from this module). Made public for notational convenience. template <class T> class ListElement { public: ListElement(T itm); // initialize a list element ListElement *next; // next element on list, NULL if this is last T item; // item on the list }; // The following class defines a "list" -- a singly linked list of // list elements, each of which points to a single item on the list. // The class has been tested only for primitive types (ints, pointers); // no guarantees it will work in general. For instance, all types // to be inserted into a list must have a "==" operator defined. template <class T> class ListIterator; template <class T> class List { public: List(); // initialize the list virtual ~List(); // de-allocate the list virtual void Prepend(T item);// Put item at the beginning of the list virtual void Append(T item); // Put item at the end of the list T Front() { return first->item; } // Return first item on list // without removing it T RemoveFront(); // Take item off the front of the list void Remove(T item); // Remove specific item from list bool IsInList(T item) const;// is the item in the list? unsigned int NumInList() { return numInList;}; // how many items in the list? bool IsEmpty() { return (numInList == 0); }; // is the list empty? void Apply(void (*f)(T)) const; // apply function to all elements in list virtual void SanityCheck() const; // has this list been corrupted? void SelfTest(T *p, int numEntries); // verify module is working protected: ListElement<T> *first; // Head of the list, NULL if list is empty ListElement<T> *last; // Last element of list int numInList; // number of elements in list friend class ListIterator<T>; }; // The following class defines a "sorted list" -- a singly linked list of // list elements, arranged so that "Remove" always returns the smallest // element. // All types to be inserted onto a sorted list must have a "Compare" // function defined: // int Compare(T x, T y) // returns -1 if x < y // returns 0 if x == y // returns 1 if x > y template <class T> class SortedList : public List<T> { public: SortedList(int (*comp)(T x, T y)) : List<T>() { compare = comp;}; ~SortedList() {}; // base class destructor called automatically void Insert(T item); // insert an item onto the list in sorted order void SanityCheck() const; // has this list been corrupted? void SelfTest(T *p, int numEntries); // verify module is working private: int (*compare)(T x, T y); // function for sorting list elements void Prepend(T item) { Insert(item); } // *pre*pending has no meaning // in a sorted list void Append(T item) { Insert(item); } // neither does *ap*pend }; // The following class can be used to step through a list. // Example code: // ListIterator<T> *iter(list); // // for (; !iter->IsDone(); iter->Next()) { // Operation on iter->Item() // } template <class T> class ListIterator { public: ListIterator(List<T> *list) { current = list->first; } // initialize an iterator bool IsDone() { return current == NULL; }; // return TRUE if we are at the end of the list T Item() { ASSERT(!IsDone()); return current->item; }; // return current element on list void Next() { current = current->next; }; // update iterator to point to next private: ListElement<T> *current; // where we are in the list }; #include "list.cc" // templates are really like macros // so needs to be included in every // file that uses the template #endif // LIST_H

nachos/code/lib/sysdep.h

// sysdep.h // System-dependent interface. Nachos uses the routines defined // here, rather than directly calling the UNIX library functions, to // simplify porting between versions of UNIX, and even to // other systems, such as MSDOS and the Macintosh. // // Copyright (c) 1992-1996 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef SYSDEP_H #define SYSDEP_H #include "copyright.h" #include <iostream> #include <stdlib.h> #include <stdio.h> #include <string.h> using namespace std; // Process control: abort, exit, and sleep extern void Abort(); extern void Exit(int exitCode); extern void Delay(int seconds); extern void UDelay(unsigned int usec);// rcgood - to avoid spinners. // Initialize system so that cleanUp routine is called when user hits ctl-C extern void CallOnUserAbort(void (*cleanup)(int)); // Initialize the pseudo random number generator extern void RandomInit(unsigned seed); extern unsigned int RandomNumber(); // Allocate, de-allocate an array, such that de-referencing // just beyond either end of the array will cause an error extern char *AllocBoundedArray(int size); extern void DeallocBoundedArray(char *p, int size); // Check file to see if there are any characters to be read. // If no characters in the file, return without waiting. extern bool PollFile(int fd); // File operations: open/read/write/lseek/close, and check for error // For simulating the disk and the console devices. extern int OpenForWrite(char *name); extern int OpenForReadWrite(char *name, bool crashOnError); extern void Read(int fd, char *buffer, int nBytes); extern int ReadPartial(int fd, char *buffer, int nBytes); extern void WriteFile(int fd, char *buffer, int nBytes); extern void Lseek(int fd, int offset, int whence); extern int Tell(int fd); extern int Close(int fd); extern bool Unlink(char *name); // Other C library routines that are used by Nachos. // These are assumed to be portable, so we don't include a wrapper. extern "C" { int atoi(const char *str); double atof(const char *str); int abs(int i); void bcopy(const void *s1, void *s2, size_t n); void bzero(void *s, size_t n); } // Interprocess communication operations, for simulating the network extern int OpenSocket(); extern void CloseSocket(int sockID); extern void AssignNameToSocket(char *socketName, int sockID); extern void DeAssignNameToSocket(char *socketName); extern bool PollSocket(int sockID); extern void ReadFromSocket(int sockID, char *buffer, int packetSize); extern void SendToSocket(int sockID, char *buffer, int packetSize,char *toName); #endif // SYSDEP_H

nachos/code/lib/libtest.h

// libtest.h // Defines self test module for standard library routines. // // Copyright (c) 1992-1996 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef LIBTEST_H #define LIBTEST_H #include "copyright.h" extern void LibSelfTest(); #endif // LIBTEST_H

nachos/code/lib/hash.h

// hash.h // Data structures to manage a hash table to relate arbitrary // keys to arbitrary values. A hash table allows efficient lookup // for the value given the key. // // I've only tested this implementation when both the key and the // value are primitive types (ints or pointers). There is no // guarantee that it will work in general. In particular, it // assumes that the "==" operator works for both keys and values. // // In addition, the key must have Hash() defined: // unsigned Hash(Key k); // returns a randomized # based on value of key // // The value must have a function defined to retrieve the key: // Key GetKey(T x); // // The hash table automatically resizes itself as items are // put into the table. The implementation uses chaining // to resolve hash conflicts. // // Allocation and deallocation of the items in the table are to // be done by the caller. // // Copyright (c) 1992-1996 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef HASH_H #define HASH_H #include "copyright.h" #include "list.h" // The following class defines a "hash table" -- allowing quick // lookup according to the hash function defined for the items // being put into the table. template <class Key,class T> class HashIterator; template <class Key, class T> class HashTable { public: HashTable(Key (*get)(T x), unsigned (*hFunc)(Key x)); // initialize a hash table ~HashTable(); // deallocate a hash table void Insert(T item); // Put item into hash table T Remove(Key key); // Remove item from hash table. bool Find(Key key, T *itemPtr) const; // Find an item from its key bool IsInTable(Key key) { T dummy; return Find(key, &dummy); } // Is the item in the table? bool IsEmpty() { return numItems == 0; } // does the table have anything in it void Apply(void (*f)(T)) const; // apply function to all elements in table void SanityCheck() const;// is this still a legal hash table? void SelfTest(T *p, int numItems); // is the module working? private: typedef List<T> *Bucket; Bucket *buckets; // the array of hash buckets int numBuckets; // the number of buckets int numItems; // the number of items in the table Key (*getKey)(T x); // get Key from value unsigned (*hash)(Key x); // the hash function void InitBuckets(int size);// initialize bucket array void DeleteBuckets(Bucket *table, int size); // deallocate bucket array int HashValue(Key key) const; // which bucket does the key hash to? void ReHash(); // expand the hash table bool FindInBucket(int bucket, Key key, T *itemPtr) const; // find item in bucket int FindNextFullBucket(int start) const; // find next full bucket starting from this one friend class HashIterator<Key,T>; }; // The following class can be used to step through a hash table -- // same interface as ListIterator. Example code: // HashIterator<Key, T> iter(table); // // for (; !iter->IsDone(); iter->Next()) { // Operation on iter->Item() // } template <class Key,class T> class HashIterator { public: HashIterator(HashTable<Key,T> *table); // initialize an iterator ~HashIterator() { if (bucketIter != NULL) delete bucketIter;}; // destruct an iterator bool IsDone() { return (bucket == table->numBuckets); }; // return TRUE if no more items in table T Item() { ASSERT(!IsDone()); return bucketIter->Item(); }; // return current item in table void Next(); // update iterator to point to next private: HashTable<Key,T> *table; // the hash table we're stepping through int bucket; // current bucket we are in ListIterator<T> *bucketIter; // where we are in the bucket }; #include "hash.cc" // templates are really like macros // so needs to be included in every // file that uses the template #endif // HASH_H

nachos/code/lib/sysdep.cc

nachos/code/lib/sysdep.cc

// sysdep.cc
//  Implementation of system-dependent interface.  Nachos uses the 
//  routines defined here, rather than directly calling the UNIX library,
//  to simplify porting between versions of UNIX, and even to
//  other systems, such as MSDOS.
//
//  On UNIX, almost all of these routines are simple wrappers
//  for the underlying UNIX system calls.
//
//  NOTE: all of these routines refer to operations on the underlying
//  host machine (e.g., the DECstation, SPARC, etc.), supporting the 
//  Nachos simulation code.  Nachos implements similar operations,
//  (such as opening a file), but those are implemented in terms
//  of hardware devices, which are simulated by calls to the underlying
//  routines in the host workstation OS.
//
//  This file includes lots of calls to C routines.  C++ requires
//  us to wrap all C definitions with a "extern "C" block".
//  This prevents the internal forms of the names from being
//  changed by the C++ compiler.
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include   "copyright.h"
#include   "debug.h"
#include   "sysdep.h"
#include   < stdlib . h >
#include   < unistd . h >
#include   < sys / time . h >
#include   < sys / file . h >
#include   < sys / socket . h >
#include   < sys / un . h >
#include   < cerrno >

#ifdef  SOLARIS
// KMS
// for open()
#include   < fcntl . h >
#endif

#ifdef  LINUX      // at this point, linux doesn't support mprotect 
#define  NO_MPROT     
#endif
#ifdef  DOS   // neither does DOS
#define  NO_MPROT
#endif

extern   "C"   {
#include   < signal . h >
#include   < sys / types . h >

#ifndef  NO_MPROT 
#include   < sys / mman . h >
#endif

// UNIX routines called by procedures in this file 

#if  defined CYGWIN
  size_t getpagesize ( void );
#else
  int  getpagesize ( void );
#endif
unsigned  sleep ( unsigned );
//#ifdef SOLARIS
//int usleep(useconds_t);
//#else
//void usleep(unsigned int);  // rcgood - to avoid spinning processes.
//#endif


#ifndef  NO_MPROT    

#ifdef  OSF
#define  OSF_OR_AIX
#endif
#ifdef  AIX
#define  OSF_OR_AIX
#endif

#ifdef  OSF_OR_AIX
int  mprotect ( const   void   * ,   long   unsigned   int ,   int );
#else
int  mprotect ( char   * ,   unsigned   int ,   int );
#endif
#endif

#if  defined ( BSD )   ||  defined ( SOLARIS )   ||  defined ( LINUX )
//KMS
// added Solaris and LINUX
int  select ( int  nfds ,  fd_set  * readfds ,  fd_set  * writefds ,  fd_set  * exceptfds ,
              struct  timeval  * timeout );
#else
int  select ( int  numBits ,   void   * readFds ,   void   * writeFds ,   void   * exceptFds ,  
     struct  timeval  * timeout );
#endif

int  socket ( int ,   int ,   int );

#if  defined ( SUNOS )   ||  defined ( ULTRIX )
long  tell ( int );
int  bind  ( int ,   const   void * ,   int );
int  recvfrom  ( int ,   void * ,   int ,   int ,   void * ,   int   * );
int  sendto  ( int ,   const   void * ,   int ,   int ,   void * ,   int );
#endif

}

//----------------------------------------------------------------------
// CallOnUserAbort
//  Arrange that "func" will be called when the user aborts (e.g., by
//  hitting ctl-C.
//----------------------------------------------------------------------

void  
CallOnUserAbort ( void   ( * func )( int ))
{
     ( void ) signal ( SIGINT ,  func );
}

//----------------------------------------------------------------------
// Delay
//  Put the UNIX process running Nachos to sleep for x seconds,
//  to give the user time to start up another invocation of Nachos
//  in a different UNIX shell.
//----------------------------------------------------------------------

void  
Delay ( int  seconds )
{
     ( void )  sleep (( unsigned )  seconds );
}

//----------------------------------------------------------------------
// UDelay
//  Put the UNIX process running Nachos to sleep for x microseconds,
//  to prevent an idle Nachos process from spinning...
//----------------------------------------------------------------------

void  
UDelay ( unsigned   int  useconds )
{
//#ifdef SOLARIS
//   usleep(useconds_t useconds);
//#else
//   usleep(useconds);
//#endif /* SOLARIS */

}

//----------------------------------------------------------------------
// Abort
//  Quit and drop core.
//----------------------------------------------------------------------

void  
Abort ()
{
    abort ();
}

//----------------------------------------------------------------------
// Exit
//  Quit without dropping core.
//----------------------------------------------------------------------

void  
Exit ( int  exitCode )
{
    exit ( exitCode );
}

//----------------------------------------------------------------------
// RandomInit
//  Initialize the pseudo-random number generator.  We use the
//  now obsolete "srand" and "rand" because they are more portable!
//----------------------------------------------------------------------

void  
RandomInit ( unsigned  seed )
{
    srand ( seed );
}

//----------------------------------------------------------------------
// RandomNumber
//  Return a pseudo-random number.
//----------------------------------------------------------------------

unsigned   int  
RandomNumber ()
{
     return  rand ();
}

//----------------------------------------------------------------------
// AllocBoundedArray
//  Return an array, with the two pages just before 
//  and after the array unmapped, to catch illegal references off
//  the end of the array.  Particularly useful for catching overflow
//  beyond fixed-size thread execution stacks.
//
//  Note: Just return the useful part!
//
//  "size" -- amount of useful space needed (in bytes)
//----------------------------------------------------------------------

char   *  
AllocBoundedArray ( int  size )
{
#ifdef  NO_MPROT
     return   new   char [ size ];
#else
     int  pgSize  =  getpagesize ();
     char   * ptr  =   new   char [ pgSize  *   2   +  size ];

    mprotect ( ptr ,  pgSize ,   0 );
    mprotect ( ptr  +  pgSize  +  size ,  pgSize ,   0 );
     return  ptr  +  pgSize ;
#endif
}

//----------------------------------------------------------------------
// DeallocBoundedArray
//  Deallocate an array of integers, unprotecting its two boundary pages.
//
//  "ptr" -- the array to be deallocated
//  "size" -- amount of useful space in the array (in bytes)
//----------------------------------------------------------------------

#ifdef  NO_MPROT
void  
DeallocBoundedArray ( char   * ptr ,   int   /* size */ )
{
     delete   []  ptr ;
}
#else
void  
DeallocBoundedArray ( char   * ptr ,   int  size )
{
     int  pgSize  =  getpagesize ();

    mprotect ( ptr  -  pgSize ,  pgSize ,  PROT_READ  |  PROT_WRITE  |  PROT_EXEC );
    mprotect ( ptr  +  size ,  pgSize ,  PROT_READ  |  PROT_WRITE  |  PROT_EXEC );
     delete   []   ( ptr  -  pgSize );
}
#endif

//----------------------------------------------------------------------
// PollFile
//  Check open file or open socket to see if there are any 
//  characters that can be read immediately.  If so, read them
//  in, and return TRUE.
//
//  "fd" -- the file descriptor of the file to be polled
//----------------------------------------------------------------------

bool
PollFile ( int  fd )
{
#if  defined ( SOLARIS )   ||  defined ( LINUX )
// KMS
    fd_set rfd , wfd , xfd ;
#else
     int  rfd  =   ( 1   <<  fd ),  wfd  =   0 ,  xfd  =   0 ;
#endif
     int  retVal ;
     struct  timeval pollTime ;

#if  defined ( SOLARIS )   ||  defined ( LINUX )
// KMS
    FD_ZERO ( & rfd );
    FD_ZERO ( & wfd );
    FD_ZERO ( & xfd );
    FD_SET ( fd , & rfd );
#endif

// don't wait if there are no characters on the file
    pollTime . tv_sec  =   0 ;
    pollTime . tv_usec  =   0 ;

// poll file or socket
#if  defined ( BSD )
    retVal  =  select ( 32 ,   ( fd_set * ) & rfd ,   ( fd_set * ) & wfd ,   ( fd_set * ) & xfd ,   & pollTime );
#elif  defined ( SOLARIS )   ||  defined ( LINUX )
     // KMS
    retVal  =  select ( 32 ,   & rfd ,   & wfd ,   & xfd ,   & pollTime );
#else
    retVal  =  select ( 32 ,   & rfd ,   & wfd ,   & xfd ,   & pollTime );
#endif

    ASSERT (( retVal  ==   0 )   ||   ( retVal  ==   1 ));
     if   ( retVal  ==   0 )
     return  FALSE ;                         // no char waiting to be read
     return  TRUE ;
}

//----------------------------------------------------------------------
// OpenForWrite
//  Open a file for writing.  Create it if it doesn't exist; truncate it 
//  if it does already exist.  Return the file descriptor.
//
//  "name" -- file name
//----------------------------------------------------------------------

int
OpenForWrite ( char   * name )
{
     int  fd  =  open ( name ,  O_RDWR | O_CREAT | O_TRUNC ,   0666 );

    ASSERT ( fd  >=   0 );  
     return  fd ;
}

//----------------------------------------------------------------------
// OpenForReadWrite
//  Open a file for reading or writing.
//  Return the file descriptor, or error if it doesn't exist.
//
//  "name" -- file name
//----------------------------------------------------------------------

int
OpenForReadWrite ( char   * name ,   bool  crashOnError )
{
     int  fd  =  open ( name ,  O_RDWR ,   0 );

    ASSERT ( ! crashOnError  ||  fd  >=   0 );
     return  fd ;
}

//----------------------------------------------------------------------
// Read
//  Read characters from an open file.  Abort if read fails.
//----------------------------------------------------------------------

void
Read ( int  fd ,   char   * buffer ,   int  nBytes )
{
     int  retVal  =  read ( fd ,  buffer ,  nBytes );
    ASSERT ( retVal  ==  nBytes );
}

//----------------------------------------------------------------------
// ReadPartial
//  Read characters from an open file, returning as many as are
//  available.
//----------------------------------------------------------------------

int
ReadPartial ( int  fd ,   char   * buffer ,   int  nBytes )
{
     return  read ( fd ,  buffer ,  nBytes );
}


//----------------------------------------------------------------------
// WriteFile
//  Write characters to an open file.  Abort if write fails.
//----------------------------------------------------------------------

void
WriteFile ( int  fd ,   char   * buffer ,   int  nBytes )
{
     int  retVal  =  write ( fd ,  buffer ,  nBytes );
    ASSERT ( retVal  ==  nBytes );
}

//----------------------------------------------------------------------
// Lseek
//  Change the location within an open file.  Abort on error.
//----------------------------------------------------------------------

void  
Lseek ( int  fd ,   int  offset ,   int  whence )
{
     int  retVal  =  lseek ( fd ,  offset ,  whence );
    ASSERT ( retVal  >=   0 );
}

//----------------------------------------------------------------------
// Tell
//  Report the current location within an open file.
//----------------------------------------------------------------------

int  
Tell ( int  fd )
{
#if  defined ( BSD )   ||  defined ( SOLARIS )   ||  defined ( LINUX )
     return  lseek ( fd , 0 , SEEK_CUR );   // 386BSD doesn't have the tell() system call
                                  // neither do Solaris and Linux  -KMS
#else
     return  tell ( fd );
#endif
}


//----------------------------------------------------------------------
// Close
//  Close a file.  Abort on error.
//----------------------------------------------------------------------

int  
Close ( int  fd )
{
     int  retVal  =  close ( fd );
    ASSERT ( retVal  >=   0 );  
     return  retVal ;
}

//----------------------------------------------------------------------
// Unlink
//  Delete a file.
//----------------------------------------------------------------------

bool  
Unlink ( char   * name )
{
     return  unlink ( name );
}

//----------------------------------------------------------------------
// OpenSocket
//  Open an interprocess communication (IPC) connection.  For now, 
//  just open a datagram port where other Nachos (simulating 
//  workstations on a network) can send messages to this Nachos.
//----------------------------------------------------------------------

int
OpenSocket ()
{
     int  sockID ;
    
    sockID  =  socket ( AF_UNIX ,  SOCK_DGRAM ,   0 );
    ASSERT ( sockID  >=   0 );

     return  sockID ;
}

//----------------------------------------------------------------------
// CloseSocket
//  Close the IPC connection. 
//----------------------------------------------------------------------

void
CloseSocket ( int  sockID )
{
     ( void )  close ( sockID );
}

//----------------------------------------------------------------------
// InitSocketName
//  Initialize a UNIX socket address -- magical!
//----------------------------------------------------------------------

static   void  
InitSocketName ( struct  sockaddr_un  * uname ,   char   * name )
{
    uname -> sun_family  =  AF_UNIX ;
    strcpy ( uname -> sun_path ,  name );
}

//----------------------------------------------------------------------
// AssignNameToSocket
//  Give a UNIX file name to the IPC port, so other instances of Nachos
//  can locate the port. 
//----------------------------------------------------------------------

void
AssignNameToSocket ( char   * socketName ,   int  sockID )
{
     struct  sockaddr_un uName ;
     int  retVal ;

     ( void )  unlink ( socketName );      // in case it's still around from last time

     InitSocketName ( & uName ,  socketName );
    retVal  =  bind ( sockID ,   ( struct  sockaddr  * )   & uName ,   sizeof ( uName ));
    ASSERT ( retVal  >=   0 );
    DEBUG ( dbgNet ,   "Created socket "   <<  socketName );
}

//----------------------------------------------------------------------
// DeAssignNameToSocket
//  Delete the UNIX file name we assigned to our IPC port, on cleanup.
//----------------------------------------------------------------------
void
DeAssignNameToSocket ( char   * socketName )
{
     ( void )  unlink ( socketName );
}

//----------------------------------------------------------------------
// PollSocket
//  Return TRUE if there are any messages waiting to arrive on the
//  IPC port.
//----------------------------------------------------------------------
bool
PollSocket ( int  sockID )
{
     return   PollFile ( sockID );      // on UNIX, socket ID's are just file ID's
}

//----------------------------------------------------------------------
// ReadFromSocket
//  Read a fixed size packet off the IPC port.  Abort on error.
//----------------------------------------------------------------------
void
ReadFromSocket ( int  sockID ,   char   * buffer ,   int  packetSize )
{
     int  retVal ;
     struct  sockaddr_un uName ;
#ifdef  LINUX
    socklen_t size  =   sizeof ( uName );
#else
     int  size  =   sizeof ( uName );
#endif
   
    retVal  =  recvfrom ( sockID ,  buffer ,  packetSize ,   0 ,
                    ( struct  sockaddr  * )   & uName ,   & size );

     if   ( retVal  !=  packetSize )   {
        perror ( "in recvfrom" );
#if  defined CYGWIN
    cerr  <<   "called with "   <<  packetSize  <<   ", got back "   <<  retVal 
                         <<   ", and "   <<   "\n" ;
#else    
        cerr  <<   "called with "   <<  packetSize  <<   ", got back "   <<  retVal 
                         <<   ", and "   <<  errno  <<   "\n" ;
#endif  
     }
    ASSERT ( retVal  ==  packetSize );
}

//----------------------------------------------------------------------
//    modified by KMS to add retry...
// SendToSocket
//  Transmit a fixed size packet to another Nachos' IPC port.
//  Try 10 times with a one second delay between attempts.
//      This is useful, e.g., to give the other socket a chance
//      to get set up.
//      Terminate if we still fail after 10 tries.
//----------------------------------------------------------------------
void
SendToSocket ( int  sockID ,   char   * buffer ,   int  packetSize ,   char   * toName )
{
     struct  sockaddr_un uName ;
     int  retVal ;
     int  retryCount ;

     InitSocketName ( & uName ,  toName );

     for ( retryCount = 0 ; retryCount  <   10 ; retryCount ++ )   {
      retVal  =  sendto ( sockID ,  buffer ,  packetSize ,   0 ,  
             ( struct  sockaddr  * )   & uName ,   sizeof ( uName ));
       if   ( retVal  ==  packetSize )   return ;
       // if we did not succeed, we should see a negative
       // return value indicating complete failure.  If we
       // don't, something fishy is going on...
      ASSERT ( retVal  <   0 );
       // wait a second before trying again
       Delay ( 1 );
     }
     // At this point, we have failed many times
     // The most common reason for this is that the target machine
     // has halted and its socket no longer exists.
     // We simply do nothing (drop the packet).
     // This may mask other kinds of failures, but it is the
     // right thing to do in the common case.
}

nachos/code/lib/utility.h

// utility.h // Miscellaneous useful definitions. // // Copyright (c) 1992-1996 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef UTILITY_H #define UTILITY_H #include "copyright.h" // Miscellaneous useful routines #define NULL 0 #define TRUE true #define FALSE false // #define bool int // necessary on the Mac? #define min(a,b) (((a) < (b)) ? (a) : (b)) #define max(a,b) (((a) > (b)) ? (a) : (b)) // Divide and either round up or down #define divRoundDown(n,s) ((n) / (s)) #define divRoundUp(n,s) (((n) / (s)) + ((((n) % (s)) > 0) ? 1 : 0)) // This declares the type "VoidFunctionPtr" to be a "pointer to a // function taking an arbitrary pointer argument and returning nothing". With // such a function pointer (say it is "func"), we can call it like this: // // (*func) ("help!"); // // This is used by Thread::Fork as well as a couple of other places. typedef void (*VoidFunctionPtr)(void *arg); typedef void (*VoidNoArgFunctionPtr)(); #endif // UTILITY_H

nachos/code/lib/bitmap.cc

nachos/code/lib/bitmap.cc

// bitmap.cc
//  Routines to manage a bitmap -- an array of bits each of which
//  can be either on or off.  Represented as an array of integers.
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include   "copyright.h"
#include   "debug.h"
#include   "bitmap.h"

//----------------------------------------------------------------------
// BitMap::BitMap
//  Initialize a bitmap with "numItems" bits, so that every bit is clear.
//  it can be added somewhere on a list.
//
//  "numItems" is the number of bits in the bitmap.
//----------------------------------------------------------------------

Bitmap :: Bitmap ( int  numItems )  
{  
     int  i ;

    ASSERT ( numItems  >   0 );

    numBits  =  numItems ;
    numWords  =  divRoundUp ( numBits ,   BitsInWord );
    map  =   new   unsigned   int [ numWords ];
     for   ( =   0 ;  i  <  numWords ;  i ++ )   {
    map [ i ]   =   0 ;       // initialize map to keep Purify happy
     }
     for   ( =   0 ;  i  <  numBits ;  i ++ )   {
         Clear ( i );
     }
}

//----------------------------------------------------------------------
// Bitmap::~Bitmap
//  De-allocate a bitmap.
//----------------------------------------------------------------------

Bitmap ::~ Bitmap ()
{  
     delete  map ;
}

//----------------------------------------------------------------------
// Bitmap::Set
//  Set the "nth" bit in a bitmap.
//
//  "which" is the number of the bit to be set.
//----------------------------------------------------------------------

void
Bitmap :: Mark ( int  which )  
{  
    ASSERT ( which  >=   0   &&  which  <  numBits );

    map [ which  /   BitsInWord ]   |=   1   <<   ( which  %   BitsInWord );

    ASSERT ( Test ( which ));
}
    
//----------------------------------------------------------------------
// Bitmap::Clear
//  Clear the "nth" bit in a bitmap.
//
//  "which" is the number of the bit to be cleared.
//----------------------------------------------------------------------

void  
Bitmap :: Clear ( int  which )  
{
    ASSERT ( which  >=   0   &&  which  <  numBits );

    map [ which  /   BitsInWord ]   &=   ~ ( 1   <<   ( which  %   BitsInWord ));

    ASSERT ( ! Test ( which ));
}

//----------------------------------------------------------------------
// Bitmap::Test
//  Return TRUE if the "nth" bit is set.
//
//  "which" is the number of the bit to be tested.
//----------------------------------------------------------------------

bool  
Bitmap :: Test ( int  which )   const
{
    ASSERT ( which  >=   0   &&  which  <  numBits );
    
     if   ( map [ which  /   BitsInWord ]   &   ( 1   <<   ( which  %   BitsInWord )))   {
     return  TRUE ;
     }   else   {
     return  FALSE ;
     }
}

//----------------------------------------------------------------------
// Bitmap::FindAndSet
//  Return the number of the first bit which is clear.
//  As a side effect, set the bit (mark it as in use).
//  (In other words, find and allocate a bit.)
//
//  If no bits are clear, return -1.
//----------------------------------------------------------------------

int  
Bitmap :: FindAndSet ()  
{
     for   ( int  i  =   0 ;  i  <  numBits ;  i ++ )   {
     if   ( ! Test ( i ))   {
         Mark ( i );
         return  i ;
     }
     }
     return   - 1 ;
}

//----------------------------------------------------------------------
// Bitmap::NumClear
//  Return the number of clear bits in the bitmap.
//  (In other words, how many bits are unallocated?)
//----------------------------------------------------------------------

int  
Bitmap :: NumClear ()   const
{
     int  count  =   0 ;

     for   ( int  i  =   0 ;  i  <  numBits ;  i ++ )   {
     if   ( ! Test ( i ))   {
        count ++ ;
     }
     }
     return  count ;
}

//----------------------------------------------------------------------
// Bitmap::Print
//  Print the contents of the bitmap, for debugging.
//
//  Could be done in a number of ways, but we just print the #'s of
//  all the bits that are set in the bitmap.
//----------------------------------------------------------------------

void
Bitmap :: Print ()   const
{
    cout  <<   "Bitmap set:\n" ;  
     for   ( int  i  =   0 ;  i  <  numBits ;  i ++ )   {
     if   ( Test ( i ))   {
        cout  <<  i  <<   ", " ;
     }
     }
    cout  <<   "\n" ;  
}


//----------------------------------------------------------------------
// Bitmap::SelfTest
//  Test whether this module is working.
//----------------------------------------------------------------------

void
Bitmap :: SelfTest ()  
{
     int  i ;
    
    ASSERT ( numBits  >=   BitsInWord );    // bitmap must be big enough

    ASSERT ( NumClear ()   ==  numBits );    // bitmap must be empty
    ASSERT ( FindAndSet ()   ==   0 );
     Mark ( 31 );
    ASSERT ( Test ( 0 )   &&   Test ( 31 ));

    ASSERT ( FindAndSet ()   ==   1 );
     Clear ( 0 );
     Clear ( 1 );
     Clear ( 31 );

     for   ( =   0 ;  i  <  numBits ;  i ++ )   {
         Mark ( i );
     }
    ASSERT ( FindAndSet ()   ==   - 1 );       // bitmap should be full!
     for   ( =   0 ;  i  <  numBits ;  i ++ )   {
         Clear ( i );
     }
}

nachos/code/filesys/directory.h

// directory.h // Data structures to manage a UNIX-like directory of file names. // // A directory is a table of pairs: <file name, sector #>, // giving the name of each file in the directory, and // where to find its file header (the data structure describing // where to find the file's data blocks) on disk. // // We assume mutual exclusion is provided by the caller. // // Copyright (c) 1992-1993 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #include "copyright.h" #ifndef DIRECTORY_H #define DIRECTORY_H #include "openfile.h" #define FileNameMaxLen 9 // for simplicity, we assume // file names are <= 9 characters long // The following class defines a "directory entry", representing a file // in the directory. Each entry gives the name of the file, and where // the file's header is to be found on disk. // // Internal data structures kept public so that Directory operations can // access them directly. class DirectoryEntry { public: bool inUse; // Is this directory entry in use? int sector; // Location on disk to find the // FileHeader for this file char name[FileNameMaxLen + 1]; // Text name for file, with +1 for // the trailing '\0' }; // The following class defines a UNIX-like "directory". Each entry in // the directory describes a file, and where to find it on disk. // // The directory data structure can be stored in memory, or on disk. // When it is on disk, it is stored as a regular Nachos file. // // The constructor initializes a directory structure in memory; the // FetchFrom/WriteBack operations shuffle the directory information // from/to disk. class Directory { public: Directory(int size); // Initialize an empty directory // with space for "size" files ~Directory(); // De-allocate the directory void FetchFrom(OpenFile *file); // Init directory contents from disk void WriteBack(OpenFile *file); // Write modifications to // directory contents back to disk int Find(char *name); // Find the sector number of the // FileHeader for file: "name" bool Add(char *name, int newSector); // Add a file name into the directory bool Remove(char *name); // Remove a file from the directory void List(); // Print the names of all the files // in the directory void Print(); // Verbose print of the contents // of the directory -- all the file // names and their contents. private: int tableSize; // Number of directory entries DirectoryEntry *table; // Table of pairs: // <file name, file header location> int FindIndex(char *name); // Find the index into the directory // table corresponding to "name" }; #endif // DIRECTORY_H

nachos/code/filesys/openfile.h

// openfile.h // Data structures for opening, closing, reading and writing to // individual files. The operations supported are similar to // the UNIX ones -- type 'man open' to the UNIX prompt. // // There are two implementations. One is a "STUB" that directly // turns the file operations into the underlying UNIX operations. // (cf. comment in filesys.h). // // The other is the "real" implementation, that turns these // operations into read and write disk sector requests. // In this baseline implementation of the file system, we don't // worry about concurrent accesses to the file system // by different threads. // // Copyright (c) 1992-1993 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef OPENFILE_H #define OPENFILE_H #include "copyright.h" #include "utility.h" #include "sysdep.h" #ifdef FILESYS_STUB // Temporarily implement calls to // Nachos file system as calls to UNIX! // See definitions listed under #else class OpenFile { public: OpenFile(int f) { file = f; currentOffset = 0; } // open the file ~OpenFile() { Close(file); } // close the file int ReadAt(char *into, int numBytes, int position) { Lseek(file, position, 0); return ReadPartial(file, into, numBytes); } int WriteAt(char *from, int numBytes, int position) { Lseek(file, position, 0); WriteFile(file, from, numBytes); return numBytes; } int Read(char *into, int numBytes) { int numRead = ReadAt(into, numBytes, currentOffset); currentOffset += numRead; return numRead; } int Write(char *from, int numBytes) { int numWritten = WriteAt(from, numBytes, currentOffset); currentOffset += numWritten; return numWritten; } int Length() { Lseek(file, 0, 2); return Tell(file); } private: int file; int currentOffset; }; #else // FILESYS class FileHeader; class OpenFile { public: OpenFile(int sector); // Open a file whose header is located // at "sector" on the disk ~OpenFile(); // Close the file void Seek(int position); // Set the position from which to // start reading/writing -- UNIX lseek int Read(char *into, int numBytes); // Read/write bytes from the file, // starting at the implicit position. // Return the # actually read/written, // and increment position in file. int Write(char *from, int numBytes); int ReadAt(char *into, int numBytes, int position); // Read/write bytes from the file, // bypassing the implicit position. int WriteAt(char *from, int numBytes, int position); int Length(); // Return the number of bytes in the // file (this interface is simpler // than the UNIX idiom -- lseek to // end of file, tell, lseek back private: FileHeader *hdr; // Header for this file int seekPosition; // Current position within the file }; #endif // FILESYS #endif // OPENFILE_H

nachos/code/filesys/synchdisk.cc

nachos/code/filesys/synchdisk.cc

// synchdisk.cc 
//  Routines to synchronously access the disk.  The physical disk 
//  is an asynchronous device (disk requests return immediately, and
//  an interrupt happens later on).  This is a layer on top of
//  the disk providing a synchronous interface (requests wait until
//  the request completes).
//
//  Use a semaphore to synchronize the interrupt handlers with the
//  pending requests.  And, because the physical disk can only
//  handle one operation at a time, use a lock to enforce mutual
//  exclusion.
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include   "copyright.h"
#include   "synchdisk.h"


//----------------------------------------------------------------------
// SynchDisk::SynchDisk
//  Initialize the synchronous interface to the physical disk, in turn
//  initializing the physical disk.
//
//----------------------------------------------------------------------

SynchDisk :: SynchDisk ()
{
    semaphore  =   new   Semaphore ( "synch disk" ,   0 );
    lock  =   new   Lock ( "synch disk lock" );
    disk  =   new   Disk ( this );
}

//----------------------------------------------------------------------
// SynchDisk::~SynchDisk
//  De-allocate data structures needed for the synchronous disk
//  abstraction.
//----------------------------------------------------------------------

SynchDisk ::~ SynchDisk ()
{
     delete  disk ;
     delete  lock ;
     delete  semaphore ;
}

//----------------------------------------------------------------------
// SynchDisk::ReadSector
//  Read the contents of a disk sector into a buffer.  Return only
//  after the data has been read.
//
//  "sectorNumber" -- the disk sector to read
//  "data" -- the buffer to hold the contents of the disk sector
//----------------------------------------------------------------------

void
SynchDisk :: ReadSector ( int  sectorNumber ,   char *  data )
{
    lock -> Acquire ();              // only one disk I/O at a time
    disk -> ReadRequest ( sectorNumber ,  data );
    semaphore -> P ();           // wait for interrupt
    lock -> Release ();
}

//----------------------------------------------------------------------
// SynchDisk::WriteSector
//  Write the contents of a buffer into a disk sector.  Return only
//  after the data has been written.
//
//  "sectorNumber" -- the disk sector to be written
//  "data" -- the new contents of the disk sector
//----------------------------------------------------------------------

void
SynchDisk :: WriteSector ( int  sectorNumber ,   char *  data )
{
    lock -> Acquire ();              // only one disk I/O at a time
    disk -> WriteRequest ( sectorNumber ,  data );
    semaphore -> P ();           // wait for interrupt
    lock -> Release ();
}

//----------------------------------------------------------------------
// SynchDisk::CallBack
//  Disk interrupt handler.  Wake up any thread waiting for the disk
//  request to finish.
//----------------------------------------------------------------------

void
SynchDisk :: CallBack ()
{  
    semaphore -> V ();
}

nachos/code/filesys/filehdr.cc

nachos/code/filesys/filehdr.cc

// filehdr.cc 
//  Routines for managing the disk file header (in UNIX, this
//  would be called the i-node).
//
//  The file header is used to locate where on disk the 
//  file's data is stored.  We implement this as a fixed size
//  table of pointers -- each entry in the table points to the 
//  disk sector containing that portion of the file data
//  (in other words, there are no indirect or doubly indirect 
//  blocks). The table size is chosen so that the file header
//  will be just big enough to fit in one disk sector, 
//
//      Unlike in a real system, we do not keep track of file permissions, 
//  ownership, last modification date, etc., in the file header. 
//
//  A file header can be initialized in two ways:
//     for a new file, by modifying the in-memory data structure
//       to point to the newly allocated data blocks
//     for a file already on disk, by reading the file header from disk
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include   "copyright.h"

#include   "filehdr.h"
#include   "debug.h"
#include   "synchdisk.h"
#include   "main.h"

//----------------------------------------------------------------------
// FileHeader::Allocate
//  Initialize a fresh file header for a newly created file.
//  Allocate data blocks for the file out of the map of free disk blocks.
//  Return FALSE if there are not enough free blocks to accomodate
//  the new file.
//
//  "freeMap" is the bit map of free disk sectors
//  "fileSize" is the bit map of free disk sectors
//----------------------------------------------------------------------

bool
FileHeader :: Allocate ( PersistentBitmap   * freeMap ,   int  fileSize )
{  
    numBytes  =  fileSize ;
    numSectors   =  divRoundUp ( fileSize ,   SectorSize );
     if   ( freeMap -> NumClear ()   <  numSectors )
     return  FALSE ;         // not enough space

     for   ( int  i  =   0 ;  i  <  numSectors ;  i ++ )   {
    dataSectors [ i ]   =  freeMap -> FindAndSet ();
     // since we checked that there was enough free space,
     // we expect this to succeed
    ASSERT ( dataSectors [ i ]   >=   0 );
     }
     return  TRUE ;
}

//----------------------------------------------------------------------
// FileHeader::Deallocate
//  De-allocate all the space allocated for data blocks for this file.
//
//  "freeMap" is the bit map of free disk sectors
//----------------------------------------------------------------------

void  
FileHeader :: Deallocate ( PersistentBitmap   * freeMap )
{
     for   ( int  i  =   0 ;  i  <  numSectors ;  i ++ )   {
    ASSERT ( freeMap -> Test (( int )  dataSectors [ i ]));    // ought to be marked!
    freeMap -> Clear (( int )  dataSectors [ i ]);
     }
}

//----------------------------------------------------------------------
// FileHeader::FetchFrom
//  Fetch contents of file header from disk. 
//
//  "sector" is the disk sector containing the file header
//----------------------------------------------------------------------

void
FileHeader :: FetchFrom ( int  sector )
{
    kernel -> synchDisk -> ReadSector ( sector ,   ( char   * ) this );
}

//----------------------------------------------------------------------
// FileHeader::WriteBack
//  Write the modified contents of the file header back to disk. 
//
//  "sector" is the disk sector to contain the file header
//----------------------------------------------------------------------

void
FileHeader :: WriteBack ( int  sector )
{
    kernel -> synchDisk -> WriteSector ( sector ,   ( char   * ) this );  
}

//----------------------------------------------------------------------
// FileHeader::ByteToSector
//  Return which disk sector is storing a particular byte within the file.
//      This is essentially a translation from a virtual address (the
//  offset in the file) to a physical address (the sector where the
//  data at the offset is stored).
//
//  "offset" is the location within the file of the byte in question
//----------------------------------------------------------------------

int
FileHeader :: ByteToSector ( int  offset )
{
     return ( dataSectors [ offset  /   SectorSize ]);
}

//----------------------------------------------------------------------
// FileHeader::FileLength
//  Return the number of bytes in the file.
//----------------------------------------------------------------------

int
FileHeader :: FileLength ()
{
     return  numBytes ;
}

//----------------------------------------------------------------------
// FileHeader::Print
//  Print the contents of the file header, and the contents of all
//  the data blocks pointed to by the file header.
//----------------------------------------------------------------------

void
FileHeader :: Print ()
{
     int  i ,  j ,  k ;
     char   * data  =   new   char [ SectorSize ];

    printf ( "FileHeader contents.  File size: %d.  File blocks:\n" ,  numBytes );
     for   ( =   0 ;  i  <  numSectors ;  i ++ )
    printf ( "%d " ,  dataSectors [ i ]);
    printf ( "\nFile contents:\n" );
     for   ( =  k  =   0 ;  i  <  numSectors ;  i ++ )   {
    kernel -> synchDisk -> ReadSector ( dataSectors [ i ],  data );
         for   ( =   0 ;   ( <   SectorSize )   &&   ( <  numBytes );  j ++ ,  k ++ )   {
         if   ( '\040'   <=  data [ j ]   &&  data [ j ]   <=   '\176' )     // isprint(data[j])
        printf ( "%c" ,  data [ j ]);
             else
        printf ( "\\%x" ,   ( unsigned   char ) data [ j ]);
     }
        printf ( "\n" );  
     }
     delete   []  data ;
}

nachos/code/filesys/filesys.cc

nachos/code/filesys/filesys.cc

// filesys.cc 
//  Routines to manage the overall operation of the file system.
//  Implements routines to map from textual file names to files.
//
//  Each file in the file system has:
//     A file header, stored in a sector on disk 
//      (the size of the file header data structure is arranged
//      to be precisely the size of 1 disk sector)
//     A number of data blocks
//     An entry in the file system directory
//
//  The file system consists of several data structures:
//     A bitmap of free disk sectors (cf. bitmap.h)
//     A directory of file names and file headers
//
//      Both the bitmap and the directory are represented as normal
//  files.  Their file headers are located in specific sectors
//  (sector 0 and sector 1), so that the file system can find them 
//  on bootup.
//
//  The file system assumes that the bitmap and directory files are
//  kept "open" continuously while Nachos is running.
//
//  For those operations (such as Create, Remove) that modify the
//  directory and/or bitmap, if the operation succeeds, the changes
//  are written immediately back to disk (the two files are kept
//  open during all this time).  If the operation fails, and we have
//  modified part of the directory and/or bitmap, we simply discard
//  the changed version, without writing it back to disk.
//
//  Our implementation at this point has the following restrictions:
//
//     there is no synchronization for concurrent accesses
//     files have a fixed size, set when the file is created
//     files cannot be bigger than about 3KB in size
//     there is no hierarchical directory structure, and only a limited
//       number of files can be added to the system
//     there is no attempt to make the system robust to failures
//      (if Nachos exits in the middle of an operation that modifies
//      the file system, it may corrupt the disk)
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.
#ifndef  FILESYS_STUB

#include   "copyright.h"
#include   "debug.h"
#include   "disk.h"
#include   "pbitmap.h"
#include   "directory.h"
#include   "filehdr.h"
#include   "filesys.h"

// Sectors containing the file headers for the bitmap of free sectors,
// and the directory of files.  These file headers are placed in well-known 
// sectors, so that they can be located on boot-up.
#define   FreeMapSector         0
#define   DirectorySector       1

// Initial file sizes for the bitmap and directory; until the file system
// supports extensible files, the directory size sets the maximum number 
// of files that can be loaded onto the disk.
#define   FreeMapFileSize       ( NumSectors   /   BitsInByte )
#define   NumDirEntries         10
#define   DirectoryFileSize     ( sizeof ( DirectoryEntry )   *   NumDirEntries )

//----------------------------------------------------------------------
// FileSystem::FileSystem
//  Initialize the file system.  If format = TRUE, the disk has
//  nothing on it, and we need to initialize the disk to contain
//  an empty directory, and a bitmap of free sectors (with almost but
//  not all of the sectors marked as free).  
//
//  If format = FALSE, we just have to open the files
//  representing the bitmap and the directory.
//
//  "format" -- should we initialize the disk?
//----------------------------------------------------------------------

FileSystem :: FileSystem ( bool  format )
{  
    DEBUG ( dbgFile ,   "Initializing the file system." );
     if   ( format )   {
         PersistentBitmap   * freeMap  =   new   PersistentBitmap ( NumSectors );
         Directory   * directory  =   new   Directory ( NumDirEntries );
     FileHeader   * mapHdr  =   new   FileHeader ;
     FileHeader   * dirHdr  =   new   FileHeader ;

        DEBUG ( dbgFile ,   "Formatting the file system." );

     // First, allocate space for FileHeaders for the directory and bitmap
     // (make sure no one else grabs these!)
    freeMap -> Mark ( FreeMapSector );        
    freeMap -> Mark ( DirectorySector );

     // Second, allocate space for the data blocks containing the contents
     // of the directory and bitmap files.  There better be enough space!

    ASSERT ( mapHdr -> Allocate ( freeMap ,   FreeMapFileSize ));
    ASSERT ( dirHdr -> Allocate ( freeMap ,   DirectoryFileSize ));

     // Flush the bitmap and directory FileHeaders back to disk
     // We need to do this before we can "Open" the file, since open
     // reads the file header off of disk (and currently the disk has garbage
     // on it!).

        DEBUG ( dbgFile ,   "Writing headers back to disk." );
    mapHdr -> WriteBack ( FreeMapSector );     
    dirHdr -> WriteBack ( DirectorySector );

     // OK to open the bitmap and directory files now
     // The file system operations assume these two files are left open
     // while Nachos is running.

        freeMapFile  =   new   OpenFile ( FreeMapSector );
        directoryFile  =   new   OpenFile ( DirectorySector );
     
     // Once we have the files "open", we can write the initial version
     // of each file back to disk.  The directory at this point is completely
     // empty; but the bitmap has been changed to reflect the fact that
     // sectors on the disk have been allocated for the file headers and
     // to hold the file data for the directory and bitmap.

        DEBUG ( dbgFile ,   "Writing bitmap and directory back to disk." );
    freeMap -> WriteBack ( freeMapFile );       // flush changes to disk
    directory -> WriteBack ( directoryFile );

     if   ( debug -> IsEnabled ( 'f' ))   {
        freeMap -> Print ();
        directory -> Print ();
         }
         delete  freeMap ;  
     delete  directory ;  
     delete  mapHdr ;  
     delete  dirHdr ;
     }   else   {
     // if we are not formatting the disk, just open the files representing
     // the bitmap and directory; these are left open while Nachos is running
        freeMapFile  =   new   OpenFile ( FreeMapSector );
        directoryFile  =   new   OpenFile ( DirectorySector );
     }
}

//----------------------------------------------------------------------
// FileSystem::Create
//  Create a file in the Nachos file system (similar to UNIX create).
//  Since we can't increase the size of files dynamically, we have
//  to give Create the initial size of the file.
//
//  The steps to create a file are:
//    Make sure the file doesn't already exist
//        Allocate a sector for the file header
//    Allocate space on disk for the data blocks for the file
//    Add the name to the directory
//    Store the new file header on disk 
//    Flush the changes to the bitmap and the directory back to disk
//
//  Return TRUE if everything goes ok, otherwise, return FALSE.
//
//  Create fails if:
//          file is already in directory
//      no free space for file header
//      no free entry for file in directory
//      no free space for data blocks for the file 
//
//  Note that this implementation assumes there is no concurrent access
//  to the file system!
//
//  "name" -- name of file to be created
//  "initialSize" -- size of file to be created
//----------------------------------------------------------------------

bool
FileSystem :: Create ( char   * name ,   int  initialSize )
{
     Directory   * directory ;
     PersistentBitmap   * freeMap ;
     FileHeader   * hdr ;
     int  sector ;
     bool  success ;

    DEBUG ( dbgFile ,   "Creating file "   <<  name  <<   " size "   <<  initialSize );

    directory  =   new   Directory ( NumDirEntries );
    directory -> FetchFrom ( directoryFile );

     if   ( directory -> Find ( name )   !=   - 1 )
      success  =  FALSE ;            // file is already in directory
     else   {   
        freeMap  =   new   PersistentBitmap ( freeMapFile , NumSectors );
        sector  =  freeMap -> FindAndSet ();   // find a sector to hold the file header
         if   ( sector  ==   - 1 )        
            success  =  FALSE ;          // no free block for file header 
         else   if   ( ! directory -> Add ( name ,  sector ))
            success  =  FALSE ;      // no space in directory
     else   {
            hdr  =   new   FileHeader ;
         if   ( ! hdr -> Allocate ( freeMap ,  initialSize ))
                success  =  FALSE ;      // no space on disk for data
         else   {   
            success  =  TRUE ;
         // everthing worked, flush all changes back to disk
                hdr -> WriteBack ( sector );          
                directory -> WriteBack ( directoryFile );
                freeMap -> WriteBack ( freeMapFile );
         }
             delete  hdr ;
     }
         delete  freeMap ;
     }
     delete  directory ;
     return  success ;
}

//----------------------------------------------------------------------
// FileSystem::Open
//  Open a file for reading and writing.  
//  To open a file:
//    Find the location of the file's header, using the directory 
//    Bring the header into memory
//
//  "name" -- the text name of the file to be opened
//----------------------------------------------------------------------

OpenFile   *
FileSystem :: Open ( char   * name )
{  
     Directory   * directory  =   new   Directory ( NumDirEntries );
     OpenFile   * openFile  =  NULL ;
     int  sector ;

    DEBUG ( dbgFile ,   "Opening file"   <<  name );
    directory -> FetchFrom ( directoryFile );
    sector  =  directory -> Find ( name );  
     if   ( sector  >=   0 )         
    openFile  =   new   OpenFile ( sector );      // name was found in directory 
     delete  directory ;
     return  openFile ;                  // return NULL if not found
}

//----------------------------------------------------------------------
// FileSystem::Remove
//  Delete a file from the file system.  This requires:
//      Remove it from the directory
//      Delete the space for its header
//      Delete the space for its data blocks
//      Write changes to directory, bitmap back to disk
//
//  Return TRUE if the file was deleted, FALSE if the file wasn't
//  in the file system.
//
//  "name" -- the text name of the file to be removed
//----------------------------------------------------------------------

bool
FileSystem :: Remove ( char   * name )
{  
     Directory   * directory ;
     PersistentBitmap   * freeMap ;
     FileHeader   * fileHdr ;
     int  sector ;
    
    directory  =   new   Directory ( NumDirEntries );
    directory -> FetchFrom ( directoryFile );
    sector  =  directory -> Find ( name );
     if   ( sector  ==   - 1 )   {
        delete  directory ;
        return  FALSE ;               // file not found 
     }
    fileHdr  =   new   FileHeader ;
    fileHdr -> FetchFrom ( sector );

    freeMap  =   new   PersistentBitmap ( freeMapFile , NumSectors );

    fileHdr -> Deallocate ( freeMap );         // remove data blocks
    freeMap -> Clear ( sector );           // remove header block
    directory -> Remove ( name );

    freeMap -> WriteBack ( freeMapFile );          // flush to disk
    directory -> WriteBack ( directoryFile );          // flush to disk
     delete  fileHdr ;
     delete  directory ;
     delete  freeMap ;
     return  TRUE ;
}  

//----------------------------------------------------------------------
// FileSystem::List
//  List all the files in the file system directory.
//----------------------------------------------------------------------

void
FileSystem :: List ()
{
     Directory   * directory  =   new   Directory ( NumDirEntries );

    directory -> FetchFrom ( directoryFile );
    directory -> List ();
     delete  directory ;
}

//----------------------------------------------------------------------
// FileSystem::Print
//  Print everything about the file system:
//    the contents of the bitmap
//    the contents of the directory
//    for each file in the directory,
//        the contents of the file header
//        the data in the file
//----------------------------------------------------------------------

void
FileSystem :: Print ()
{
     FileHeader   * bitHdr  =   new   FileHeader ;
     FileHeader   * dirHdr  =   new   FileHeader ;
     PersistentBitmap   * freeMap  =   new   PersistentBitmap ( freeMapFile , NumSectors );
     Directory   * directory  =   new   Directory ( NumDirEntries );

    printf ( "Bit map file header:\n" );
    bitHdr -> FetchFrom ( FreeMapSector );
    bitHdr -> Print ();

    printf ( "Directory file header:\n" );
    dirHdr -> FetchFrom ( DirectorySector );
    dirHdr -> Print ();

    freeMap -> Print ();

    directory -> FetchFrom ( directoryFile );
    directory -> Print ();

     delete  bitHdr ;
     delete  dirHdr ;
     delete  freeMap ;
     delete  directory ;
}  

#endif   // FILESYS_STUB

nachos/code/filesys/pbitmap.cc

nachos/code/filesys/pbitmap.cc

// pbitmap.c 
//  Routines to manage a persistent bitmap -- a bitmap that is
//  stored on disk.
//
// Copyright (c) 1992,1993,1995 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include   "copyright.h"
#include   "pbitmap.h"

//----------------------------------------------------------------------
// PersistentBitmap::PersistentBitmap(int)
//  Initialize a bitmap with "numItems" bits, so that every bit is clear.
//  it can be added somewhere on a list.
//
//  "numItems" is the number of bits in the bitmap.
//
//      This constructor does not initialize the bitmap from a disk file
//----------------------------------------------------------------------

PersistentBitmap :: PersistentBitmap ( int  numItems ) : Bitmap ( numItems )  
{  
}

//----------------------------------------------------------------------
// PersistentBitmap::PersistentBitmap(OpenFile*,int)
//  Initialize a persistent bitmap with "numItems" bits,
//      so that every bit is clear.
//
//  "numItems" is the number of bits in the bitmap.
//      "file" refers to an open file containing the bitmap (written
//        by a previous call to PersistentBitmap::WriteBack
//
//      This constructor initializes the bitmap from a disk file
//----------------------------------------------------------------------

PersistentBitmap :: PersistentBitmap ( OpenFile   * file ,   int  numItems ) : Bitmap ( numItems )  
{  
     // map has already been initialized by the BitMap constructor,
     // but we will just overwrite that with the contents of the
     // map found in the file
    file -> ReadAt (( char   * ) map ,  numWords  *   sizeof ( unsigned ),   0 );
}

//----------------------------------------------------------------------
// PersistentBitmap::~PersistentBitmap
//  De-allocate a persistent bitmap.
//----------------------------------------------------------------------

PersistentBitmap ::~ PersistentBitmap ()
{  
}

//----------------------------------------------------------------------
// PersistentBitmap::FetchFrom
//  Initialize the contents of a persistent bitmap from a Nachos file.
//
//  "file" is the place to read the bitmap from
//----------------------------------------------------------------------

void
PersistentBitmap :: FetchFrom ( OpenFile   * file )  
{
    file -> ReadAt (( char   * ) map ,  numWords  *   sizeof ( unsigned ),   0 );
}

//----------------------------------------------------------------------
// PersistentBitmap::WriteBack
//  Store the contents of a persistent bitmap to a Nachos file.
//
//  "file" is the place to write the bitmap to
//----------------------------------------------------------------------

void
PersistentBitmap :: WriteBack ( OpenFile   * file )
{
   file -> WriteAt (( char   * ) map ,  numWords  *   sizeof ( unsigned ),   0 );
}

nachos/code/filesys/directory.cc

nachos/code/filesys/directory.cc

// directory.cc 
//  Routines to manage a directory of file names.
//
//  The directory is a table of fixed length entries; each
//  entry represents a single file, and contains the file name,
//  and the location of the file header on disk.  The fixed size
//  of each directory entry means that we have the restriction
//  of a fixed maximum size for file names.
//
//  The constructor initializes an empty directory of a certain size;
//  we use ReadFrom/WriteBack to fetch the contents of the directory
//  from disk, and to write back any modifications back to disk.
//
//  Also, this implementation has the restriction that the size
//  of the directory cannot expand.  In other words, once all the
//  entries in the directory are used, no more files can be created.
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include   "copyright.h"
#include   "utility.h"
#include   "filehdr.h"
#include   "directory.h"

//----------------------------------------------------------------------
// Directory::Directory
//  Initialize a directory; initially, the directory is completely
//  empty.  If the disk is being formatted, an empty directory
//  is all we need, but otherwise, we need to call FetchFrom in order
//  to initialize it from disk.
//
//  "size" is the number of entries in the directory
//----------------------------------------------------------------------

Directory :: Directory ( int  size )
{
    table  =   new   DirectoryEntry [ size ];
    tableSize  =  size ;
     for   ( int  i  =   0 ;  i  <  tableSize ;  i ++ )
    table [ i ]. inUse  =  FALSE ;
}

//----------------------------------------------------------------------
// Directory::~Directory
//  De-allocate directory data structure.
//----------------------------------------------------------------------

Directory ::~ Directory ()
{  
     delete   []  table ;
}  

//----------------------------------------------------------------------
// Directory::FetchFrom
//  Read the contents of the directory from disk.
//
//  "file" -- file containing the directory contents
//----------------------------------------------------------------------

void
Directory :: FetchFrom ( OpenFile   * file )
{
     ( void )  file -> ReadAt (( char   * ) table ,  tableSize  *   sizeof ( DirectoryEntry ),   0 );
}

//----------------------------------------------------------------------
// Directory::WriteBack
//  Write any modifications to the directory back to disk
//
//  "file" -- file to contain the new directory contents
//----------------------------------------------------------------------

void
Directory :: WriteBack ( OpenFile   * file )
{
     ( void )  file -> WriteAt (( char   * ) table ,  tableSize  *   sizeof ( DirectoryEntry ),   0 );
}

//----------------------------------------------------------------------
// Directory::FindIndex
//  Look up file name in directory, and return its location in the table of
//  directory entries.  Return -1 if the name isn't in the directory.
//
//  "name" -- the file name to look up
//----------------------------------------------------------------------

int
Directory :: FindIndex ( char   * name )
{
     for   ( int  i  =   0 ;  i  <  tableSize ;  i ++ )
         if   ( table [ i ]. inUse  &&   ! strncmp ( table [ i ]. name ,  name ,   FileNameMaxLen ))
         return  i ;
     return   - 1 ;        // name not in directory
}

//----------------------------------------------------------------------
// Directory::Find
//  Look up file name in directory, and return the disk sector number
//  where the file's header is stored. Return -1 if the name isn't 
//  in the directory.
//
//  "name" -- the file name to look up
//----------------------------------------------------------------------

int
Directory :: Find ( char   * name )
{
     int  i  =   FindIndex ( name );

     if   ( !=   - 1 )
     return  table [ i ]. sector ;
     return   - 1 ;
}

//----------------------------------------------------------------------
// Directory::Add
//  Add a file into the directory.  Return TRUE if successful;
//  return FALSE if the file name is already in the directory, or if
//  the directory is completely full, and has no more space for
//  additional file names.
//
//  "name" -- the name of the file being added
//  "newSector" -- the disk sector containing the added file's header
//----------------------------------------------------------------------

bool
Directory :: Add ( char   * name ,   int  newSector )
{  
     if   ( FindIndex ( name )   !=   - 1 )
     return  FALSE ;

     for   ( int  i  =   0 ;  i  <  tableSize ;  i ++ )
         if   ( ! table [ i ]. inUse )   {
            table [ i ]. inUse  =  TRUE ;
            strncpy ( table [ i ]. name ,  name ,   FileNameMaxLen );  
            table [ i ]. sector  =  newSector ;
         return  TRUE ;
     }
     return  FALSE ;     // no space.  Fix when we have extensible files.
}

//----------------------------------------------------------------------
// Directory::Remove
//  Remove a file name from the directory.  Return TRUE if successful;
//  return FALSE if the file isn't in the directory. 
//
//  "name" -- the file name to be removed
//----------------------------------------------------------------------

bool
Directory :: Remove ( char   * name )
{  
     int  i  =   FindIndex ( name );

     if   ( ==   - 1 )
     return  FALSE ;         // name not in directory
    table [ i ]. inUse  =  FALSE ;
     return  TRUE ;     
}

//----------------------------------------------------------------------
// Directory::List
//  List all the file names in the directory. 
//----------------------------------------------------------------------

void
Directory :: List ()
{
    for   ( int  i  =   0 ;  i  <  tableSize ;  i ++ )
     if   ( table [ i ]. inUse )
        printf ( "%s\n" ,  table [ i ]. name );
}

//----------------------------------------------------------------------
// Directory::Print
//  List all the file names in the directory, their FileHeader locations,
//  and the contents of each file.  For debugging.
//----------------------------------------------------------------------

void
Directory :: Print ()
{  
     FileHeader   * hdr  =   new   FileHeader ;

    printf ( "Directory contents:\n" );
     for   ( int  i  =   0 ;  i  <  tableSize ;  i ++ )
     if   ( table [ i ]. inUse )   {
        printf ( "Name: %s, Sector: %d\n" ,  table [ i ]. name ,  table [ i ]. sector );
        hdr -> FetchFrom ( table [ i ]. sector );
        hdr -> Print ();
     }
    printf ( "\n" );
     delete  hdr ;
}

nachos/code/filesys/filesys.h

// filesys.h // Data structures to represent the Nachos file system. // // A file system is a set of files stored on disk, organized // into directories. Operations on the file system have to // do with "naming" -- creating, opening, and deleting files, // given a textual file name. Operations on an individual // "open" file (read, write, close) are to be found in the OpenFile // class (openfile.h). // // We define two separate implementations of the file system. // The "STUB" version just re-defines the Nachos file system // operations as operations on the native UNIX file system on the machine // running the Nachos simulation. // // The other version is a "real" file system, built on top of // a disk simulator. The disk is simulated using the native UNIX // file system (in a file named "DISK"). // // In the "real" implementation, there are two key data structures used // in the file system. There is a single "root" directory, listing // all of the files in the file system; unlike UNIX, the baseline // system does not provide a hierarchical directory structure. // In addition, there is a bitmap for allocating // disk sectors. Both the root directory and the bitmap are themselves // stored as files in the Nachos file system -- this causes an interesting // bootstrap problem when the simulated disk is initialized. // // Copyright (c) 1992-1993 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef FS_H #define FS_H #include "copyright.h" #include "sysdep.h" #include "openfile.h" #ifdef FILESYS_STUB // Temporarily implement file system calls as // calls to UNIX, until the real file system // implementation is available class FileSystem { public: FileSystem() {} bool Create(char *name) { int fileDescriptor = OpenForWrite(name); if (fileDescriptor == -1) return FALSE; Close(fileDescriptor); return TRUE; } OpenFile* Open(char *name) { int fileDescriptor = OpenForReadWrite(name, FALSE); if (fileDescriptor == -1) return NULL; return new OpenFile(fileDescriptor); } bool Remove(char *name) { return Unlink(name) == 0; } }; #else // FILESYS class FileSystem { public: FileSystem(bool format); // Initialize the file system. // Must be called *after* "synchDisk" // has been initialized. // If "format", there is nothing on // the disk, so initialize the directory // and the bitmap of free blocks. bool Create(char *name, int initialSize); // Create a file (UNIX creat) OpenFile* Open(char *name); // Open a file (UNIX open) bool Remove(char *name); // Delete a file (UNIX unlink) void List(); // List all the files in the file system void Print(); // List all the files and their contents private: OpenFile* freeMapFile; // Bit map of free disk blocks, // represented as a file OpenFile* directoryFile; // "Root" directory -- list of // file names, represented as a file }; #endif // FILESYS #endif // FS_H

nachos/code/filesys/filehdr.h

// filehdr.h // Data structures for managing a disk file header. // // A file header describes where on disk to find the data in a file, // along with other information about the file (for instance, its // length, owner, etc.) // // Copyright (c) 1992-1993 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #include "copyright.h" #ifndef FILEHDR_H #define FILEHDR_H #include "disk.h" #include "pbitmap.h" #define NumDirect ((SectorSize - 2 * sizeof(int)) / sizeof(int)) #define MaxFileSize (NumDirect * SectorSize) // The following class defines the Nachos "file header" (in UNIX terms, // the "i-node"), describing where on disk to find all of the data in the file. // The file header is organized as a simple table of pointers to // data blocks. // // The file header data structure can be stored in memory or on disk. // When it is on disk, it is stored in a single sector -- this means // that we assume the size of this data structure to be the same // as one disk sector. Without indirect addressing, this // limits the maximum file length to just under 4K bytes. // // There is no constructor; rather the file header can be initialized // by allocating blocks for the file (if it is a new file), or by // reading it from disk. class FileHeader { public: bool Allocate(PersistentBitmap *bitMap, int fileSize);// Initialize a file header, // including allocating space // on disk for the file data void Deallocate(PersistentBitmap *bitMap); // De-allocate this file's // data blocks void FetchFrom(int sectorNumber); // Initialize file header from disk void WriteBack(int sectorNumber); // Write modifications to file header // back to disk int ByteToSector(int offset); // Convert a byte offset into the file // to the disk sector containing // the byte int FileLength(); // Return the length of the file // in bytes void Print(); // Print the contents of the file. private: int numBytes; // Number of bytes in the file int numSectors; // Number of data sectors in the file int dataSectors[NumDirect]; // Disk sector numbers for each data // block in the file }; #endif // FILEHDR_H

nachos/code/filesys/synchdisk.h

// synchdisk.h // Data structures to export a synchronous interface to the raw // disk device. // // Copyright (c) 1992-1993 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #include "copyright.h" #ifndef SYNCHDISK_H #define SYNCHDISK_H #include "disk.h" #include "synch.h" #include "callback.h" // The following class defines a "synchronous" disk abstraction. // As with other I/O devices, the raw physical disk is an asynchronous device -- // requests to read or write portions of the disk return immediately, // and an interrupt occurs later to signal that the operation completed. // (Also, the physical characteristics of the disk device assume that // only one operation can be requested at a time). // // This class provides the abstraction that for any individual thread // making a request, it waits around until the operation finishes before // returning. class SynchDisk : public CallBackObj { public: SynchDisk(); // Initialize a synchronous disk, // by initializing the raw Disk. ~SynchDisk(); // De-allocate the synch disk data void ReadSector(int sectorNumber, char* data); // Read/write a disk sector, returning // only once the data is actually read // or written. These call // Disk::ReadRequest/WriteRequest and // then wait until the request is done. void WriteSector(int sectorNumber, char* data); void CallBack(); // Called by the disk device interrupt // handler, to signal that the // current disk operation is complete. private: Disk *disk; // Raw disk device Semaphore *semaphore; // To synchronize requesting thread // with the interrupt handler Lock *lock; // Only one read/write request // can be sent to the disk at a time }; #endif // SYNCHDISK_H

nachos/code/filesys/openfile.cc

nachos/code/filesys/openfile.cc

// openfile.cc 
//  Routines to manage an open Nachos file.  As in UNIX, a
//  file must be open before we can read or write to it.
//  Once we're all done, we can close it (in Nachos, by deleting
//  the OpenFile data structure).
//
//  Also as in UNIX, for convenience, we keep the file header in
//  memory while the file is open.
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.
#ifndef  FILESYS_STUB

#include   "copyright.h"
#include   "main.h"
#include   "filehdr.h"
#include   "openfile.h"
#include   "synchdisk.h"

//----------------------------------------------------------------------
// OpenFile::OpenFile
//  Open a Nachos file for reading and writing.  Bring the file header
//  into memory while the file is open.
//
//  "sector" -- the location on disk of the file header for this file
//----------------------------------------------------------------------

OpenFile :: OpenFile ( int  sector )
{  
    hdr  =   new   FileHeader ;
    hdr -> FetchFrom ( sector );
    seekPosition  =   0 ;
}

//----------------------------------------------------------------------
// OpenFile::~OpenFile
//  Close a Nachos file, de-allocating any in-memory data structures.
//----------------------------------------------------------------------

OpenFile ::~ OpenFile ()
{
     delete  hdr ;
}

//----------------------------------------------------------------------
// OpenFile::Seek
//  Change the current location within the open file -- the point at
//  which the next Read or Write will start from.
//
//  "position" -- the location within the file for the next Read/Write
//----------------------------------------------------------------------

void
OpenFile :: Seek ( int  position )
{
    seekPosition  =  position ;
}    

//----------------------------------------------------------------------
// OpenFile::Read/Write
//  Read/write a portion of a file, starting from seekPosition.
//  Return the number of bytes actually written or read, and as a
//  side effect, increment the current position within the file.
//
//  Implemented using the more primitive ReadAt/WriteAt.
//
//  "into" -- the buffer to contain the data to be read from disk 
//  "from" -- the buffer containing the data to be written to disk 
//  "numBytes" -- the number of bytes to transfer
//----------------------------------------------------------------------

int
OpenFile :: Read ( char   * into ,   int  numBytes )
{
    int  result  =   ReadAt ( into ,  numBytes ,  seekPosition );
   seekPosition  +=  result ;
    return  result ;
}

int
OpenFile :: Write ( char   * into ,   int  numBytes )
{
    int  result  =   WriteAt ( into ,  numBytes ,  seekPosition );
   seekPosition  +=  result ;
    return  result ;
}

//----------------------------------------------------------------------
// OpenFile::ReadAt/WriteAt
//  Read/write a portion of a file, starting at "position".
//  Return the number of bytes actually written or read, but has
//  no side effects (except that Write modifies the file, of course).
//
//  There is no guarantee the request starts or ends on an even disk sector
//  boundary; however the disk only knows how to read/write a whole disk
//  sector at a time.  Thus:
//
//  For ReadAt:
//     We read in all of the full or partial sectors that are part of the
//     request, but we only copy the part we are interested in.
//  For WriteAt:
//     We must first read in any sectors that will be partially written,
//     so that we don't overwrite the unmodified portion.  We then copy
//     in the data that will be modified, and write back all the full
//     or partial sectors that are part of the request.
//
//  "into" -- the buffer to contain the data to be read from disk 
//  "from" -- the buffer containing the data to be written to disk 
//  "numBytes" -- the number of bytes to transfer
//  "position" -- the offset within the file of the first byte to be
//          read/written
//----------------------------------------------------------------------

int
OpenFile :: ReadAt ( char   * into ,   int  numBytes ,   int  position )
{
     int  fileLength  =  hdr -> FileLength ();
     int  i ,  firstSector ,  lastSector ,  numSectors ;
     char   * buf ;

     if   (( numBytes  <=   0 )   ||   ( position  >=  fileLength ))
         return   0 ;                 // check request
     if   (( position  +  numBytes )   >  fileLength )      
    numBytes  =  fileLength  -  position ;
    DEBUG ( dbgFile ,   "Reading "   <<  numBytes  <<   " bytes at "   <<  position  <<   " from file of length "   <<  fileLength );

    firstSector  =  divRoundDown ( position ,   SectorSize );
    lastSector  =  divRoundDown ( position  +  numBytes  -   1 ,   SectorSize );
    numSectors  =   1   +  lastSector  -  firstSector ;

     // read in all the full and partial sectors that we need
    buf  =   new   char [ numSectors  *   SectorSize ];
     for   ( =  firstSector ;  i  <=  lastSector ;  i ++ )  
        kernel -> synchDisk -> ReadSector ( hdr -> ByteToSector ( *   SectorSize ),  
                     & buf [( -  firstSector )   *   SectorSize ]);

     // copy the part we want
    bcopy ( & buf [ position  -   ( firstSector  *   SectorSize )],  into ,  numBytes );
     delete   []  buf ;
     return  numBytes ;
}

int
OpenFile :: WriteAt ( char   * from ,   int  numBytes ,   int  position )
{
     int  fileLength  =  hdr -> FileLength ();
     int  i ,  firstSector ,  lastSector ,  numSectors ;
     bool  firstAligned ,  lastAligned ;
     char   * buf ;

     if   (( numBytes  <=   0 )   ||   ( position  >=  fileLength ))
     return   0 ;                 // check request
     if   (( position  +  numBytes )   >  fileLength )
    numBytes  =  fileLength  -  position ;
    DEBUG ( dbgFile ,   "Writing "   <<  numBytes  <<   " bytes at "   <<  position  <<   " from file of length "   <<  fileLength );

    firstSector  =  divRoundDown ( position ,   SectorSize );
    lastSector  =  divRoundDown ( position  +  numBytes  -   1 ,   SectorSize );
    numSectors  =   1   +  lastSector  -  firstSector ;

    buf  =   new   char [ numSectors  *   SectorSize ];

    firstAligned  =   ( position  ==   ( firstSector  *   SectorSize ));
    lastAligned  =   (( position  +  numBytes )   ==   (( lastSector  +   1 )   *   SectorSize ));

// read in first and last sector, if they are to be partially modified
     if   ( ! firstAligned )
         ReadAt ( buf ,   SectorSize ,  firstSector  *   SectorSize );   
     if   ( ! lastAligned  &&   (( firstSector  !=  lastSector )   ||  firstAligned ))
         ReadAt ( & buf [( lastSector  -  firstSector )   *   SectorSize ],  
                 SectorSize ,  lastSector  *   SectorSize );    

// copy in the bytes we want to change 
    bcopy ( from ,   & buf [ position  -   ( firstSector  *   SectorSize )],  numBytes );

// write modified sectors back
     for   ( =  firstSector ;  i  <=  lastSector ;  i ++ )  
        kernel -> synchDisk -> WriteSector ( hdr -> ByteToSector ( *   SectorSize ),  
                     & buf [( -  firstSector )   *   SectorSize ]);
     delete   []  buf ;
     return  numBytes ;
}

//----------------------------------------------------------------------
// OpenFile::Length
//  Return the number of bytes in the file.
//----------------------------------------------------------------------

int
OpenFile :: Length ()  
{  
     return  hdr -> FileLength ();  
}

#endif   //FILESYS_STUB

nachos/code/filesys/pbitmap.h

// pbitmap.h // Data structures defining a "persistent" bitmap -- a bitmap // that can be stored and fetched off of disk // // A persistent bitmap can either be initialized from the disk // when it is created, or it can be initialized later using // the FetchFrom method // // Copyright (c) 1992,1993,1995 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef PBITMAP_H #define PBITMAP_H #include "copyright.h" #include "bitmap.h" #include "openfile.h" // The following class defines a persistent bitmap. It inherits all // the behavior of a bitmap (see bitmap.h), adding the ability to // be read from and stored to the disk. class PersistentBitmap : public Bitmap { public: PersistentBitmap(OpenFile *file,int numItems); //initialize bitmap from disk PersistentBitmap(int numItems); // or don't... ~PersistentBitmap(); // deallocate bitmap void FetchFrom(OpenFile *file); // read bitmap from the disk void WriteBack(OpenFile *file); // write bitmap contents to disk }; #endif // PBITMAP_H

nachos/code/test/sort.c

/* sort.c * Test program to sort a large number of integers. * * Intention is to stress virtual memory system. * * Ideally, we could read the unsorted array off of the file system, * and store the result back to the file system! */ /* #define UNIX #define UNIX_DEBUG */ #ifdef UNIX #include <stdio.h> #define Exit exit #else #include "syscall.h" #endif /* UNIX */ #define SIZE (1024) int A[SIZE]; /* size of physical memory; with code, we'll run out of space!*/ int main() { int i, j, tmp; /* first initialize the array, in reverse sorted order */ for (i = 0; i < SIZE; i++) { A[i] = (SIZE-1) - i; } /* then sort! */ for (i = 0; i < SIZE; i++) { for (j = 0; j < (SIZE-1); j++) { if (A[j] > A[j + 1]) { /* out of order -> need to swap ! */ tmp = A[j]; A[j] = A[j + 1]; A[j + 1] = tmp; } } } #ifdef UNIX_DEBUG for (i=0; i<SIZE; i++) { printf("%4d ", A[i]); if (((i+1) % 15) == 0) { printf("\n"); } if (A[i] != i) { fprintf(stderr, "Out of order A[%d] = %d\n", i, A[i]); Exit(1); } } printf("\n"); #endif /* UNIX_DEBUG */ for (i=0; i<SIZE; i++) { if (A[i] != i) { Exit(1); } } Exit(0); }

nachos/code/test/add.o

nachos/code/test/start.o

nachos/code/test/Makefile.dep

############################################################################# # Machine-specific definitions # # If you are not in the MFCF environment, you can either add a new # automatic test for your machine/OS type, or you should set the # necessary variables "manually" here ############################################################################# # unfortunately, command line arguments to uname are not # very consistent across UNIX flavours. However, the following # seem to work almost everywhere in MFCF land osname = $(shell uname -s) osrelease = $(shell uname -r) hosttype = unknown # Test for x86 Linux # !!! COMMENT THE FOLLOWING LINES OUT IF BUILDING FOR SOLARIS HOST !!! # !!! ADD PATH TO CPP and CROSS COMPILER ifeq ($(osname),Linux) # full path name of your cpp program i.e.: CPP = /usr/local/nachos/lib/gcc-lib/decstation-ultrix/2.95.2/cpp # directory in which your gcc cross-compiler lives i.e.: GCCDIR = /usr/local/nachos/bin/decstation-ultrix- LDFLAGS = -T script -N ASFLAGS = -mips2 CPPFLAGS = $(INCDIR) COFF2NOFF = ../../coff2noff/coff2noff.x86Linux hosttype = x86Linux endif ifeq ($(osname),Windows) CPP = /usr/local/nachosxdev/lib/gcc-lib/decstation-ultrix/2.95.3/cpp0 # directory in which your gcc cross-compiler lives i.e.: GCCDIR = /usr/local/nachosxdev/bin/decstation-ultrix- LDFLAGS = -T script -N ASFLAGS = -mips2 CPPFLAGS = $(INCDIR) COFF2NOFF = ../../coff2noff/coff2noff.Windows hosttype = Windows endif # Note: # If you are trying to build on MacOS X # try something like this, substituting whatever # uname -s returns on your machine for the XXX # #ifeq ($(osname),XXX) #CPP = full path name of your cpp program #GCCDIR = directory in which your gcc cross-compiler lives #LDFLAGS = -T script -N #ASFLAGS = -mips2 #CPPFLAGS = $(INCDIR) #COFF2NOFF = full pathname of your coff2noff program # Note: it has been moved to part of the Nachos distribution # COFF2NOFF = ../../coff2noff.mipsUltrix #hosttype = MacOS #endif

nachos/code/test/sort.coff

nachos/code/test/matmult.coff

nachos/code/test/add.c

/* add.c * Simple program to test whether the systemcall interface works. * * Just do a add syscall that adds two values and returns the result. * */ #include "syscall.h" int main() { int result; result = Add(42, 23); Halt(); /* not reached */ }

nachos/code/test/halt.coff

nachos/code/test/add

nachos/code/test/Makefile

# # Makefile for building user programs to run on top of Nachos # # Use "make" to build the test executable(s) # Use "make clean" to remove .o files and .coff files # Use "make distclean" to remove all files produced by make, including # the test executables # # This is a GNU Makefile. It must be used with the GNU make program. # At UW, the GNU make program is /software/gnu/bin/make. # In many other places it is known as "gmake". # You may wish to include /software/gnu/bin/ early in your command # search path, so that you will be using GNU make when you type "make". # # Several things to be aware of: # # It should not be necessary to build the test executables for # every type of host machine on which Nachos runs. You should # be able to build them once, and then use them regardless of # the host machine type. That is because the test executables # run on the simulated MIPS machine, and not on the host. # # However: # (1) if you are experiencing problems with the test executables, # it would be prudent to rebuild them on the host machine # on which you are currently running Nachos. To do this, # just type "make distclean", and then "make" # # (2) the procedure used to build the test executables does # depend on the host machine you are on. All of the machine # dependencies are isolated in the Makefile.dep file. # It should be possible to build the test executables on # any MFCF machine. In the MFCF environment, this makefile # should automatically figure out what type of host you are # on, and should use the appropriate procedure. # However, if you are working outside the MFCF environment, # you will need to build a cross-compiler, build coff2noff, # and edit Makefile.dep in this directory before you # can build the test programs. # # Nachos assumes that the location of the program startup routine (the # location the kernel jumps to when the program initially starts up) # is at location 0. This means: start.o must be the first .o passed # to ld, in order for the routine "Start" to be loaded at location 0 # # When you make the test programs, you will see messages like these: # numsections 3 # Loading 3 sections: # ".text", filepos 0xd0, mempos 0x0, size 0x440 # ".data", filepos 0x510, mempos 0x440, size 0x0 # ".bss", filepos 0x0, mempos 0x440, size 0x12c0 # These messages are normal. They come from the coff2noff program. # They are useful in that they tell you how big the various parts of your # compiled user program are, and where in the address space # coff2noff is going to place them. This information is also # recorded in the header of the executable file that coff2noff # creates. See the method AddrSpace::Load (in userprog/addrspace.cc) # for an example of how this header is used by the Nachos OS to set up the # address space for a new process that will run the executable. # # # Adding New Test Programs: # # You are free to write new test programs, and to modify the # existing programs. If you write a new program, you will # need to modify this makefile so that the new program will # get built. # You will need to make the following changes for each program # you add: # (1) add the program's name to PROGRAMS variable definition # (2) add dependencies and build commands for the new # program. The easiest way to do this is to # copy the dependencies and commands for an # existing program, and then change the names. # # For example, if you write a test program in foo.c, for which # the executable is to be called foo, you should do the following: # # change the PROGRAMS definition to look like this: # # PROGRAMS = halt shell matmult sort foo # # add these dependencies/commands: # # foo.o: foo.c # $(CC) $(CFLAGS) -c foo.c # foo: foo.o start.o # $(LD) $(LDFLAGS) start.o foo.o -o foo.coff # $(COFF2NOFF) foo.coff foo # # Be careful when you copy the commands! The commands # must be indented with a *TAB*, not a bunch of spaces. # # ############################################################################# # Makefile.dep contains all machine-dependent definitions # If you are trying to build coff2noff somewhere outside # of the MFCF environment, you will almost certainly want # to visit and edit Makefile.dep before doing so ############################################################################# include Makefile.dep CC = $(GCCDIR)gcc AS = $(GCCDIR)as LD = $(GCCDIR)ld INCDIR =-I../userprog -I../lib CFLAGS = -G 0 -c $(INCDIR) -B/usr/local/nachos/lib/gcc-lib/decstation-ultrix/2.95.2/ -B/usr/local/nachos/decstation-ultrix/bin/ ifeq ($(hosttype),unknown) PROGRAMS = unknownhost else # change this if you create a new test program! PROGRAMS = add halt shell matmult sort segments endif all: $(PROGRAMS) start.o: start.S ../userprog/syscall.h $(CC) $(CFLAGS) $(ASFLAGS) -c start.S halt.o: halt.c $(CC) $(CFLAGS) -c halt.c halt: halt.o start.o $(LD) $(LDFLAGS) start.o halt.o -o halt.coff $(COFF2NOFF) halt.coff halt add.o: add.c $(CC) $(CFLAGS) -c add.c add: add.o start.o $(LD) $(LDFLAGS) start.o add.o -o add.coff $(COFF2NOFF) add.coff add shell.o: shell.c $(CC) $(CFLAGS) -c shell.c shell: shell.o start.o $(LD) $(LDFLAGS) start.o shell.o -o shell.coff $(COFF2NOFF) shell.coff shell sort.o: sort.c $(CC) $(CFLAGS) -c sort.c sort: sort.o start.o $(LD) $(LDFLAGS) start.o sort.o -o sort.coff $(COFF2NOFF) sort.coff sort segments.o: segments.c $(CC) $(CFLAGS) -c segments.c segments: segments.o start.o $(LD) $(LDFLAGS) start.o segments.o -o segments.coff $(COFF2NOFF) segments.coff segments matmult.o: matmult.c $(CC) $(CFLAGS) -c matmult.c matmult: matmult.o start.o $(LD) $(LDFLAGS) start.o matmult.o -o matmult.coff $(COFF2NOFF) matmult.coff matmult clean: $(RM) -f *.o *.ii $(RM) -f *.coff distclean: clean $(RM) -f $(PROGRAMS) unknownhost: @echo Host type could not be determined. @echo make is terminating. @echo If you are on an MFCF machine, contact the instructor to report this problem @echo Otherwise, edit Makefile.dep and try again.

nachos/code/test/halt.c

/* halt.c * Simple program to test whether running a user program works. * * Just do a "syscall" that shuts down the OS. * * NOTE: for some reason, user programs with global data structures * sometimes haven't worked in the Nachos environment. So be careful * out there! One option is to allocate data structures as * automatics within a procedure, but if you do this, you have to * be careful to allocate a big enough stack to hold the automatics! */ #include "syscall.h" int main() { Halt(); /* not reached */ }

nachos/code/test/shell

nachos/code/test/halt.o

nachos/code/test/halt

nachos/code/test/segments.c

/* segments.c * Simple program to illustrate different segments and to show * how parameters are passed and the syscall is generated. * * objdump below refers to: * /software/gcc_nachos/bin/decstation-ultrix-objdump * * Compile this "gmake segments" * Then use objdump to examine output. * objdump -d segments.coff - to disassemble * objdump -s segments.coff - to see contents of segments * objdump -x segments.coff - to see symbol table information * nachos -d m -s -x segments */ #define N (5) /* N is replaced by the preprocessor */ unsigned int initdata1 = 0xdeadbeef; /* initialized data put in .data segment */ int initdata2 = 0xbb; /* same as above */ const int blah = 0xff; /* into .rdata segment */ int uninitdata[N]; /* allocate space in .bss segment */ main() { /* automatic variable stored on stack or in register */ int i; int stack1 = 0xaa; int stack2; const int stack3 = 0xee; /* in reg or on stack not .rdata */ char *str = "Hello World .rdata segment\n"; /* str is stored on the stack or in a register * but text that is initialized is stored in .rdata */ for (i=0; i<N; i++) { uninitdata[i] = i; } Halt(); }

nachos/code/test/shell.c

#include "syscall.h" int main() { SpaceId newProc; OpenFileId input = ConsoleInput; OpenFileId output = ConsoleOutput; char prompt[2], ch, buffer[60]; int i; prompt[0] = '-'; prompt[1] = '-'; while( 1 ) { Write(prompt, 2, output); i = 0; do { Read(&buffer[i], 1, input); } while( buffer[i++] != '\n' ); buffer[--i] = '\0'; if( i > 0 ) { newProc = Exec(buffer); Join(newProc); } } }

nachos/code/test/sort

nachos/code/test/matmult.o

nachos/code/test/shell.o

nachos/code/test/start.S

/* Start.s * Assembly language assist for user programs running on top of Nachos. * * Since we don't want to pull in the entire C library, we define * what we need for a user program here, namely Start and the system * calls. */ #define IN_ASM #include "syscall.h" .text .align 2 /* ------------------------------------------------------------- * __start * Initialize running a C program, by calling "main". * * NOTE: This has to be first, so that it gets loaded at location 0. * The Nachos kernel always starts a program by jumping to location 0. * ------------------------------------------------------------- */ .globl __start .ent __start __start: jal main move $4,$0 jal Exit /* if we return from main, exit(0) */ .end __start /* ------------------------------------------------------------- * System call stubs: * Assembly language assist to make system calls to the Nachos kernel. * There is one stub per system call, that places the code for the * system call into register r2, and leaves the arguments to the * system call alone (in other words, arg1 is in r4, arg2 is * in r5, arg3 is in r6, arg4 is in r7) * * The return value is in r2. This follows the standard C calling * convention on the MIPS. * ------------------------------------------------------------- */ .globl Halt .ent Halt Halt: addiu $2,$0,SC_Halt syscall j $31 .end Halt .globl Add .ent Add Add: addiu $2,$0,SC_Add syscall j $31 .end Add .globl Exit .ent Exit Exit: addiu $2,$0,SC_Exit syscall j $31 .end Exit .globl Exec .ent Exec Exec: addiu $2,$0,SC_Exec syscall j $31 .end Exec .globl ExecV .ent ExecV ExecV: addiu $2,$0,SC_ExecV syscall j $31 .end ExecV .globl Join .ent Join Join: addiu $2,$0,SC_Join syscall j $31 .end Join .globl Create .ent Create Create: addiu $2,$0,SC_Create syscall j $31 .end Create .globl Remove .ent Remove Remove: addiu $2,$0,SC_Remove syscall j $31 .end Remove .globl Open .ent Open Open: addiu $2,$0,SC_Open syscall j $31 .end Open .globl Read .ent Read Read: addiu $2,$0,SC_Read syscall j $31 .end Read .globl Write .ent Write Write: addiu $2,$0,SC_Write syscall j $31 .end Write .globl Close .ent Close Close: addiu $2,$0,SC_Close syscall j $31 .end Close .globl Seek .ent Seek Seek: addiu $2,$0,SC_Seek syscall j $31 .end Seek .globl ThreadFork .ent ThreadFork ThreadFork: addiu $2,$0,SC_ThreadFork syscall j $31 .end ThreadFork .globl ThreadYield .ent ThreadYield ThreadYield: addiu $2,$0,SC_ThreadYield syscall j $31 .end ThreadYield .globl ThreadExit .ent ThreadExit ThreadExit: addiu $2, $0, SC_ThreadExit syscall j $31 .end ThreadExit .globl ThreadJoin .ent ThreadJoin ThreadJoin: addiu $2, $0, SC_ThreadJoin syscall j $31 .end ThreadJoin /* dummy function to keep gcc happy */ .globl __main .ent __main __main: j $31 .end __main

nachos/code/test/shell.coff

nachos/code/test/matmult

nachos/code/test/add.coff

nachos/code/test/DISK_0

nachos/code/test/script

OUTPUT_FORMAT("ecoff-littlemips") ENTRY(__start) SECTIONS { .text 0 : { _ftext = . ; *(.init) eprol = .; *(.text) *(.fini) etext = .; _etext = .; } .rdata . : { *(.rdata) } _fdata = .; .data . : { *(.data) CONSTRUCTORS } edata = .; _edata = .; _fbss = .; .sbss . : { *(.sbss) *(.scommon) } .bss . : { *(.bss) *(COMMON) } end = .; _end = .; }

nachos/code/test/segments.o

nachos/code/test/sort.o

nachos/code/test/segments.coff

nachos/code/test/segments

nachos/code/test/matmult.c

/* matmult.c * Test program to do matrix multiplication on large arrays. * * Intended to stress virtual memory system. * * Ideally, we could read the matrices off of the file system, * and store the result back to the file system! */ #include "syscall.h" #define Dim 20 /* sum total of the arrays doesn't fit in * physical memory */ int A[Dim][Dim]; int B[Dim][Dim]; int C[Dim][Dim]; int main() { int i, j, k; for (i = 0; i < Dim; i++) /* first initialize the matrices */ for (j = 0; j < Dim; j++) { A[i][j] = i; B[i][j] = j; C[i][j] = 0; } for (i = 0; i < Dim; i++) /* then multiply them together */ for (j = 0; j < Dim; j++) for (k = 0; k < Dim; k++) C[i][j] += A[i][k] * B[k][j]; Exit(C[Dim-1][Dim-1]); /* and then we're done */ }

nachos/code/network/post.h

// post.h // Data structures for providing the abstraction of unreliable, // ordered, fixed-size message delivery to mailboxes on other // (directly connected) machines. Messages can be dropped by // the network, but they are never corrupted. // // The US Post Office (and Canada Post! -KMS) // delivers mail to the addressed mailbox. // By analogy, our post office delivers packets to a specific buffer // (MailBox), based on the mailbox number stored in the packet header. // Mail waits in the box until a thread asks for it; if the mailbox // is empty, threads can wait for mail to arrive in it. // // Thus, the service our post office provides is to de-multiplex // incoming packets, delivering them to the appropriate thread. // // With each message, you get a return address, which consists of a "from // address", which is the id of the machine that sent the message, and // a "from box", which is the number of a mailbox on the sending machine // to which you can send an acknowledgement, if your protocol requires // this. // // Copyright (c) 1992-1996 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef POST_H #define POST_H #include "copyright.h" #include "utility.h" #include "callback.h" #include "network.h" #include "synchlist.h" #include "synch.h" // Mailbox address -- uniquely identifies a mailbox on a given machine. // A mailbox is just a place for temporary storage for messages. typedef int MailBoxAddress; // The following class defines part of the message header. // This is prepended to the message by the PostOffice, before the message // is sent to the Network. class MailHeader { public: MailBoxAddress to; // Destination mail box MailBoxAddress from; // Mail box to reply to unsigned length; // Bytes of message data (excluding the // mail header) }; // Maximum "payload" -- real data -- that can included in a single message // Excluding the MailHeader and the PacketHeader #define MaxMailSize (MaxPacketSize - sizeof(MailHeader)) // The following class defines the format of an incoming/outgoing // "Mail" message. The message format is layered: // network header (PacketHeader) // post office header (MailHeader) // data class Mail { public: Mail(PacketHeader pktH, MailHeader mailH, char *msgData); // Initialize a mail message by // concatenating the headers to the data PacketHeader pktHdr; // Header appended by Network MailHeader mailHdr; // Header appended by PostOffice char data[MaxMailSize]; // Payload -- message data }; // The following class defines a single mailbox, or temporary storage // for messages. Incoming messages are put by the PostOffice into the // appropriate mailbox, and these messages can then be retrieved by // threads on this machine. class MailBox { public: MailBox(); // Allocate and initialize mail box ~MailBox(); // De-allocate mail box void Put(PacketHeader pktHdr, MailHeader mailHdr, char *data); // Atomically put a message into the mailbox void Get(PacketHeader *pktHdr, MailHeader *mailHdr, char *data); // Atomically get a message out of the // mailbox (and wait if there is no message // to get!) private: SynchList<Mail *> *messages; // A mailbox is just a list of arrived messages }; // The following two classes defines a "Post Office", or a collection of // mailboxes. The Post Office provides two main operations: // Send -- send a message to a mailbox on a remote machine // Receive -- wait until a message is in the mailbox, then remove and // return it. // // Incoming messages are put by the PostOffice into the // appropriate mailbox, waking up any threads waiting on Receive. class PostOfficeInput : public CallBackObj { public: PostOfficeInput(int nBoxes); // Allocate and initialize Post Office ~PostOfficeInput(); // De-allocate Post Office data void Receive(int box, PacketHeader *pktHdr, MailHeader *mailHdr, char *data); // Retrieve a message from "box". Wait if // there is no message in the box. static void PostalDelivery(void* data); // Wait for incoming messages, // and then put them in the correct mailbox void CallBack(); // Called when incoming packet has arrived // and can be pulled off of network // (i.e., time to call PostalDelivery) private: NetworkInput *network; // Physical network connection MailBox *boxes; // Table of mail boxes to hold incoming mail int numBoxes; // Number of mail boxes Semaphore *messageAvailable;// V'ed when message has arrived from network }; class PostOfficeOutput : public CallBackObj { public: PostOfficeOutput(double reliability); // Allocate and initialize output // "reliability" is how many packets // get dropped by the underlying network ~PostOfficeOutput(); // De-allocate Post Office data void Send(PacketHeader pktHdr, MailHeader mailHdr, char *data); // Send a message to a mailbox on a remote // machine. The fromBox in the MailHeader is // the return box for ack's. void CallBack(); // Called when outgoing packet has been // put on network; next packet can now be sent private: NetworkOutput *network; // Physical network connection Semaphore *messageSent; // V'ed when next message can be sent to network Lock *sendLock; // Only one outgoing message at a time }; #endif

nachos/code/network/post.cc

nachos/code/network/post.cc

// post.cc 
//  Routines to deliver incoming network messages to the correct
//  "address" -- a mailbox, or a holding area for incoming messages.
//  This module operates just like the US postal service (in other
//  words, it works, but it's slow, and you can't really be sure if
//  your mail really got through!).
//
//  Note that once we prepend the MailHdr to the outgoing message data,
//  the combination (MailHdr plus data) looks like "data" to the Network 
//  device.
//
//  The implementation synchronizes incoming messages with threads
//  waiting for those messages.
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include   "copyright.h"
#include   "post.h"

//----------------------------------------------------------------------
// Mail::Mail
//      Initialize a single mail message, by concatenating the headers to
//  the data.
//
//  "pktH" -- source, destination machine ID's
//  "mailH" -- source, destination mailbox ID's
//  "data" -- payload data
//----------------------------------------------------------------------

Mail :: Mail ( PacketHeader  pktH ,   MailHeader  mailH ,   char   * msgData )
{
    ASSERT ( mailH . length  <=   MaxMailSize );

    pktHdr  =  pktH ;
    mailHdr  =  mailH ;
    bcopy ( msgData ,  data ,  mailHdr . length );
}

//----------------------------------------------------------------------
// MailBox::MailBox
//      Initialize a single mail box within the post office, so that it
//  can receive incoming messages.
//
//  Just initialize a list of messages, representing the mailbox.
//----------------------------------------------------------------------


MailBox :: MailBox ()
{  
    messages  =   new   SynchList < Mail   *> ();  
}

//----------------------------------------------------------------------
// MailBox::~MailBox
//      De-allocate a single mail box within the post office.
//
//  Just delete the mailbox, and throw away all the queued messages 
//  in the mailbox.
//----------------------------------------------------------------------

MailBox ::~ MailBox ()
{  
     delete  messages ;  
}

//----------------------------------------------------------------------
// PrintHeader
//  Print the message header -- the destination machine ID and mailbox
//  #, source machine ID and mailbox #, and message length.
//
//  "pktHdr" -- source, destination machine ID's
//  "mailHdr" -- source, destination mailbox ID's
//----------------------------------------------------------------------

static   void  
PrintHeader ( PacketHeader  pktHdr ,   MailHeader  mailHdr )
{
    cout  <<   "From ("   <<  pktHdr . from  <<   ", "   <<  mailHdr . from  <<   ") to ("   <<  
    pktHdr . to  <<   ", "   <<  mailHdr . to  <<   ") bytes "   <<  mailHdr . length  <<   "\n" ;
}

//----------------------------------------------------------------------
// MailBox::Put
//  Add a message to the mailbox.  If anyone is waiting for message
//  arrival, wake them up!
//
//  We need to reconstruct the Mail message (by concatenating the headers
//  to the data), to simplify queueing the message on the SynchList.
//
//  "pktHdr" -- source, destination machine ID's
//  "mailHdr" -- source, destination mailbox ID's
//  "data" -- payload message data
//----------------------------------------------------------------------

void  
MailBox :: Put ( PacketHeader  pktHdr ,   MailHeader  mailHdr ,   char   * data )
{  
     Mail   * mail  =   new   Mail ( pktHdr ,  mailHdr ,  data );  

    messages -> Append ( mail );       // put on the end of the list of 
                     // arrived messages, and wake up 
                     // any waiters
}

//----------------------------------------------------------------------
// MailBox::Get
//  Get a message from a mailbox, parsing it into the packet header,
//  mailbox header, and data. 
//
//  The calling thread waits if there are no messages in the mailbox.
//
//  "pktHdr" -- address to put: source, destination machine ID's
//  "mailHdr" -- address to put: source, destination mailbox ID's
//  "data" -- address to put: payload message data
//----------------------------------------------------------------------

void  
MailBox :: Get ( PacketHeader   * pktHdr ,   MailHeader   * mailHdr ,   char   * data )  
{  
    DEBUG ( dbgNet ,   "Waiting for mail in mailbox" );
     Mail   * mail  =  messages -> RemoveFront ();     // remove message from list;
                         // will wait if list is empty

     * pktHdr  =  mail -> pktHdr ;
     * mailHdr  =  mail -> mailHdr ;
     if   ( debug -> IsEnabled ( 'n' ))   {
    cout  <<   "Got mail from mailbox: " ;
     PrintHeader ( * pktHdr ,   * mailHdr );
     }
    bcopy ( mail -> data ,  data ,  mail -> mailHdr . length );
                     // copy the message data into
                     // the caller's buffer
     delete  mail ;              // we've copied out the stuff we
                     // need, we can now discard the message
}

//----------------------------------------------------------------------
// PostOfficeInput::PostOfficeInput
//  Initialize the post office input queues as a collection of mailboxes.
//  Also initialize the network device, to allow post offices
//  on different machines to deliver messages to one another.
//
//      We use a separate thread "the postal worker" to wait for messages 
//  to arrive, and deliver them to the correct mailbox.  Note that
//  delivering messages to the mailboxes can't be done directly
//  by the interrupt handlers, because it requires a Lock.
//
//  "nBoxes" is the number of mail boxes in this Post Office
//----------------------------------------------------------------------

PostOfficeInput :: PostOfficeInput ( int  nBoxes )
{
    messageAvailable  =   new   Semaphore ( "message available" ,   0 );

    numBoxes  =  nBoxes ;
    boxes  =   new   MailBox [ nBoxes ];

    network  =   new   NetworkInput ( this );

     Thread   * =   new   Thread ( "postal worker" );

    t -> Fork ( PostOfficeInput :: PostalDelivery ,   this );
}

//----------------------------------------------------------------------
// PostOfficeInput::~PostOfficeInput
//  De-allocate the post office data structures.
//  
//  Since the postal helper is waiting on the "messageAvail" semaphore,
//  we don't deallocate it!  This leaves garbage lying about,
//  but the alternative is worse!
//----------------------------------------------------------------------

PostOfficeInput ::~ PostOfficeInput ()
{
     delete  network ;
     delete   []  boxes ;
}

//----------------------------------------------------------------------
// PostOffice::PostalDelivery
//  Wait for incoming messages, and put them in the right mailbox.
//
//      Incoming messages have had the PacketHeader stripped off,
//  but the MailHeader is still tacked on the front of the data.
//----------------------------------------------------------------------

void
PostOfficeInput :: PostalDelivery ( void *  data )
{
     PostOfficeInput *  _this  =   ( PostOfficeInput * ) data ;
     PacketHeader  pktHdr ;
     MailHeader  mailHdr ;
     char   * buffer  =   new   char [ MaxPacketSize ];

     for   (;;)   {
         // first, wait for a message
        _this -> messageAvailable -> P ();    
        pktHdr  =  _this -> network -> Receive ( buffer );

        mailHdr  =   * ( MailHeader   * ) buffer ;
         if   ( debug -> IsEnabled ( 'n' ))   {
        cout  <<   "Putting mail into mailbox: " ;
         PrintHeader ( pktHdr ,  mailHdr );
         }

     // check that arriving message is legal!
    ASSERT ( 0   <=  mailHdr . to  &&  mailHdr . to  <  _this -> numBoxes );
    ASSERT ( mailHdr . length  <=   MaxMailSize );

     // put into mailbox
        _this -> boxes [ mailHdr . to ]. Put ( pktHdr ,  mailHdr ,  buffer  +   sizeof ( MailHeader ));
     }
}

//----------------------------------------------------------------------
// PostOfficeInput::Receive
//  Retrieve a message from a specific box if one is available, 
//  otherwise wait for a message to arrive in the box.
//
//  Note that the MailHeader + data looks just like normal payload
//  data to the Network.
//
//
//  "box" -- mailbox ID in which to look for message
//  "pktHdr" -- address to put: source, destination machine ID's
//  "mailHdr" -- address to put: source, destination mailbox ID's
//  "data" -- address to put: payload message data
//----------------------------------------------------------------------

void
PostOfficeInput :: Receive ( int  box ,   PacketHeader   * pktHdr ,  
                 MailHeader   * mailHdr ,   char *  data )
{
    ASSERT (( box  >=   0 )   &&   ( box  <  numBoxes ));

    boxes [ box ]. Get ( pktHdr ,  mailHdr ,  data );
    ASSERT ( mailHdr -> length  <=   MaxMailSize );
}

//----------------------------------------------------------------------
// PostOffice::CallBack
//  Interrupt handler, called when a packet arrives from the network.
//
//  Signal the PostalDelivery routine that it is time to get to work!
//----------------------------------------------------------------------

void
PostOfficeInput :: CallBack ()
{  
    messageAvailable -> V ();  
}

//----------------------------------------------------------------------
// PostOfficeOutput::PostOfficeOutput
//  Initialize the post office output queue.
//
//  "reliability" is the probability that a network packet will
//    be delivered (e.g., reliability = 1 means the network never
//    drops any packets; reliability = 0 means the network never
//    delivers any packets)
//----------------------------------------------------------------------

PostOfficeOutput :: PostOfficeOutput ( double  reliability )
{
    messageSent  =   new   Semaphore ( "message sent" ,   0 );
    sendLock  =   new   Lock ( "message send lock" );

    network  =   new   NetworkOutput ( reliability ,   this );
}

//----------------------------------------------------------------------
// PostOfficeOutput::~PostOfficeOutput
//  De-allocate the post office data structures.
//----------------------------------------------------------------------

PostOfficeOutput ::~ PostOfficeOutput ()
{
     delete  network ;
     delete  messageSent ;
     delete  sendLock ;
}

//----------------------------------------------------------------------
// PostOfficeOutput::Send
//  Concatenate the MailHeader to the front of the data, and pass 
//  the result to the Network for delivery to the destination machine.
//
//  Note that the MailHeader + data looks just like normal payload
//  data to the Network.
//
//  "pktHdr" -- source, destination machine ID's
//  "mailHdr" -- source, destination mailbox ID's
//  "data" -- payload message data
//----------------------------------------------------------------------

void
PostOfficeOutput :: Send ( PacketHeader  pktHdr ,   MailHeader  mailHdr ,   char *  data )
{
     char *  buffer  =   new   char [ MaxPacketSize ];   // space to hold concatenated
                         // mailHdr + data

     if   ( debug -> IsEnabled ( 'n' ))   {
    cout  <<   "Post send: " ;
     PrintHeader ( pktHdr ,  mailHdr );
     }
    ASSERT ( mailHdr . length  <=   MaxMailSize );
    ASSERT ( 0   <=  mailHdr . to );
    
     // fill in pktHdr, for the Network layer
    pktHdr . from  =  kernel -> hostName ;
    pktHdr . length  =  mailHdr . length  +   sizeof ( MailHeader );

     // concatenate MailHeader and data
    bcopy (( char   * ) & mailHdr ,  buffer ,   sizeof ( MailHeader ));
    bcopy ( data ,  buffer  +   sizeof ( MailHeader ),  mailHdr . length );

    sendLock -> Acquire ();          // only one message can be sent
                     // to the network at any one time
    network -> Send ( pktHdr ,  buffer );
    messageSent -> P ();             // wait for interrupt to tell us
                     // ok to send the next message
    sendLock -> Release ();

     delete   []  buffer ;             // we've sent the message, so
                     // we can delete our buffer
}

//----------------------------------------------------------------------
// PostOfficeOutput::CallBack
//  Interrupt handler, called when the next packet can be put onto the 
//  network.
//
//  Called even if the previous packet was dropped.
//----------------------------------------------------------------------

void  
PostOfficeOutput :: CallBack ()
{  
    messageSent -> V ();
}

nachos/code/threads/scheduler.h

// scheduler.h // Data structures for the thread dispatcher and scheduler. // Primarily, the list of threads that are ready to run. // // Copyright (c) 1992-1996 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef SCHEDULER_H #define SCHEDULER_H #include "copyright.h" #include "list.h" #include "thread.h" // The following class defines the scheduler/dispatcher abstraction -- // the data structures and operations needed to keep track of which // thread is running, and which threads are ready but not running. class Scheduler { public: Scheduler(); // Initialize list of ready threads ~Scheduler(); // De-allocate ready list void ReadyToRun(Thread* thread); // Thread can be dispatched. Thread* FindNextToRun(); // Dequeue first thread on the ready // list, if any, and return thread. void Run(Thread* nextThread, bool finishing); // Cause nextThread to start running void CheckToBeDestroyed();// Check if thread that had been // running needs to be deleted void Print(); // Print contents of ready list // SelfTest for scheduler is implemented in class Thread private: List<Thread *> *readyList; // queue of threads that are ready to run, // but not running Thread *toBeDestroyed; // finishing thread to be destroyed // by the next thread that runs }; #endif // SCHEDULER_H

nachos/code/threads/alarm.cc

nachos/code/threads/alarm.cc

// alarm.cc
//  Routines to use a hardware timer device to provide a
//  software alarm clock.  For now, we just provide time-slicing.
//
//  Not completely implemented.
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include   "copyright.h"
#include   "alarm.h"
#include   "main.h"

//----------------------------------------------------------------------
// Alarm::Alarm
//      Initialize a software alarm clock.  Start up a timer device
//
//      "doRandom" -- if true, arrange for the hardware interrupts to 
//      occur at random, instead of fixed, intervals.
//----------------------------------------------------------------------

Alarm :: Alarm ( bool  doRandom )
{
    timer  =   new   Timer ( doRandom ,   this );
}

//----------------------------------------------------------------------
// Alarm::CallBack
//  Software interrupt handler for the timer device. The timer device is
//  set up to interrupt the CPU periodically (once every TimerTicks).
//  This routine is called each time there is a timer interrupt,
//  with interrupts disabled.
//
//  Note that instead of calling Yield() directly (which would
//  suspend the interrupt handler, not the interrupted thread
//  which is what we wanted to context switch), we set a flag
//  so that once the interrupt handler is done, it will appear as 
//  if the interrupted thread called Yield at the point it is 
//  was interrupted.
//
//  For now, just provide time-slicing.  Only need to time slice 
//      if we're currently running something (in other words, not idle).
//----------------------------------------------------------------------

void  
Alarm :: CallBack ()  
{
     Interrupt   * interrupt  =  kernel -> interrupt ;
     MachineStatus  status  =  interrupt -> getStatus ();
    
     if   ( status  !=   IdleMode )   {
    interrupt -> YieldOnReturn ();
     }
}

nachos/code/threads/synch.h

// synch.h // Data structures for synchronizing threads. // // Three kinds of synchronization are defined here: semaphores, // locks, and condition variables. The implementation for // semaphores is given; for the latter two, only the procedure // interface is given -- they are to be implemented as part of // the first assignment. // // Note that all the synchronization objects take a "name" as // part of the initialization. This is solely for debugging purposes. // // Copyright (c) 1992-1996 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // synch.h -- synchronization primitives. #ifndef SYNCH_H #define SYNCH_H #include "copyright.h" #include "thread.h" #include "list.h" #include "main.h" // The following class defines a "semaphore" whose value is a non-negative // integer. The semaphore has only two operations P() and V(): // // P() -- waits until value > 0, then decrement // // V() -- increment, waking up a thread waiting in P() if necessary // // Note that the interface does *not* allow a thread to read the value of // the semaphore directly -- even if you did read the value, the // only thing you would know is what the value used to be. You don't // know what the value is now, because by the time you get the value // into a register, a context switch might have occurred, // and some other thread might have called P or V, so the true value might // now be different. class Semaphore { public: Semaphore(char* debugName, int initialValue); // set initial value ~Semaphore(); // de-allocate semaphore char* getName() { return name;} // debugging assist void P(); // these are the only operations on a semaphore void V(); // they are both *atomic* void SelfTest(); // test routine for semaphore implementation private: char* name; // useful for debugging int value; // semaphore value, always >= 0 List<Thread *> *queue; // threads waiting in P() for the value to be > 0 }; // The following class defines a "lock". A lock can be BUSY or FREE. // There are only two operations allowed on a lock: // // Acquire -- wait until the lock is FREE, then set it to BUSY // // Release -- set lock to be FREE, waking up a thread waiting // in Acquire if necessary // // In addition, by convention, only the thread that acquired the lock // may release it. As with semaphores, you can't read the lock value // (because the value might change immediately after you read it). class Lock { public: Lock(char* debugName); // initialize lock to be FREE ~Lock(); // deallocate lock char* getName() { return name; } // debugging assist void Acquire(); // these are the only operations on a lock void Release(); // they are both *atomic* bool IsHeldByCurrentThread() { return lockHolder == kernel->currentThread; } // return true if the current thread // holds this lock. // Note: SelfTest routine provided by SynchList private: char *name; // debugging assist Thread *lockHolder; // thread currently holding lock Semaphore *semaphore; // we use a semaphore to implement lock }; // The following class defines a "condition variable". A condition // variable does not have a value, but threads may be queued, waiting // on the variable. These are only operations on a condition variable: // // Wait() -- release the lock, relinquish the CPU until signaled, // then re-acquire the lock // // Signal() -- wake up a thread, if there are any waiting on // the condition // // Broadcast() -- wake up all threads waiting on the condition // // All operations on a condition variable must be made while // the current thread has acquired a lock. Indeed, all accesses // to a given condition variable must be protected by the same lock. // In other words, mutual exclusion must be enforced among threads calling // the condition variable operations. // // In Nachos, condition variables are assumed to obey *Mesa*-style // semantics. When a Signal or Broadcast wakes up another thread, // it simply puts the thread on the ready list, and it is the responsibility // of the woken thread to re-acquire the lock (this re-acquire is // taken care of within Wait()). By contrast, some define condition // variables according to *Hoare*-style semantics -- where the signalling // thread gives up control over the lock and the CPU to the woken thread, // which runs immediately and gives back control over the lock to the // signaller when the woken thread leaves the critical section. // // The consequence of using Mesa-style semantics is that some other thread // can acquire the lock, and change data structures, before the woken // thread gets a chance to run. The advantage to Mesa-style semantics // is that it is a lot easier to implement than Hoare-style. class Condition { public: Condition(char* debugName); // initialize condition to // "no one waiting" ~Condition(); // deallocate the condition char* getName() { return (name); } void Wait(Lock *conditionLock); // these are the 3 operations on // condition variables; releasing the // lock and going to sleep are // *atomic* in Wait() void Signal(Lock *conditionLock); // conditionLock must be held by void Broadcast(Lock *conditionLock);// the currentThread for all of // these operations // SelfTest routine provided by SyncLists private: char* name; List<Semaphore *> *waitQueue; // list of waiting threads }; #endif // SYNCH_H

nachos/code/threads/main.cc

nachos/code/threads/main.cc

// main.cc 
//  Driver code to initialize, selftest, and run the 
//  operating system kernel.  
//
// Usage: nachos -d <debugflags> -rs <random seed #>
//              -s -x <nachos file> -ci <consoleIn> -co <consoleOut>
//              -f -cp <unix file> <nachos file>
//              -p <nachos file> -r <nachos file> -l -D
//              -n <network reliability> -m <machine id>
//              -z -K -C -N
//
//    -d causes certain debugging messages to be printed (see debug.h)
//    -rs causes Yield to occur at random (but repeatable) spots
//    -z prints the copyright message
//    -s causes user programs to be executed in single-step mode
//    -x runs a user program
//    -ci specify file for console input (stdin is the default)
//    -co specify file for console output (stdout is the default)
//    -n sets the network reliability
//    -m sets this machine's host id (needed for the network)
//    -K run a simple self test of kernel threads and synchronization
//    -C run an interactive console test
//    -N run a two-machine network test (see Kernel::NetworkTest)
//
//    Filesystem-related flags:
//    -f forces the Nachos disk to be formatted
//    -cp copies a file from UNIX to Nachos
//    -p prints a Nachos file to stdout
//    -r removes a Nachos file from the file system
//    -l lists the contents of the Nachos directory
//    -D prints the contents of the entire file system 
//
//  Note: the file system flags are not used if the stub filesystem
//        is being used
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#define  MAIN
#include   "copyright.h"
#undef  MAIN

#include   "main.h"
#include   "filesys.h"
#include   "openfile.h"
#include   "sysdep.h"

// global variables
Kernel   * kernel ;
Debug   * debug ;

extern   void   ThreadTest ( void );

//----------------------------------------------------------------------
// Cleanup
//  Delete kernel data structures; called when user hits "ctl-C".
//----------------------------------------------------------------------

static   void  
Cleanup ( int  x )  
{      
    cerr  <<   "\nCleaning up after signal "   <<  x  <<   "\n" ;
     delete  kernel ;  
}

//-------------------------------------------------------------------
// Constant used by "Copy" and "Print"
//   It is the number of bytes read from the Unix file (for Copy)
//   or the Nachos file (for Print) by each read operation
//-------------------------------------------------------------------
static   const   int   TransferSize   =   128 ;


#ifndef  FILESYS_STUB
//----------------------------------------------------------------------
// Copy
//      Copy the contents of the UNIX file "from" to the Nachos file "to"
//----------------------------------------------------------------------

static   void
Copy ( char   * from ,   char   * to )
{
     int  fd ;
     OpenFile *  openFile ;
     int  amountRead ,  fileLength ;
     char   * buffer ;

// Open UNIX file
     if   (( fd  =   OpenForReadWrite ( from , FALSE ))   <   0 )   {        
        printf ( "Copy: couldn't open input file %s\n" ,  from );
         return ;
     }

// Figure out length of UNIX file
     Lseek ( fd ,   0 ,   2 );             
    fileLength  =   Tell ( fd );
     Lseek ( fd ,   0 ,   0 );

// Create a Nachos file of the same length
    DEBUG ( 'f' ,   "Copying file "   <<  from  <<   " of size "   <<  fileLength  <<    " to file "   <<  to );
     if   ( ! kernel -> fileSystem -> Create ( to ,  fileLength ))   {     // Create Nachos file
        printf ( "Copy: couldn't create output file %s\n" ,  to );
         Close ( fd );
         return ;
     }
    
    openFile  =  kernel -> fileSystem -> Open ( to );
    ASSERT ( openFile  !=  NULL );
    
// Copy the data in TransferSize chunks
    buffer  =   new   char [ TransferSize ];
     while   (( amountRead = ReadPartial ( fd ,  buffer ,   sizeof ( char ) * TransferSize ))   >   0 )
        openFile -> Write ( buffer ,  amountRead );     
     delete   []  buffer ;

// Close the UNIX and the Nachos files
     delete  openFile ;
     Close ( fd );
}

#endif   // FILESYS_STUB

//----------------------------------------------------------------------
// Print
//      Print the contents of the Nachos file "name".
//----------------------------------------------------------------------

void
Print ( char   * name )
{
     OpenFile   * openFile ;     
     int  i ,  amountRead ;
     char   * buffer ;

     if   (( openFile  =  kernel -> fileSystem -> Open ( name ))   ==  NULL )   {
        printf ( "Print: unable to open file %s\n" ,  name );
         return ;
     }
    
    buffer  =   new   char [ TransferSize ];
     while   (( amountRead  =  openFile -> Read ( buffer ,   TransferSize ))   >   0 )
         for   ( =   0 ;  i  <  amountRead ;  i ++ )
            printf ( "%c" ,  buffer [ i ]);
     delete   []  buffer ;

     delete  openFile ;              // close the Nachos file
     return ;
}

//----------------------------------------------------------------------
// RunUserProg
//      Run the user program in the given file.
//----------------------------------------------------------------------

void
RunUserProg ( void   * filename )   {
     AddrSpace   * space  =   new   AddrSpace ;
    ASSERT ( space  !=   ( AddrSpace   * ) NULL );
     if   ( space -> Load (( char * ) filename ))   {    // load the program into the space
        space -> Execute ();           // run the program
     }
    ASSERTNOTREACHED ();
}

//----------------------------------------------------------------------
// main
//  Bootstrap the operating system kernel.  
//  
//  Initialize kernel data structures
//  Call some test routines
//  Call "Run" to start an initial user program running
//
//  "argc" is the number of command line arguments (including the name
//      of the command) -- ex: "nachos -d +" -> argc = 3 
//  "argv" is an array of strings, one for each command line argument
//      ex: "nachos -d +" -> argv = {"nachos", "-d", "+"}
//----------------------------------------------------------------------

int
main ( int  argc ,   char   ** argv )
{
     int  i ;
     char   * debugArg  =   "" ;
     char   * userProgName  =  NULL ;          // default is not to execute a user prog
     bool  threadTestFlag  =   false ;
     bool  consoleTestFlag  =   false ;
     bool  networkTestFlag  =   false ;
#ifndef  FILESYS_STUB
     char   * copyUnixFileName  =  NULL ;      // UNIX file to be copied into Nachos
     char   * copyNachosFileName  =  NULL ;    // name of copied file in Nachos
     char   * printFileName  =  NULL ;  
     char   * removeFileName  =  NULL ;
     bool  dirListFlag  =   false ;
     bool  dumpFlag  =   false ;
#endif   //FILESYS_STUB

     // some command line arguments are handled here.
     // those that set kernel parameters are handled in
     // the Kernel constructor
     for   ( =   1 ;  i  <  argc ;  i ++ )   {
         if   ( strcmp ( argv [ i ],   "-d" )   ==   0 )   {
        ASSERT ( +   1   <  argc );     // next argument is debug string
            debugArg  =  argv [ +   1 ];
        i ++ ;
     }
     else   if   ( strcmp ( argv [ i ],   "-z" )   ==   0 )   {
            cout  <<  copyright  <<   "\n" ;
     }
     else   if   ( strcmp ( argv [ i ],   "-x" )   ==   0 )   {
        ASSERT ( +   1   <  argc );
        userProgName  =  argv [ +   1 ];
        i ++ ;
     }
     else   if   ( strcmp ( argv [ i ],   "-K" )   ==   0 )   {
        threadTestFlag  =  TRUE ;
     }
     else   if   ( strcmp ( argv [ i ],   "-C" )   ==   0 )   {
        consoleTestFlag  =  TRUE ;
     }
     else   if   ( strcmp ( argv [ i ],   "-N" )   ==   0 )   {
        networkTestFlag  =  TRUE ;
     }
#ifndef  FILESYS_STUB
     else   if   ( strcmp ( argv [ i ],   "-cp" )   ==   0 )   {
        ASSERT ( +   2   <  argc );
        copyUnixFileName  =  argv [ +   1 ];
        copyNachosFileName  =  argv [ +   2 ];
        i  +=   2 ;
     }
     else   if   ( strcmp ( argv [ i ],   "-p" )   ==   0 )   {
        ASSERT ( +   1   <  argc );
        printFileName  =  argv [ +   1 ];
        i ++ ;
     }
     else   if   ( strcmp ( argv [ i ],   "-r" )   ==   0 )   {
        ASSERT ( +   1   <  argc );
        removeFileName  =  argv [ +   1 ];
        i ++ ;
     }
     else   if   ( strcmp ( argv [ i ],   "-l" )   ==   0 )   {
        dirListFlag  =   true ;
     }
     else   if   ( strcmp ( argv [ i ],   "-D" )   ==   0 )   {
        dumpFlag  =   true ;
     }
#endif   //FILESYS_STUB
     else   if   ( strcmp ( argv [ i ],   "-u" )   ==   0 )   {
            cout  <<   "Partial usage: nachos [-z -d debugFlags]\n" ;
            cout  <<   "Partial usage: nachos [-x programName]\n" ;
        cout  <<   "Partial usage: nachos [-K] [-C] [-N]\n" ;
#ifndef  FILESYS_STUB
            cout  <<   "Partial usage: nachos [-cp UnixFile NachosFile]\n" ;
            cout  <<   "Partial usage: nachos [-p fileName] [-r fileName]\n" ;
            cout  <<   "Partial usage: nachos [-l] [-D]\n" ;
#endif   //FILESYS_STUB
     }

     }
    debug  =   new   Debug ( debugArg );
    
    DEBUG ( dbgThread ,   "Entering main" );

    kernel  =   new   Kernel ( argc ,  argv );

    kernel -> Initialize ();

     CallOnUserAbort ( Cleanup );         // if user hits ctl-C

     // at this point, the kernel is ready to do something
     // run some tests, if requested
     if   ( threadTestFlag )   {
       //kernel->ThreadSelfTest();  // test threads and synchronization
       ThreadTest ();
     }
     if   ( consoleTestFlag )   {
      kernel -> ConsoleTest ();     // interactive test of the synchronized console
     }
     if   ( networkTestFlag )   {
      kernel -> NetworkTest ();     // two-machine test of the network
     }

#ifndef  FILESYS_STUB
     if   ( removeFileName  !=  NULL )   {
      kernel -> fileSystem -> Remove ( removeFileName );
     }
     if   ( copyUnixFileName  !=  NULL  &&  copyNachosFileName  !=  NULL )   {
       Copy ( copyUnixFileName , copyNachosFileName );
     }
     if   ( dumpFlag )   {
      kernel -> fileSystem -> Print ();
     }
     if   ( dirListFlag )   {
      kernel -> fileSystem -> List ();
     }
     if   ( printFileName  !=  NULL )   {
       Print ( printFileName );
     }
#endif   // FILESYS_STUB

     // finally, run an initial user program if requested to do so
     if   ( userProgName  !=  NULL )   {
       RunUserProg ( userProgName );
     }

     // NOTE: if the procedure "main" returns, then the program "nachos"
     // will exit (as any other normal program would).  But there may be
     // other threads on the ready list (started in SelfTest).  
     // We switch to those threads by saying that the "main" thread 
     // is finished, preventing it from returning.
    kernel -> currentThread -> Finish ();   
    
    ASSERTNOTREACHED ();
}

nachos/code/threads/synch.cc

nachos/code/threads/synch.cc

// synch.cc 
//  Routines for synchronizing threads.  Three kinds of
//  synchronization routines are defined here: semaphores, locks 
//      and condition variables.
//
// Any implementation of a synchronization routine needs some
// primitive atomic operation.  We assume Nachos is running on
// a uniprocessor, and thus atomicity can be provided by
// turning off interrupts.  While interrupts are disabled, no
// context switch can occur, and thus the current thread is guaranteed
// to hold the CPU throughout, until interrupts are reenabled.
//
// Because some of these routines might be called with interrupts
// already disabled (Semaphore::V for one), instead of turning
// on interrupts at the end of the atomic operation, we always simply
// re-set the interrupt state back to its original value (whether
// that be disabled or enabled).
//
// Once we'e implemented one set of higher level atomic operations,
// we can implement others using that implementation.  We illustrate
// this by implementing locks and condition variables on top of 
// semaphores, instead of directly enabling and disabling interrupts.
//
// Locks are implemented using a semaphore to keep track of
// whether the lock is held or not -- a semaphore value of 0 means
// the lock is busy; a semaphore value of 1 means the lock is free.
//
// The implementation of condition variables using semaphores is
// a bit trickier, as explained below under Condition::Wait.
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include   "copyright.h"
#include   "synch.h"
#include   "main.h"

//----------------------------------------------------------------------
// Semaphore::Semaphore
//  Initialize a semaphore, so that it can be used for synchronization.
//
//  "debugName" is an arbitrary name, useful for debugging.
//  "initialValue" is the initial value of the semaphore.
//----------------------------------------------------------------------

Semaphore :: Semaphore ( char *  debugName ,   int  initialValue )
{
    name  =  debugName ;
     value   =  initialValue ;
    queue  =   new   List < Thread   *> ;
}

//----------------------------------------------------------------------
// Semaphore::Semaphore
//  De-allocate semaphore, when no longer needed.  Assume no one
//  is still waiting on the semaphore!
//----------------------------------------------------------------------

Semaphore ::~ Semaphore ()
{
     delete  queue ;
}

//----------------------------------------------------------------------
// Semaphore::P
//  Wait until semaphore value > 0, then decrement.  Checking the
//  value and decrementing must be done atomically, so we
//  need to disable interrupts before checking the value.
//
//  Note that Thread::Sleep assumes that interrupts are disabled
//  when it is called.
//----------------------------------------------------------------------

void
Semaphore :: P ()
{
     Interrupt   * interrupt  =  kernel -> interrupt ;
     Thread   * currentThread  =  kernel -> currentThread ;
    
     // disable interrupts
     IntStatus  oldLevel  =  interrupt -> SetLevel ( IntOff );    
    
     while   ( value   ==   0 )   {          // semaphore not available
    queue -> Append ( currentThread );     // so go to sleep
    currentThread -> Sleep ( FALSE );
     }  
     value -- ;              // semaphore available, consume its value
   
     // re-enable interrupts
     ( void )  interrupt -> SetLevel ( oldLevel );    
}

//----------------------------------------------------------------------
// Semaphore::V
//  Increment semaphore value, waking up a waiter if necessary.
//  As with P(), this operation must be atomic, so we need to disable
//  interrupts.  Scheduler::ReadyToRun() assumes that interrupts
//  are disabled when it is called.
//----------------------------------------------------------------------

void
Semaphore :: V ()
{
     Interrupt   * interrupt  =  kernel -> interrupt ;
    
     // disable interrupts
     IntStatus  oldLevel  =  interrupt -> SetLevel ( IntOff );    
    
     if   ( ! queue -> IsEmpty ())   {    // make thread ready.
    kernel -> scheduler -> ReadyToRun ( queue -> RemoveFront ());
     }
     value ++ ;
    
     // re-enable interrupts
     ( void )  interrupt -> SetLevel ( oldLevel );
}

//----------------------------------------------------------------------
// Semaphore::SelfTest, SelfTestHelper
//  Test the semaphore implementation, by using a semaphore
//  to control two threads ping-ponging back and forth.
//----------------------------------------------------------------------

static   Semaphore   * ping ;
static   void
SelfTestHelper   ( Semaphore   * pong )  
{
     for   ( int  i  =   0 ;  i  <   10 ;  i ++ )   {
        ping -> P ();
    pong -> V ();
     }
}

void
Semaphore :: SelfTest ()
{
     Thread   * helper  =   new   Thread ( "ping" );

    ASSERT ( value   ==   0 );       // otherwise test won't work!
    ping  =   new   Semaphore ( "ping" ,   0 );
    helper -> Fork (( VoidFunctionPtr )   SelfTestHelper ,   this );
     for   ( int  i  =   0 ;  i  <   10 ;  i ++ )   {
        ping -> V ();
     this -> P ();
     }
     delete  ping ;
}

//----------------------------------------------------------------------
// Lock::Lock
//  Initialize a lock, so that it can be used for synchronization.
//  Initially, unlocked.
//
//  "debugName" is an arbitrary name, useful for debugging.
//----------------------------------------------------------------------

Lock :: Lock ( char *  debugName )
{
    name  =  debugName ;
    semaphore  =   new   Semaphore ( "lock" ,   1 );    // initially, unlocked
    lockHolder  =  NULL ;
}

//----------------------------------------------------------------------
// Lock::~Lock
//  Deallocate a lock
//----------------------------------------------------------------------
Lock ::~ Lock ()
{
     delete  semaphore ;
}

//----------------------------------------------------------------------
// Lock::Acquire
//  Atomically wait until the lock is free, then set it to busy.
//  Equivalent to Semaphore::P(), with the semaphore value of 0
//  equal to busy, and semaphore value of 1 equal to free.
//----------------------------------------------------------------------

void   Lock :: Acquire ()
{
    semaphore -> P ();
    lockHolder  =  kernel -> currentThread ;
}

//----------------------------------------------------------------------
// Lock::Release
//  Atomically set lock to be free, waking up a thread waiting
//  for the lock, if any.
//  Equivalent to Semaphore::V(), with the semaphore value of 0
//  equal to busy, and semaphore value of 1 equal to free.
//
//  By convention, only the thread that acquired the lock
//  may release it.
//---------------------------------------------------------------------

void   Lock :: Release ()
{
    ASSERT ( IsHeldByCurrentThread ());
    lockHolder  =  NULL ;
    semaphore -> V ();
}

//----------------------------------------------------------------------
// Condition::Condition
//  Initialize a condition variable, so that it can be 
//  used for synchronization.  Initially, no one is waiting
//  on the condition.
//
//  "debugName" is an arbitrary name, useful for debugging.
//----------------------------------------------------------------------
Condition :: Condition ( char *  debugName )
{
    name  =  debugName ;
    waitQueue  =   new   List < Semaphore   *> ;
}

//----------------------------------------------------------------------
// Condition::Condition
//  Deallocate the data structures implementing a condition variable.
//----------------------------------------------------------------------

Condition ::~ Condition ()
{
     delete  waitQueue ;
}

//----------------------------------------------------------------------
// Condition::Wait
//  Atomically release monitor lock and go to sleep.
//  Our implementation uses semaphores to implement this, by
//  allocating a semaphore for each waiting thread.  The signaller
//  will V() this semaphore, so there is no chance the waiter
//  will miss the signal, even though the lock is released before
//  calling P().
//
//  Note: we assume Mesa-style semantics, which means that the
//  waiter must re-acquire the monitor lock when waking up.
//
//  "conditionLock" -- lock protecting the use of this condition
//----------------------------------------------------------------------

void   Condition :: Wait ( Lock *  conditionLock )  
{
      Semaphore   * waiter ;
    
     ASSERT ( conditionLock -> IsHeldByCurrentThread ());

     waiter  =   new   Semaphore ( "condition" ,   0 );
     waitQueue -> Append ( waiter );
     conditionLock -> Release ();
     waiter -> P ();
     conditionLock -> Acquire ();
      delete  waiter ;
}

//----------------------------------------------------------------------
// Condition::Signal
//  Wake up a thread waiting on this condition, if any.
//
//  Note: we assume Mesa-style semantics, which means that the
//  signaller doesn't give up control immediately to the thread
//  being woken up (unlike Hoare-style).
//
//  Also note: we assume the caller holds the monitor lock
//  (unlike what is described in Birrell's paper).  This allows
//  us to access waitQueue without disabling interrupts.
//
//  "conditionLock" -- lock protecting the use of this condition
//----------------------------------------------------------------------

void   Condition :: Signal ( Lock *  conditionLock )
{
     Semaphore   * waiter ;
    
    ASSERT ( conditionLock -> IsHeldByCurrentThread ());
    
     if   ( ! waitQueue -> IsEmpty ())   {
        waiter  =  waitQueue -> RemoveFront ();
    waiter -> V ();
     }
}

//----------------------------------------------------------------------
// Condition::Broadcast
//  Wake up all threads waiting on this condition, if any.
//
//  "conditionLock" -- lock protecting the use of this condition
//----------------------------------------------------------------------

void   Condition :: Broadcast ( Lock *  conditionLock )  
{
     while   ( ! waitQueue -> IsEmpty ())   {
         Signal ( conditionLock );
     }
}

nachos/code/threads/switch.h

/* switch.h * Definitions needed for implementing context switching. * * Context switching is inherently machine dependent, since * the registers to be saved, how to set up an initial * call frame, etc, are all specific to a processor architecture. * * This file currently supports the DEC MIPS, DEC Alpha, SUN SPARC, * HP PARISC, IBM PowerPC, and Intel x86 architectures. */ /* Copyright (c) 1992-1996 The Regents of the University of California. All rights reserved. See copyright.h for copyright notice and limitation of liability and disclaimer of warranty provisions. */ #ifndef SWITCH_H #define SWITCH_H #include "copyright.h" #ifdef DECMIPS /* Registers that must be saved during a context switch. * These are the offsets from the beginning of the Thread object, * in bytes, used in switch.s */ #define SP 0 #define S0 4 #define S1 8 #define S2 12 #define S3 16 #define S4 20 #define S5 24 #define S6 28 #define S7 32 #define FP 36 #define PC 40 /* To fork a thread, we set up its saved register state, so that * when we switch to the thread, it will start running in ThreadRoot. * * The following are the initial registers we need to set up to * pass values into ThreadRoot (for instance, containing the procedure * for the thread to run). The first set is the registers as used * by ThreadRoot; the second set is the locations for these initial * values in the Thread object -- used in Thread::AllocateStack(). */ #define InitialPC s0 #define InitialArg s1 #define WhenDonePC s2 #define StartupPC s3 #define PCState (PC/4-1) #define FPState (FP/4-1) #define InitialPCState (S0/4-1) #define InitialArgState (S1/4-1) #define WhenDonePCState (S2/4-1) #define StartupPCState (S3/4-1) #endif // DECMIPS #ifdef SPARC /* Registers that must be saved during a context switch. See comment above. */ #define I0 4 #define I1 8 #define I2 12 #define I3 16 #define I4 20 #define I5 24 #define I6 28 #define I7 32 /* Aliases used for clearing code. */ #define FP I6 #define PC I7 /* Registers for ThreadRoot. See comment above. */ #define InitialPC %o0 #define InitialArg %o1 #define WhenDonePC %o2 #define StartupPC %o3 #define PCState (PC/4-1) #define InitialPCState (I0/4-1) #define InitialArgState (I1/4-1) #define WhenDonePCState (I2/4-1) #define StartupPCState (I3/4-1) #endif // SPARC #ifdef PARISC /* Registers that must be saved during a context switch. See comment above. */ #define SP 0 #define S0 4 #define S1 8 #define S2 12 #define S3 16 #define S4 20 #define S5 24 #define S6 28 #define S7 32 #define S8 36 #define S9 40 #define S10 44 #define S11 48 #define S12 52 #define S13 56 #define S14 60 #define S15 64 #define PC 68 /* Registers for ThreadRoot. See comment above. */ #define InitialPC %r3 /* S0 */ #define InitialArg %r4 #define WhenDonePC %r5 #define StartupPC %r6 #define PCState (PC/4-1) #define InitialPCState (S0/4-1) #define InitialArgState (S1/4-1) #define WhenDonePCState (S2/4-1) #define StartupPCState (S3/4-1) #endif // PARISC #ifdef x86 /* the offsets of the registers from the beginning of the thread object */ #define _ESP 0 #define _EAX 4 #define _EBX 8 #define _ECX 12 #define _EDX 16 #define _EBP 20 #define _ESI 24 #define _EDI 28 #define _PC 32 /* These definitions are used in Thread::AllocateStack(). */ #define PCState (_PC/4-1) #define FPState (_EBP/4-1) #define InitialPCState (_ESI/4-1) #define InitialArgState (_EDX/4-1) #define WhenDonePCState (_EDI/4-1) #define StartupPCState (_ECX/4-1) #define InitialPC %esi #define InitialArg %edx #define WhenDonePC %edi #define StartupPC %ecx #endif // x86 #ifdef PowerPC #define SP 0 // stack pointer #define P1 4 // parameters #define P2 8 #define P3 12 #define P4 16 #define GP13 20 // general purpose registers 13-31 #define GP14 24 #define GP15 28 #define GP16 32 #define GP17 36 #define GP18 40 #define GP19 44 #define GP20 48 #define GP21 52 #define GP22 56 #define GP23 60 #define GP24 64 #define GP25 68 #define GP26 72 #define GP27 76 #define GP28 80 #define GP29 84 #define GP30 88 #define GP31 92 #define FP13 96 // floating point registers 14-31 #define FP15 104 #define FP16 112 #define FP17 120 #define FP18 128 #define FP19 136 #define FP20 144 #define FP21 152 #define FP22 160 #define FP23 168 #define FP24 176 #define FP25 184 #define FP26 192 #define FP27 200 #define FP28 208 #define FP29 216 #define FP30 224 #define FP31 232 #define CR 240 // control register #define LR 244 // link register #define TOC 248 // Table Of Contents // for ThreadRoot assembly function #define InitialPCState 0 // (P1/4 - 1) // user function address #define InitialArgState 1 // (P2/4 - 1) // user function argument #define WhenDonePCState 2 // (P3/4 - 1) // clean up function addr #define StartupPCState 3 // (P4/4 - 1) // start up function addr #define PCState 60 // (LR/4 - 1) // ThreadRoot addr (first time). // Later PC addr when SWITCH // occured #define InitialLR 21 #define InitialArg 22 #define WhenDoneLR 23 #define StartupLR 24 #endif // PowerPC #ifdef ALPHA /* * Porting to Alpha was done by Shuichi Oikawa ([email protected]). */ /* Registers that must be saved during a context switch. * These are the offsets from the beginning of the Thread object, * in bytes, used in switch.s */ #define SP (0*8) #define S0 (1*8) #define S1 (2*8) #define S2 (3*8) #define S3 (4*8) #define S4 (5*8) #define S5 (6*8) #define S6 (7*8) /* used as FP (Frame Pointer) */ #define GP (8*8) #define PC (9*8) /* To fork a thread, we set up its saved register state, so that * when we switch to the thread, it will start running in ThreadRoot. * * The following are the initial registers we need to set up to * pass values into ThreadRoot (for instance, containing the procedure * for the thread to run). The first set is the registers as used * by ThreadRoot; the second set is the locations for these initial * values in the Thread object -- used in Thread::StackAllocate(). */ #define InitialPC s0 #define InitialArg s1 #define WhenDonePC s2 #define StartupPC s3 #define PCState (PC/8-1) #define FPState (S6/8-1) #define InitialPCState (S0/8-1) #define InitialArgState (S1/8-1) #define WhenDonePCState (S2/8-1) #define StartupPCState (S3/8-1) #endif // HOST_ALPHA #endif // SWITCH_H

nachos/code/threads/alarm.h

// alarm.h // Data structures for a software alarm clock. // // We make use of a hardware timer device, that generates // an interrupt every X time ticks (on real systems, X is // usually between 0.25 - 10 milliseconds). // // From this, we provide the ability for a thread to be // woken up after a delay; we also provide time-slicing. // // NOTE: this abstraction is not completely implemented. // // Copyright (c) 1992-1996 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef ALARM_H #define ALARM_H #include "copyright.h" #include "utility.h" #include "callback.h" #include "timer.h" // The following class defines a software alarm clock. class Alarm : public CallBackObj { public: Alarm(bool doRandomYield); // Initialize the timer, and callback // to "toCall" every time slice. ~Alarm() { delete timer; } void WaitUntil(int x); // suspend execution until time > now + x // this method is not yet implemented private: Timer *timer; // the hardware timer device void CallBack(); // called when the hardware // timer generates an interrupt }; #endif // ALARM_H

nachos/code/threads/threadtest.cc

#include "kernel.h" #include "main.h" #include "thread.h" void SimpleThread(int which) { int num; for (num = 0; num < 5; num++) { printf("*** thread %d looped %d times\n", which, num); kernel->currentThread->Yield(); } } void ThreadTest() { Thread *t = new Thread("forked thread"); t->Fork((VoidFunctionPtr) SimpleThread, (void *) 1); SimpleThread(0); }

nachos/code/threads/thread.cc

nachos/code/threads/thread.cc

// thread.cc 
//  Routines to manage threads.  These are the main operations:
//
//  Fork -- create a thread to run a procedure concurrently
//      with the caller (this is done in two steps -- first
//      allocate the Thread object, then call Fork on it)
//  Begin -- called when the forked procedure starts up, to turn
//      interrupts on and clean up after last thread
//  Finish -- called when the forked procedure finishes, to clean up
//  Yield -- relinquish control over the CPU to another ready thread
//  Sleep -- relinquish control over the CPU, but thread is now blocked.
//      In other words, it will not run again, until explicitly 
//      put back on the ready queue.
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include   "copyright.h"
#include   "thread.h"
#include   "switch.h"
#include   "synch.h"
#include   "sysdep.h"

// this is put at the top of the execution stack, for detecting stack overflows
const   int  STACK_FENCEPOST  =   0xdedbeef ;

//----------------------------------------------------------------------
// Thread::Thread
//  Initialize a thread control block, so that we can then call
//  Thread::Fork.
//
//  "threadName" is an arbitrary string, useful for debugging.
//----------------------------------------------------------------------

Thread :: Thread ( char *  threadName )
{
    name  =  threadName ;
    stackTop  =  NULL ;
    stack  =  NULL ;
    status  =  JUST_CREATED ;
     for   ( int  i  =   0 ;  i  <   MachineStateSize ;  i ++ )   {
    machineState [ i ]   =  NULL ;       // not strictly necessary, since
                     // new thread ignores contents 
                     // of machine registers
     }
    space  =  NULL ;
}

//----------------------------------------------------------------------
// Thread::~Thread
//  De-allocate a thread.
//
//  NOTE: the current thread *cannot* delete itself directly,
//  since it is still running on the stack that we need to delete.
//
//      NOTE: if this is the main thread, we can't delete the stack
//      because we didn't allocate it -- we got it automatically
//      as part of starting up Nachos.
//----------------------------------------------------------------------

Thread ::~ Thread ()
{
    DEBUG ( dbgThread ,   "Deleting thread: "   <<  name );

    ASSERT ( this   !=  kernel -> currentThread );
     if   ( stack  !=  NULL )
     DeallocBoundedArray (( char   * )  stack ,   StackSize   *   sizeof ( int ));
}

//----------------------------------------------------------------------
// Thread::Fork
//  Invoke (*func)(arg), allowing caller and callee to execute 
//  concurrently.
//
//  NOTE: although our definition allows only a single argument
//  to be passed to the procedure, it is possible to pass multiple
//  arguments by making them fields of a structure, and passing a pointer
//  to the structure as "arg".
//
//  Implemented as the following steps:
//      1. Allocate a stack
//      2. Initialize the stack so that a call to SWITCH will
//      cause it to run the procedure
//      3. Put the thread on the ready queue
//  
//  "func" is the procedure to run concurrently.
//  "arg" is a single argument to be passed to the procedure.
//----------------------------------------------------------------------

void  
Thread :: Fork ( VoidFunctionPtr  func ,   void   * arg )
{
     Interrupt   * interrupt  =  kernel -> interrupt ;
     Scheduler   * scheduler  =  kernel -> scheduler ;
     IntStatus  oldLevel ;
    
    DEBUG ( dbgThread ,   "Forking thread: "   <<  name  <<   " f(a): "   <<   ( int )  func  <<   " "   <<  arg );
    
     StackAllocate ( func ,  arg );

    oldLevel  =  interrupt -> SetLevel ( IntOff );
    scheduler -> ReadyToRun ( this );      // ReadyToRun assumes that interrupts 
                     // are disabled!
     ( void )  interrupt -> SetLevel ( oldLevel );
}     

//----------------------------------------------------------------------
// Thread::CheckOverflow
//  Check a thread's stack to see if it has overrun the space
//  that has been allocated for it.  If we had a smarter compiler,
//  we wouldn't need to worry about this, but we don't.
//
//  NOTE: Nachos will not catch all stack overflow conditions.
//  In other words, your program may still crash because of an overflow.
//
//  If you get bizarre results (such as seg faults where there is no code)
//  then you *may* need to increase the stack size.  You can avoid stack
//  overflows by not putting large data structures on the stack.
//  Don't do this: void foo() { int bigArray[10000]; ... }
//----------------------------------------------------------------------

void
Thread :: CheckOverflow ()
{
     if   ( stack  !=  NULL )   {
#ifdef  HPUX          // Stacks grow upward on the Snakes
    ASSERT ( stack [ StackSize   -   1 ]   ==  STACK_FENCEPOST );
#else
    ASSERT ( * stack  ==  STACK_FENCEPOST );
#endif
    }
}

//----------------------------------------------------------------------
// Thread::Begin
//  Called by ThreadRoot when a thread is about to begin
//  executing the forked procedure.
//
//  It's main responsibilities are:
//  1. deallocate the previously running thread if it finished 
//      (see Thread::Finish())
//  2. enable interrupts (so we can get time-sliced)
//----------------------------------------------------------------------

void
Thread :: Begin   ()
{
    ASSERT ( this   ==  kernel -> currentThread );
    DEBUG ( dbgThread ,   "Beginning thread: "   <<  name );
    
    kernel -> scheduler -> CheckToBeDestroyed ();
    kernel -> interrupt -> Enable ();
}

//----------------------------------------------------------------------
// Thread::Finish
//  Called by ThreadRoot when a thread is done executing the 
//  forked procedure.
//
//  NOTE: we can't immediately de-allocate the thread data structure 
//  or the execution stack, because we're still running in the thread 
//  and we're still on the stack!  Instead, we tell the scheduler
//  to call the destructor, once it is running in the context of a different thread.
//
//  NOTE: we disable interrupts, because Sleep() assumes interrupts
//  are disabled.
//----------------------------------------------------------------------

//
void
Thread :: Finish   ()
{
     ( void )  kernel -> interrupt -> SetLevel ( IntOff );      
    ASSERT ( this   ==  kernel -> currentThread );
    
    DEBUG ( dbgThread ,   "Finishing thread: "   <<  name );
    
     Sleep ( TRUE );                  // invokes SWITCH
     // not reached
}

//----------------------------------------------------------------------
// Thread::Yield
//  Relinquish the CPU if any other thread is ready to run.
//  If so, put the thread on the end of the ready list, so that
//  it will eventually be re-scheduled.
//
//  NOTE: returns immediately if no other thread on the ready queue.
//  Otherwise returns when the thread eventually works its way
//  to the front of the ready list and gets re-scheduled.
//
//  NOTE: we disable interrupts, so that looking at the thread
//  on the front of the ready list, and switching to it, can be done
//  atomically.  On return, we re-set the interrupt level to its
//  original state, in case we are called with interrupts disabled. 
//
//  Similar to Thread::Sleep(), but a little different.
//----------------------------------------------------------------------

void
Thread :: Yield   ()
{
     Thread   * nextThread ;
     IntStatus  oldLevel  =  kernel -> interrupt -> SetLevel ( IntOff );
    
    ASSERT ( this   ==  kernel -> currentThread );
    
    DEBUG ( dbgThread ,   "Yielding thread: "   <<  name );
    
    nextThread  =  kernel -> scheduler -> FindNextToRun ();
     if   ( nextThread  !=  NULL )   {
    kernel -> scheduler -> ReadyToRun ( this );
    kernel -> scheduler -> Run ( nextThread ,  FALSE );
     }
     ( void )  kernel -> interrupt -> SetLevel ( oldLevel );
}

//----------------------------------------------------------------------
// Thread::Sleep
//  Relinquish the CPU, because the current thread has either
//  finished or is blocked waiting on a synchronization 
//  variable (Semaphore, Lock, or Condition).  In the latter case,
//  eventually some thread will wake this thread up, and put it
//  back on the ready queue, so that it can be re-scheduled.
//
//  NOTE: if there are no threads on the ready queue, that means
//  we have no thread to run.  "Interrupt::Idle" is called
//  to signify that we should idle the CPU until the next I/O interrupt
//  occurs (the only thing that could cause a thread to become
//  ready to run).
//
//  NOTE: we assume interrupts are already disabled, because it
//  is called from the synchronization routines which must
//  disable interrupts for atomicity.   We need interrupts off 
//  so that there can't be a time slice between pulling the first thread
//  off the ready list, and switching to it.
//----------------------------------------------------------------------
void
Thread :: Sleep   ( bool  finishing )
{
     Thread   * nextThread ;
    
    ASSERT ( this   ==  kernel -> currentThread );
    ASSERT ( kernel -> interrupt -> getLevel ()   ==   IntOff );
    
    DEBUG ( dbgThread ,   "Sleeping thread: "   <<  name );

    status  =  BLOCKED ;
     while   (( nextThread  =  kernel -> scheduler -> FindNextToRun ())   ==  NULL )
    kernel -> interrupt -> Idle ();    // no one to run, wait for an interrupt
    
     // returns when it's time for us to run
    kernel -> scheduler -> Run ( nextThread ,  finishing );  
}

//----------------------------------------------------------------------
// ThreadBegin, ThreadFinish,  ThreadPrint
//  Dummy functions because C++ does not (easily) allow pointers to member
//  functions.  So we create a dummy C function
//  (which we can pass a pointer to), that then simply calls the 
//  member function.
//----------------------------------------------------------------------

static   void   ThreadFinish ()      {  kernel -> currentThread -> Finish ();   }
static   void   ThreadBegin ()   {  kernel -> currentThread -> Begin ();   }
void   ThreadPrint ( Thread   * t )   {  t -> Print ();   }

#ifdef  PARISC

//----------------------------------------------------------------------
// PLabelToAddr
//  On HPUX, function pointers don't always directly point to code,
//  so we need to do the conversion.
//----------------------------------------------------------------------

static   void   *
PLabelToAddr ( void   * plabel )
{
     int  funcPtr  =   ( int )  plabel ;

     if   ( funcPtr  &   0x02 )   {
         // L-Field is set.  This is a PLT pointer
        funcPtr  -=   2 ;     // Get rid of the L bit
         return   ( * ( void   ** ) funcPtr );
     }   else   {
         // L-field not set.
         return  plabel ;
     }
}
#endif

//----------------------------------------------------------------------
// Thread::StackAllocate
//  Allocate and initialize an execution stack.  The stack is
//  initialized with an initial stack frame for ThreadRoot, which:
//      enables interrupts
//      calls (*func)(arg)
//      calls Thread::Finish
//
//  "func" is the procedure to be forked
//  "arg" is the parameter to be passed to the procedure
//----------------------------------------------------------------------

void
Thread :: StackAllocate   ( VoidFunctionPtr  func ,   void   * arg )
{
    stack  =   ( int   * )   AllocBoundedArray ( StackSize   *   sizeof ( int ));

#ifdef  PARISC
     // HP stack works from low addresses to high addresses
     // everyone else works the other way: from high addresses to low addresses
    stackTop  =  stack  +   16 ;    // HP requires 64-byte frame marker
    stack [ StackSize   -   1 ]   =  STACK_FENCEPOST ;
#endif

#ifdef  SPARC
    stackTop  =  stack  +   StackSize   -   96 ;    // SPARC stack must contains at 
                     // least 1 activation record 
                     // to start with.
     * stack  =  STACK_FENCEPOST ;
#endif  

#ifdef   PowerPC   // RS6000
    stackTop  =  stack  +   StackSize   -   16 ;    // RS6000 requires 64-byte frame marker
     * stack  =  STACK_FENCEPOST ;
#endif  

#ifdef  DECMIPS
    stackTop  =  stack  +   StackSize   -   4 ;     // -4 to be on the safe side!
     * stack  =  STACK_FENCEPOST ;
#endif

#ifdef  ALPHA
    stackTop  =  stack  +   StackSize   -   8 ;     // -8 to be on the safe side!
     * stack  =  STACK_FENCEPOST ;
#endif


#ifdef  x86
     // the x86 passes the return address on the stack.  In order for SWITCH() 
     // to go to ThreadRoot when we switch to this thread, the return addres 
     // used in SWITCH() must be the starting address of ThreadRoot.
    stackTop  =  stack  +   StackSize   -   4 ;     // -4 to be on the safe side!
     * ( -- stackTop )   =   ( int )   ThreadRoot ;
     * stack  =  STACK_FENCEPOST ;
#endif
    
#ifdef  PARISC
    machineState [ PCState ]   =   PLabelToAddr ( ThreadRoot );
    machineState [ StartupPCState ]   =   PLabelToAddr ( ThreadBegin );
    machineState [ InitialPCState ]   =   PLabelToAddr ( func );
    machineState [ InitialArgState ]   =  arg ;
    machineState [ WhenDonePCState ]   =   PLabelToAddr ( ThreadFinish );
#else
    machineState [ PCState ]   =   ( void * ) ThreadRoot ;
    machineState [ StartupPCState ]   =   ( void * ) ThreadBegin ;
    machineState [ InitialPCState ]   =   ( void * ) func ;
    machineState [ InitialArgState ]   =   ( void * ) arg ;
    machineState [ WhenDonePCState ]   =   ( void * ) ThreadFinish ;
#endif
}

#include   "machine.h"

//----------------------------------------------------------------------
// Thread::SaveUserState
//  Save the CPU state of a user program on a context switch.
//
//  Note that a user program thread has *two* sets of CPU registers -- 
//  one for its state while executing user code, one for its state 
//  while executing kernel code.  This routine saves the former.
//----------------------------------------------------------------------

void
Thread :: SaveUserState ()
{
     for   ( int  i  =   0 ;  i  <   NumTotalRegs ;  i ++ )
    userRegisters [ i ]   =  kernel -> machine -> ReadRegister ( i );
}

//----------------------------------------------------------------------
// Thread::RestoreUserState
//  Restore the CPU state of a user program on a context switch.
//
//  Note that a user program thread has *two* sets of CPU registers -- 
//  one for its state while executing user code, one for its state 
//  while executing kernel code.  This routine restores the former.
//----------------------------------------------------------------------

void
Thread :: RestoreUserState ()
{
     for   ( int  i  =   0 ;  i  <   NumTotalRegs ;  i ++ )
    kernel -> machine -> WriteRegister ( i ,  userRegisters [ i ]);
}


//----------------------------------------------------------------------
// SimpleThread
//  Loop 5 times, yielding the CPU to another ready thread 
//  each iteration.
//
//  "which" is simply a number identifying the thread, for debugging
//  purposes.
//----------------------------------------------------------------------

static   void
SimpleThread ( int  which )
{
     int  num ;
    
     for   ( num  =   0 ;  num  <   5 ;  num ++ )   {
    cout  <<   "*** thread "   <<  which  <<   " looped "   <<  num  <<   " times\n" ;
        kernel -> currentThread -> Yield ();
     }
}

//----------------------------------------------------------------------
// Thread::SelfTest
//  Set up a ping-pong between two threads, by forking a thread 
//  to call SimpleThread, and then calling SimpleThread ourselves.
//----------------------------------------------------------------------

void
Thread :: SelfTest ()
{
    DEBUG ( dbgThread ,   "Entering Thread::SelfTest" );

     Thread   * =   new   Thread ( "forked thread" );

    t -> Fork (( VoidFunctionPtr )   SimpleThread ,   ( void   * )   1 );
    kernel -> currentThread -> Yield ();
     SimpleThread ( 0 );
}

nachos/code/threads/synchlist.cc

nachos/code/threads/synchlist.cc

// synchlist.cc
//  Routines for synchronized access to a list.
//
//  Implemented in "monitor"-style -- surround each procedure with a
//  lock acquire and release pair, using condition signal and wait for
//  synchronization.
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include   "copyright.h"
#include   "synchlist.h"

//----------------------------------------------------------------------
// SynchList<T>::SynchList
//  Allocate and initialize the data structures needed for a 
//  synchronized list, empty to start with.
//  Elements can now be added to the list.
//----------------------------------------------------------------------

template   < class  T >
SynchList < T >:: SynchList ()
{
    list  =   new   List < T > ;
    lock  =   new   Lock ( "list lock" );  
    listEmpty  =   new   Condition ( "list empty cond" );
}

//----------------------------------------------------------------------
// SynchList<T>::~SynchList
//  De-allocate the data structures created for synchronizing a list. 
//----------------------------------------------------------------------

template   < class  T >
SynchList < T >::~ SynchList ()
{  
     delete  listEmpty ;
     delete  lock ;
     delete  list ;
}

//----------------------------------------------------------------------
// SynchList<T>::Append
//      Append an "item" to the end of the list.  Wake up anyone
//  waiting for an element to be appended.
//
//  "item" is the thing to put on the list. 
//----------------------------------------------------------------------

template   < class  T >
void
SynchList < T >:: Append ( T item )
{
    lock -> Acquire ();          // enforce mutual exclusive access to the list 
    list -> Append ( item );
    listEmpty -> Signal ( lock );      // wake up a waiter, if any
    lock -> Release ();
}

//----------------------------------------------------------------------
// SynchList<T>::RemoveFront
//      Remove an "item" from the beginning of the list.  Wait if
//  the list is empty.
// Returns:
//  The removed item. 
//----------------------------------------------------------------------

template   < class  T >
T
SynchList < T >:: RemoveFront ()
{
    T item ;

    lock -> Acquire ();              // enforce mutual exclusion
     while   ( list -> IsEmpty ())
    listEmpty -> Wait ( lock );        // wait until list isn't empty
    item  =  list -> RemoveFront ();
    lock -> Release ();
     return  item ;
}

//----------------------------------------------------------------------
// SynchList<T>::Apply
//      Apply function to every item on a list.
//
//      "func" -- the function to apply
//----------------------------------------------------------------------

template   < class  T >
void
SynchList < T >:: Apply ( void   ( * func )( T ))
{
    lock -> Acquire ();              // enforce mutual exclusion
    list -> Apply ( func );
    lock -> Release ();
}

//----------------------------------------------------------------------
// SynchList<T>::SelfTest, SelfTestHelper
//  Test whether the SynchList implementation is working,
//  by having two threads ping-pong a value between them
//  using two synchronized lists.
//----------------------------------------------------------------------

template   < class  T >
void
SynchList < T >:: SelfTestHelper   ( void *  data )  
{
     SynchList < T >*  _this  =   ( SynchList < T >* ) data ;
     for   ( int  i  =   0 ;  i  <   10 ;  i ++ )   {
        _this -> Append ( _this -> selfTestPing -> RemoveFront ());
     }
}

template   < class  T >
void
SynchList < T >:: SelfTest ( T val )
{
     Thread   * helper  =   new   Thread ( "ping" );
    
    ASSERT ( list -> IsEmpty ());
    selfTestPing  =   new   SynchList < T > ;
    helper -> Fork ( SynchList < T >:: SelfTestHelper ,   this );
     for   ( int  i  =   0 ;  i  <   10 ;  i ++ )   {
        selfTestPing -> Append ( val );
    ASSERT ( val  ==   this -> RemoveFront ());
     }
     delete  selfTestPing ;
}

nachos/code/threads/main.h

// main.h // This file defines the Nachos global variables // // Copyright (c) 1992-1996 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef MAIN_H #define MAIN_H #include "copyright.h" #include "debug.h" #include "kernel.h" extern Kernel *kernel; extern Debug *debug; #endif // MAIN_H

nachos/code/threads/switch.S

/* switch.s * Machine dependent context switch routines. DO NOT MODIFY THESE! * * Context switching is inherently machine dependent, since * the registers to be saved, how to set up an initial * call frame, etc, are all specific to a processor architecture. * * This file currently supports the following architectures: * DEC MIPS (DECMIPS) * DEC Alpha (ALPHA) * SUN SPARC (SPARC) * HP PA-RISC (PARISC) * Intel 386 (x86) * IBM RS6000 (PowerPC) -- I hope it will also work for Mac PowerPC * * We define two routines for each architecture: * * ThreadRoot(InitialPC, InitialArg, WhenDonePC, StartupPC) * InitialPC - The program counter of the procedure to run * in this thread. * InitialArg - The single argument to the thread. * WhenDonePC - The routine to call when the thread returns. * StartupPC - Routine to call when the thread is started. * * ThreadRoot is called from the SWITCH() routine to start * a thread for the first time. * * SWITCH(oldThread, newThread) * oldThread - The current thread that was running, where the * CPU register state is to be saved. * newThread - The new thread to be run, where the CPU register * state is to be loaded from. */ /* Copyright (c) 1992-1996 The Regents of the University of California. All rights reserved. See copyright.h for copyright notice and limitation of liability and disclaimer of warranty provisions. */ #include "copyright.h" #include "switch.h" #ifdef DECMIPS /* Symbolic register names */ #define z $0 /* zero register */ #define a0 $4 /* argument registers */ #define a1 $5 #define s0 $16 /* callee saved */ #define s1 $17 #define s2 $18 #define s3 $19 #define s4 $20 #define s5 $21 #define s6 $22 #define s7 $23 #define sp $29 /* stack pointer */ #define fp $30 /* frame pointer */ #define ra $31 /* return address */ .text .align 2 .globl ThreadRoot .ent ThreadRoot,0 ThreadRoot: or fp,z,z # Clearing the frame pointer here # makes gdb backtraces of thread stacks # end here (I hope!) jal StartupPC # call startup procedure move a0, InitialArg jal InitialPC # call main procedure jal WhenDonePC # when done, call clean up procedure # NEVER REACHED .end ThreadRoot # a0 -- pointer to old Thread # a1 -- pointer to new Thread .globl SWITCH .ent SWITCH,0 SWITCH: sw sp, SP(a0) # save new stack pointer sw s0, S0(a0) # save all the callee-save registers sw s1, S1(a0) sw s2, S2(a0) sw s3, S3(a0) sw s4, S4(a0) sw s5, S5(a0) sw s6, S6(a0) sw s7, S7(a0) sw fp, FP(a0) # save frame pointer sw ra, PC(a0) # save return address lw sp, SP(a1) # load the new stack pointer lw s0, S0(a1) # load the callee-save registers lw s1, S1(a1) lw s2, S2(a1) lw s3, S3(a1) lw s4, S4(a1) lw s5, S5(a1) lw s6, S6(a1) lw s7, S7(a1) lw fp, FP(a1) lw ra, PC(a1) # load the return address j ra .end SWITCH #endif // DECMIPS #ifdef SPARC /* NOTE! These files appear not to exist on Solaris -- * you need to find where (the SPARC-specific) MINFRAME, ST_FLUSH_WINDOWS, ... * are defined. (I don't have a Solaris machine, so I have no way to tell.) */ #ifdef SOLARIS #include <sys/trap.h> #include <sys/asm_linkage.h> #else #include <sun4/trap.h> #include <sun4/asm_linkage.h> #endif .seg "text" /* SPECIAL to the SPARC: * The first two instruction of ThreadRoot are skipped because * the address of ThreadRoot is made the return address of SWITCH() * by the routine Thread::StackAllocate. SWITCH() jumps here on the * "ret" instruction which is really at "jmp %o7+8". The 8 skips the * two nops at the beginning of the routine. */ #ifdef SOLARIS .globl ThreadRoot ThreadRoot: #else .globl _ThreadRoot _ThreadRoot: #endif nop ; nop /* These 2 nops are skipped because we are called * with a jmp+8 instruction. */ clr %fp /* Clearing the frame pointer makes gdb backtraces * of thread stacks end here. */ /* Currently the arguments are in out registers we * save them into local registers so they won't be * trashed during the calls we make. */ mov InitialPC, %l0 mov InitialArg, %l1 mov WhenDonePC, %l2 /* Execute the code: * call StartupPC(); * call InitialPC(InitialArg); * call WhenDonePC(); */ call StartupPC,0 nop call %l0, 1 mov %l1, %o0 /* Using delay slot to setup argument to InitialPC */ call %l2, 0 nop /* WhenDonePC call should never return. If it does * we execute a trap into the debugger. */ ta ST_BREAKPOINT #ifdef SOLARIS .globl SWITCH SWITCH: #else .globl _SWITCH _SWITCH: #endif save %sp, -SA(MINFRAME), %sp st %fp, [%i0] st %i0, [%i0+I0] st %i1, [%i0+I1] st %i2, [%i0+I2] st %i3, [%i0+I3] st %i4, [%i0+I4] st %i5, [%i0+I5] st %i7, [%i0+I7] ta ST_FLUSH_WINDOWS nop mov %i1, %l0 ld [%l0+I0], %i0 ld [%l0+I1], %i1 ld [%l0+I2], %i2 ld [%l0+I3], %i3 ld [%l0+I4], %i4 ld [%l0+I5], %i5 ld [%l0+I7], %i7 ld [%l0], %i6 ret restore #endif // SPARC #ifdef PARISC ;rp = r2, sp = r30 ;arg0 = r26, arg1 = r25, arg2 = r24, arg3 = r23 .SPACE $TEXT$ .SUBSPA $CODE$ ThreadRoot .PROC .CALLINFO CALLER,FRAME=0 .ENTER .CALL ble 0(%r6) ;call StartupPC stw %r31, -24(%sp) ;put return address in proper stack ;location for StartupPC export stub. or %r4, 0, %arg0 ;load InitialArg .CALL ;in=26 ble 0(%r3) ;call InitialPC stw %r31, -24(%sp) ;put return address in proper stack ;location for InitialPC export stub. .CALL ble 0(%r5) ;call WhenDonePC stw %r31, -24(%sp) ;put return address in proper stack ;location for StartupPC export stub. .LEAVE .PROCEND SWITCH .PROC .CALLINFO CALLER,FRAME=0 .ENTRY ; save process state of oldThread stw %sp, SP(%arg0) ;save stack pointer stw %r3, S0(%arg0) ;save callee-save registers stw %r4, S1(%arg0) stw %r5, S2(%arg0) stw %r6, S3(%arg0) stw %r7, S4(%arg0) stw %r8, S5(%arg0) stw %r9, S6(%arg0) stw %r10, S7(%arg0) stw %r11, S8(%arg0) stw %r12, S9(%arg0) stw %r13, S10(%arg0) stw %r14, S11(%arg0) stw %r15, S12(%arg0) stw %r16, S13(%arg0) stw %r17, S14(%arg0) stw %r18, S15(%arg0) stw %rp, PC(%arg0) ;save program counter ; restore process state of nextThread ldw SP(%arg1), %sp ;restore stack pointer ldw S0(%arg1), %r3 ;restore callee-save registers ldw S1(%arg1), %r4 ldw S2(%arg1), %r5 ldw S3(%arg1), %r6 ldw S4(%arg1), %r7 ldw S5(%arg1), %r8 ldw S6(%arg1), %r9 ldw S7(%arg1), %r10 ldw S8(%arg1), %r11 ldw S9(%arg1), %r12 ldw S10(%arg1), %r13 ldw S11(%arg1), %r14 ldw S12(%arg1), %r15 ldw S13(%arg1), %r16 ldw S14(%arg1), %r17 ldw PC(%arg1), %rp ;save program counter bv 0(%rp) .EXIT ldw S15(%arg1), %r18 .PROCEND .EXPORT SWITCH,ENTRY,PRIV_LEV=3,RTNVAL=GR .EXPORT ThreadRoot,ENTRY,PRIV_LEV=3,RTNVAL=GR #endif // PARISC #ifdef x86 .text .align 2 .globl ThreadRoot .globl _ThreadRoot /* void ThreadRoot( void ) ** ** expects the following registers to be initialized: ** eax points to startup function (interrupt enable) ** edx contains inital argument to thread function ** esi points to thread function ** edi point to Thread::Finish() */ _ThreadRoot: ThreadRoot: pushl %ebp movl %esp,%ebp pushl InitialArg call *StartupPC call *InitialPC call *WhenDonePC # NOT REACHED movl %ebp,%esp popl %ebp ret /* void SWITCH( thread *t1, thread *t2 ) ** ** on entry, stack looks like this: ** 8(esp) -> thread *t2 ** 4(esp) -> thread *t1 ** (esp) -> return address ** ** we push the current eax on the stack so that we can use it as ** a pointer to t1, this decrements esp by 4, so when we use it ** to reference stuff on the stack, we add 4 to the offset. */ .comm _eax_save,4 .globl SWITCH .globl _SWITCH _SWITCH: SWITCH: movl %eax,_eax_save # save the value of eax movl 4(%esp),%eax # move pointer to t1 into eax movl %ebx,_EBX(%eax) # save registers movl %ecx,_ECX(%eax) movl %edx,_EDX(%eax) movl %esi,_ESI(%eax) movl %edi,_EDI(%eax) movl %ebp,_EBP(%eax) movl %esp,_ESP(%eax) # save stack pointer movl _eax_save,%ebx # get the saved value of eax movl %ebx,_EAX(%eax) # store it movl 0(%esp),%ebx # get return address from stack into ebx movl %ebx,_PC(%eax) # save it into the pc storage movl 8(%esp),%eax # move pointer to t2 into eax movl _EAX(%eax),%ebx # get new value for eax into ebx movl %ebx,_eax_save # save it movl _EBX(%eax),%ebx # retore old registers movl _ECX(%eax),%ecx movl _EDX(%eax),%edx movl _ESI(%eax),%esi movl _EDI(%eax),%edi movl _EBP(%eax),%ebp movl _ESP(%eax),%esp # restore stack pointer movl _PC(%eax),%eax # restore return address into eax movl %eax,4(%esp) # copy over the ret address on the stack movl _eax_save,%eax ret #endif // x86 #if defined(ApplePowerPC) /* The AIX PowerPC code is incompatible with the assembler on MacOS X * and Linux. So the SWITCH code was adapted for IBM 750 compatible * processors, and ThreadRoot is modeled after the more reasonable * looking ThreadRoot's in this file. * * Joshua LeVasseur <[email protected]> */ .align 2 .globl _SWITCH _SWITCH: stw r1, 0(r3) /* Store stack pointer. */ stmw r13, 20(r3) /* Store general purpose registers 13 - 31. */ stfd f14, 96(r3) /* Store floating point registers 14 -31. */ stfd f15, 104(r3) stfd f16, 112(r3) stfd f17, 120(r3) stfd f18, 128(r3) stfd f19, 136(r3) stfd f20, 144(r3) stfd f21, 152(r3) stfd f22, 160(r3) stfd f23, 168(r3) stfd f24, 176(r3) stfd f25, 184(r3) stfd f26, 192(r3) stfd f27, 200(r3) stfd f28, 208(r3) stfd f29, 216(r3) stfd f30, 224(r3) stfd f31, 232(r3) mflr r0 stw r0, 244(r3) /* Spill the link register. */ mfcr r12 stw r12, 240(r3) /* Spill the condition register. */ lwz r1, 0(r4) /* Load the incoming stack pointer. */ lwz r0, 244(r4) /* Load the incoming link register. */ mtlr r0 /* Restore the link register. */ lwz r12, 240(r4) /* Load the condition register value. */ mtcrf 0xff, r12 /* Restore the condition register. */ lmw r13, 20(r4) /* Restore registers r13 - r31. */ lfd f14, 96(r4) /* Restore floating point register f14 - f31. */ lfd f15, 104(r4) lfd f16, 112(r4) lfd f17, 120(r4) lfd f18, 128(r4) lfd f19, 136(r4) lfd f20, 144(r4) lfd f21, 152(r4) lfd f22, 160(r4) lfd f23, 168(r4) lfd f24, 176(r4) lfd f25, 184(r4) lfd f26, 192(r4) lfd f27, 200(r4) lfd f28, 208(r4) lfd f29, 216(r4) lfd f30, 224(r4) lfd f31, 232(r4) /* When a thread first starts, the following blr instruction jumps * to ThreadRoot. ThreadRoot expects the incoming thread block * in r4. */ blr /* Branch to the address held in link register. */ .align 2 .globl _ThreadRoot _ThreadRoot: lwz r20, 16(r4) /* StartupPCState - ThreadBegin */ lwz r21, 8(r4) /* InitialArgState - arg */ lwz r22, 4(r4) /* InitialPCState - func */ lwz r23, 12(r4) /* WhenDonePCState - ThreadFinish */ /* Call ThreadBegin function. */ mtctr r20 /* The function pointer. */ bctrl /* Call the target function. */ mr r3, r21 /* Function arg. */ mtctr r22 /* Function pointer. */ bctrl /* Call the ThreadFinish function. */ mtctr r23 bctrl /* We shouldn't execute here. */ 1: b 1b #endif #if defined(PowerPC) && !defined(ApplePowerPC) .globl branch[ds] .csect branch[ds] .long .branch[PR] .long TOC[tc0] .long 0 .toc T.branch: .tc .branch[tc], branch[ds] .globl .branch[PR] .csect .branch[PR] l 0, 0x0(11) # load function address into r0 mtctr 0 # move r0 into counter register l 2, 0x4(11) # move new TOC address into r2 l 11, 0x8(11) # reset function address bctr # branch to the counter register .globl ThreadRoot[ds] .csect ThreadRoot[ds] .long .ThreadRoot[PR] .long TOC[tc0] .long 0 .toc T.ThreadRoot: .tc .ThreadRoot[tc], ThreadRoot[ds] .globl .ThreadRoot[PR] .csect .ThreadRoot[PR] .set argarea, 32 .set linkarea, 24 .set locstckarea, 0 .set nfprs, 18 .set ngprs, 19 .set szdsa, 8*nfprs+4*ngprs+linkarea+argarea+locstckarea mflr 0 mfcr 12 bl ._savef14 cror 0xf, 0xf, 0xf stm 13, -8*nfprs-4*ngprs(1) st 0, 8(1) st 12, 4(1) st 4, 24(1) st 5, 28(1) st 6, 32(1) stu 1, -szdsa(1) muli 11,3,1 # copy contents of register r24 to r11 bl .branch[PR] # call function branch cror 0xf, 0xf, 0xf # no operation ai 1,1,szdsa lm 13, -8*nfprs-4*ngprs(1) bl ._restf14 cror 0xf, 0xf, 0xf l 0, 8(1) l 12, 4(1) mtlr 0 mtcrf 0x38, 12 l 4, 24(1) l 5, 28(1) l 6, 32(1) mflr 0 mfcr 12 bl ._savef14 cror 0xf, 0xf, 0xf stm 13, -8*nfprs-4*ngprs(1) st 0, 8(1) st 12, 4(1) st 6, 24(1) stu 1, -szdsa(1) muli 3, 4,1 # load user function parameter r22 to r3 muli 11,5,1 # copy contents of register r21 to r11 bl .branch[PR] # call function branch cror 0xf, 0xf, 0xf # no operation ai 1,1,szdsa lm 13, -8*nfprs-4*ngprs(1) bl ._restf14 cror 0xf, 0xf, 0xf l 0, 8(1) l 12, 4(1) mtlr 0 mtcrf 0x38, 12 l 6, 24(1) muli 11,6,1 # copy contents of register r23 to r11 bl .branch[PR] # call function branch cror 0xf, 0xf, 0xf # no operation brl # the programme should not return here. .extern ._savef14 .extern ._restf14 .globl SWITCH[ds] .csect SWITCH[ds] .long .SWITCH[PR] .long TOC[tc0] .long 0 .toc T.SWITCH: .tc .SWITCH[tc], SWITCH[ds] .globl .SWITCH[PR] .csect .SWITCH[PR] st 1, 0(3) # store stack pointer stm 13, 20(3) # store general purpose registers (13 -31) stfd 14, 96(3) # store floating point registers (14 -31) stfd 15, 104(3) # there is no single instruction to do for stfd 16, 112(3) # floating point registers. so do one by one stfd 17, 120(3) stfd 18, 128(3) stfd 19, 136(3) stfd 20, 144(3) stfd 21, 152(3) stfd 22, 160(3) stfd 23, 168(3) stfd 24, 176(3) stfd 25, 184(3) stfd 26, 192(3) stfd 27, 200(3) stfd 28, 208(3) stfd 29, 216(3) stfd 30, 224(3) stfd 31, 232(3) mflr 0 # move link register value to register 0 st 0, 244(3) # store link register value mfcr 12 # move condition register to register 12 st 12, 240(3) # store condition register value l 1, 0(4) # load stack pointer l 0, 244(4) # load link register value mtlr 0 l 12, 240(4) # load condition register value mtcrf 0x38, 12 lm 13, 20(4) # load into general purpose registers (13 -31) lfd 14, 96(4) # load into floating point registers (14 -31) lfd 15, 104(4) # there is no single instruction for lfd 16, 112(4) # loading into more than one floating point lfd 17, 120(4) # registers. so do one by one. lfd 18, 128(4) lfd 19, 136(4) lfd 20, 144(4) lfd 21, 152(4) lfd 22, 160(4) lfd 23, 168(4) lfd 24, 176(4) lfd 25, 184(4) lfd 26, 192(4) lfd 27, 200(4) lfd 28, 208(4) lfd 29, 216(4) lfd 30, 224(4) lfd 31, 232(4) l 3, 16(4) l 5, 4(4) l 6, 12(4) l 4, 8(4) brl # branch to the address held in link register. #endif // PowerPC #ifdef ALPHA /* * Porting to Alpha was done by Shuichi Oikawa ([email protected]). */ /* * Symbolic register names and register saving rules * * Legend: * T Saved by caller (Temporaries) * S Saved by callee (call-Safe registers) */ #define v0 $0 /* (T) return value */ #define t0 $1 /* (T) temporary registers */ #define s0 $9 /* (S) call-safe registers */ #define s1 $10 #define s2 $11 #define s3 $12 #define s4 $13 #define s5 $14 #define s6 $15 #define a0 $16 /* (T) argument registers */ #define a1 $17 #define ai $25 /* (T) argument information */ #define ra $26 /* (T) return address */ #define pv $27 /* (T) procedure value */ #define gp $29 /* (T) (local) data pointer */ #define sp $30 /* (S) stack pointer */ #define zero $31 /* wired zero */ .set noreorder # unless overridden .align 3 .text .globl ThreadRoot .ent ThreadRoot,0 ThreadRoot: .frame sp,0,ra ldgp gp,0(pv) mov zero,s6 # Clearing the frame pointer here # makes gdb backtraces of thread stacks # end here (I hope!) mov StartupPC,pv jsr ra,(pv) # call startup procedure ldgp gp,0(ra) mov InitialArg,a0 mov InitialPC,pv jsr ra,(pv) # call main procedure ldgp gp,0(ra) mov WhenDonePC,pv jsr ra,(pv) # when done, call clean up procedure ldgp gp,0(ra) .end ThreadRoot # NEVER REACHED /* a0 -- pointer to old Thread * * a1 -- pointer to new Thread */ .globl SWITCH .ent SWITCH,0 SWITCH: .frame sp,0,ra ldgp gp,0(pv) stq ra, PC(a0) # save return address stq gp, GP(a0) stq sp, SP(a0) # save new stack pointer stq s0, S0(a0) # save all the callee-save registers stq s1, S1(a0) stq s2, S2(a0) stq s3, S3(a0) stq s4, S4(a0) stq s5, S5(a0) stq s6, S6(a0) # save frame pointer ldq ra, PC(a1) # load the return address ldq gp, GP(a1) ldq sp, SP(a1) # load the new stack pointer ldq s0, S0(a1) # load the callee-save registers ldq s1, S1(a1) ldq s2, S2(a1) ldq s3, S3(a1) ldq s4, S4(a1) ldq s5, S5(a1) ldq s6, S6(a1) mov ra,pv ret zero,(ra) .end SWITCH #endif // ALPHA

nachos/code/threads/thread.h

// thread.h // Data structures for managing threads. A thread represents // sequential execution of code within a program. // So the state of a thread includes the program counter, // the processor registers, and the execution stack. // // Note that because we allocate a fixed size stack for each // thread, it is possible to overflow the stack -- for instance, // by recursing to too deep a level. The most common reason // for this occuring is allocating large data structures // on the stack. For instance, this will cause problems: // // void foo() { int buf[1000]; ...} // // Instead, you should allocate all data structures dynamically: // // void foo() { int *buf = new int[1000]; ...} // // // Bad things happen if you overflow the stack, and in the worst // case, the problem may not be caught explicitly. Instead, // the only symptom may be bizarre segmentation faults. (Of course, // other problems can cause seg faults, so that isn't a sure sign // that your thread stacks are too small.) // // One thing to try if you find yourself with seg faults is to // increase the size of thread stack -- ThreadStackSize. // // In this interface, forking a thread takes two steps. // We must first allocate a data structure for it: "t = new Thread". // Only then can we do the fork: "t->fork(f, arg)". // // Copyright (c) 1992-1996 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef THREAD_H #define THREAD_H #include "copyright.h" #include "utility.h" #include "sysdep.h" #include "machine.h" #include "addrspace.h" // CPU register state to be saved on context switch. // The x86 needs to save only a few registers, // SPARC and MIPS needs to save 10 registers, // the Snake needs 18, // and the RS6000 needs to save 75 (!) // For simplicity, I just take the maximum over all architectures. #define MachineStateSize 75 // Size of the thread's private execution stack. // WATCH OUT IF THIS ISN'T BIG ENOUGH!!!!! const int StackSize = (8 * 1024); // in words // Thread state enum ThreadStatus { JUST_CREATED, RUNNING, READY, BLOCKED }; // The following class defines a "thread control block" -- which // represents a single thread of execution. // // Every thread has: // an execution stack for activation records ("stackTop" and "stack") // space to save CPU registers while not running ("machineState") // a "status" (running/ready/blocked) // // Some threads also belong to a user address space; threads // that only run in the kernel have a NULL address space. class Thread { private: // NOTE: DO NOT CHANGE the order of these first two members. // THEY MUST be in this position for SWITCH to work. int *stackTop; // the current stack pointer void *machineState[MachineStateSize]; // all registers except for stackTop public: Thread(char* debugName); // initialize a Thread ~Thread(); // deallocate a Thread // NOTE -- thread being deleted // must not be running when delete // is called // basic thread operations void Fork(VoidFunctionPtr func, void *arg); // Make thread run (*func)(arg) void Yield(); // Relinquish the CPU if any // other thread is runnable void Sleep(bool finishing); // Put the thread to sleep and // relinquish the processor void Begin(); // Startup code for the thread void Finish(); // The thread is done executing void CheckOverflow(); // Check if thread stack has overflowed void setStatus(ThreadStatus st) { status = st; } char* getName() { return (name); } void Print() { cout << name; } void SelfTest(); // test whether thread impl is working private: // some of the private data for this class is listed above int *stack; // Bottom of the stack // NULL if this is the main thread // (If NULL, don't deallocate stack) ThreadStatus status; // ready, running or blocked char* name; void StackAllocate(VoidFunctionPtr func, void *arg); // Allocate a stack for thread. // Used internally by Fork() // A thread running a user program actually has *two* sets of CPU registers -- // one for its state while executing user code, one for its state // while executing kernel code. int userRegisters[NumTotalRegs]; // user-level CPU register state public: void SaveUserState(); // save user-level register state void RestoreUserState(); // restore user-level register state AddrSpace *space; // User code this thread is running. }; // external function, dummy routine whose sole job is to call Thread::Print extern void ThreadPrint(Thread *thread); // Magical machine-dependent routines, defined in switch.s extern "C" { // First frame on thread execution stack; // call ThreadBegin // call "func" // (when func returns, if ever) call ThreadFinish() void ThreadRoot(); // Stop running oldThread and start running newThread void SWITCH(Thread *oldThread, Thread *newThread); } #endif // THREAD_H

nachos/code/threads/kernel.cc

nachos/code/threads/kernel.cc

// kernel.cc 
//  Initialization and cleanup routines for the Nachos kernel.
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include   "copyright.h"
#include   "debug.h"
#include   "main.h"
#include   "kernel.h"
#include   "sysdep.h"
#include   "synch.h"
#include   "synchlist.h"
#include   "libtest.h"
#include   "string.h"
#include   "synchconsole.h"
#include   "synchdisk.h"
#include   "post.h"

//----------------------------------------------------------------------
// Kernel::Kernel
//  Interpret command line arguments in order to determine flags 
//  for the initialization (see also comments in main.cc)  
//----------------------------------------------------------------------

Kernel :: Kernel ( int  argc ,   char   ** argv )
{
    randomSlice  =  FALSE ;  
    debugUserProg  =  FALSE ;
    consoleIn  =  NULL ;            // default is stdin
    consoleOut  =  NULL ;           // default is stdout
#ifndef  FILESYS_STUB
    formatFlag  =  FALSE ;
#endif
    reliability  =   1 ;              // network reliability, default is 1.0
    hostName  =   0 ;                 // machine id, also UNIX socket name
                                 // 0 is the default machine id
     for   ( int  i  =   1 ;  i  <  argc ;  i ++ )   {
         if   ( strcmp ( argv [ i ],   "-rs" )   ==   0 )   {
        ASSERT ( +   1   <  argc );
         RandomInit ( atoi ( argv [ +   1 ])); // initialize pseudo-random
                     // number generator
        randomSlice  =  TRUE ;
        i ++ ;
         }   else   if   ( strcmp ( argv [ i ],   "-s" )   ==   0 )   {
            debugUserProg  =  TRUE ;
     }   else   if   ( strcmp ( argv [ i ],   "-ci" )   ==   0 )   {
        ASSERT ( +   1   <  argc );
        consoleIn  =  argv [ +   1 ];
        i ++ ;
     }   else   if   ( strcmp ( argv [ i ],   "-co" )   ==   0 )   {
        ASSERT ( +   1   <  argc );
        consoleOut  =  argv [ +   1 ];
        i ++ ;
#ifndef  FILESYS_STUB
     }   else   if   ( strcmp ( argv [ i ],   "-f" )   ==   0 )   {
        formatFlag  =  TRUE ;
#endif
         }   else   if   ( strcmp ( argv [ i ],   "-n" )   ==   0 )   {
            ASSERT ( +   1   <  argc );     // next argument is float
            reliability  =  atof ( argv [ +   1 ]);
            i ++ ;
         }   else   if   ( strcmp ( argv [ i ],   "-m" )   ==   0 )   {
            ASSERT ( +   1   <  argc );     // next argument is int
            hostName  =  atoi ( argv [ +   1 ]);
            i ++ ;
         }   else   if   ( strcmp ( argv [ i ],   "-u" )   ==   0 )   {
            cout  <<   "Partial usage: nachos [-rs randomSeed]\n" ;
        cout  <<   "Partial usage: nachos [-s]\n" ;
            cout  <<   "Partial usage: nachos [-ci consoleIn] [-co consoleOut]\n" ;
#ifndef  FILESYS_STUB
        cout  <<   "Partial usage: nachos [-nf]\n" ;
#endif
            cout  <<   "Partial usage: nachos [-n #] [-m #]\n" ;
     }
     }
}

//----------------------------------------------------------------------
// Kernel::Initialize
//  Initialize Nachos global data structures.  Separate from the 
//  constructor because some of these refer to earlier initialized
//  data via the "kernel" global variable.
//----------------------------------------------------------------------

void
Kernel :: Initialize ()
{
     // We didn't explicitly allocate the current thread we are running in.
     // But if it ever tries to give up the CPU, we better have a Thread
     // object to save its state. 
    currentThread  =   new   Thread ( "main" );      
    currentThread -> setStatus ( RUNNING );

    stats  =   new   Statistics ();         // collect statistics
    interrupt  =   new   Interrupt ;        // start up interrupt handling
    scheduler  =   new   Scheduler ();      // initialize the ready queue
    alarm  =   new   Alarm ( randomSlice );   // start up time slicing
    machine  =   new   Machine ( debugUserProg );
    synchConsoleIn  =   new   SynchConsoleInput ( consoleIn );   // input from stdin
    synchConsoleOut  =   new   SynchConsoleOutput ( consoleOut );   // output to stdout
    synchDisk  =   new   SynchDisk ();      //
#ifdef  FILESYS_STUB
    fileSystem  =   new   FileSystem ();
#else
    fileSystem  =   new   FileSystem ( formatFlag );
#endif   // FILESYS_STUB
    postOfficeIn  =   new   PostOfficeInput ( 10 );
    postOfficeOut  =   new   PostOfficeOutput ( reliability );

    interrupt -> Enable ();
}

//----------------------------------------------------------------------
// Kernel::~Kernel
//  Nachos is halting.  De-allocate global data structures.
//----------------------------------------------------------------------

Kernel ::~ Kernel ()
{
     delete  stats ;
     delete  interrupt ;
     delete  scheduler ;
     delete  alarm ;
     delete  machine ;
     delete  synchConsoleIn ;
     delete  synchConsoleOut ;
     delete  synchDisk ;
     delete  fileSystem ;
     delete  postOfficeIn ;
     delete  postOfficeOut ;
    
     Exit ( 0 );
}

//----------------------------------------------------------------------
// Kernel::ThreadSelfTest
//      Test threads, semaphores, synchlists
//----------------------------------------------------------------------

void
Kernel :: ThreadSelfTest ()   {
    Semaphore   * semaphore ;
    SynchList < int >   * synchList ;
   
    LibSelfTest ();         // test library routines
   currentThread -> SelfTest ();     // test thread switching
   
                 // test semaphore operation
   semaphore  =   new   Semaphore ( "test" ,   0 );
   semaphore -> SelfTest ();
    delete  semaphore ;
   
                 // test locks, condition variables
                 // using synchronized lists
   synchList  =   new   SynchList < int > ;
   synchList -> SelfTest ( 9 );
    delete  synchList ;

}

//----------------------------------------------------------------------
// Kernel::ConsoleTest
//      Test the synchconsole
//----------------------------------------------------------------------

void
Kernel :: ConsoleTest ()   {
     char  ch ;

    cout  <<   "Testing the console device.\n"  
         <<   "Typed characters will be echoed, until ^D is typed.\n"
         <<   "Note newlines are needed to flush input through UNIX.\n" ;
    cout . flush ();

     do   {
        ch  =  synchConsoleIn -> GetChar ();
         if ( ch  !=  EOF )  synchConsoleOut -> PutChar ( ch );     // echo it!
     }   while   ( ch  !=  EOF );

    cout  <<   "\n" ;

}

//----------------------------------------------------------------------
// Kernel::NetworkTest
//      Test whether the post office is working. On machines #0 and #1, do:
//
//      1. send a message to the other machine at mail box #0
//      2. wait for the other machine's message to arrive (in our mailbox #0)
//      3. send an acknowledgment for the other machine's message
//      4. wait for an acknowledgement from the other machine to our 
//          original message
//
//  This test works best if each Nachos machine has its own window
//----------------------------------------------------------------------

void
Kernel :: NetworkTest ()   {

     if   ( hostName  ==   0   ||  hostName  ==   1 )   {
         // if we're machine 1, send to 0 and vice versa
         int  farHost  =   ( hostName  ==   0   ?   1   :   0 );  
         PacketHeader  outPktHdr ,  inPktHdr ;
         MailHeader  outMailHdr ,  inMailHdr ;
         char   * data  =   "Hello there!" ;
         char   * ack  =   "Got it!" ;
         char  buffer [ MaxMailSize ];

         // construct packet, mail header for original message
         // To: destination machine, mailbox 0
         // From: our machine, reply to: mailbox 1
        outPktHdr . to  =  farHost ;          
        outMailHdr . to  =   0 ;
        outMailHdr . from  =   1 ;
        outMailHdr . length  =  strlen ( data )   +   1 ;

         // Send the first message
        postOfficeOut -> Send ( outPktHdr ,  outMailHdr ,  data );  

         // Wait for the first message from the other machine
        postOfficeIn -> Receive ( 0 ,   & inPktHdr ,   & inMailHdr ,  buffer );
        cout  <<   "Got: "   <<  buffer  <<   " : from "   <<  inPktHdr . from  <<   ", box "  
                                                 <<  inMailHdr . from  <<   "\n" ;
        cout . flush ();

         // Send acknowledgement to the other machine (using "reply to" mailbox
         // in the message that just arrived
        outPktHdr . to  =  inPktHdr . from ;
        outMailHdr . to  =  inMailHdr . from ;
        outMailHdr . length  =  strlen ( ack )   +   1 ;
        postOfficeOut -> Send ( outPktHdr ,  outMailHdr ,  ack );  

         // Wait for the ack from the other machine to the first message we sent
    postOfficeIn -> Receive ( 1 ,   & inPktHdr ,   & inMailHdr ,  buffer );
        cout  <<   "Got: "   <<  buffer  <<   " : from "   <<  inPktHdr . from  <<   ", box "  
                                                 <<  inMailHdr . from  <<   "\n" ;
        cout . flush ();
     }

     // Then we're done!
}

nachos/code/threads/synchlist.h

// synchlist.h // Data structures for synchronized access to a list. // // Identical interface to List, except accesses are synchronized. // // Copyright (c) 1992-1996 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef SYNCHLIST_H #define SYNCHLIST_H #include "copyright.h" #include "list.h" #include "synch.h" // The following class defines a "synchronized list" -- a list for which // these constraints hold: // 1. Threads trying to remove an item from a list will // wait until the list has an element on it. // 2. One thread at a time can access list data structures template <class T> class SynchList { public: SynchList(); // initialize a synchronized list ~SynchList(); // de-allocate a synchronized list void Append(T item); // append item to the end of the list, // and wake up any thread waiting in remove T RemoveFront(); // remove the first item from the front of // the list, waiting if the list is empty void Apply(void (*f)(T)); // apply function to all elements in list void SelfTest(T value); // test the SynchList implementation private: List<T> *list; // the list of things Lock *lock; // enforce mutual exclusive access to the list Condition *listEmpty; // wait in Remove if the list is empty // these are only to assist SelfTest() SynchList<T> *selfTestPing; static void SelfTestHelper(void* data); }; #include "synchlist.cc" #endif // SYNCHLIST_H

nachos/code/threads/scheduler.cc

nachos/code/threads/scheduler.cc

// scheduler.cc 
//  Routines to choose the next thread to run, and to dispatch to
//  that thread.
//
//  These routines assume that interrupts are already disabled.
//  If interrupts are disabled, we can assume mutual exclusion
//  (since we are on a uniprocessor).
//
//  NOTE: We can't use Locks to provide mutual exclusion here, since
//  if we needed to wait for a lock, and the lock was busy, we would 
//  end up calling FindNextToRun(), and that would put us in an 
//  infinite loop.
//
//  Very simple implementation -- no priorities, straight FIFO.
//  Might need to be improved in later assignments.
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include   "copyright.h"
#include   "debug.h"
#include   "scheduler.h"
#include   "main.h"

//----------------------------------------------------------------------
// Scheduler::Scheduler
//  Initialize the list of ready but not running threads.
//  Initially, no ready threads.
//----------------------------------------------------------------------

Scheduler :: Scheduler ()
{  
    readyList  =   new   List < Thread   *> ;  
    toBeDestroyed  =  NULL ;
}  

//----------------------------------------------------------------------
// Scheduler::~Scheduler
//  De-allocate the list of ready threads.
//----------------------------------------------------------------------

Scheduler ::~ Scheduler ()
{  
     delete  readyList ;  
}  

//----------------------------------------------------------------------
// Scheduler::ReadyToRun
//  Mark a thread as ready, but not running.
//  Put it on the ready list, for later scheduling onto the CPU.
//
//  "thread" is the thread to be put on the ready list.
//----------------------------------------------------------------------

void
Scheduler :: ReadyToRun   ( Thread   * thread )
{
    ASSERT ( kernel -> interrupt -> getLevel ()   ==   IntOff );
    DEBUG ( dbgThread ,   "Putting thread on ready list: "   <<   thread -> getName ());

     thread -> setStatus ( READY );
    readyList -> Append ( thread );
}

//----------------------------------------------------------------------
// Scheduler::FindNextToRun
//  Return the next thread to be scheduled onto the CPU.
//  If there are no ready threads, return NULL.
// Side effect:
//  Thread is removed from the ready list.
//----------------------------------------------------------------------

Thread   *
Scheduler :: FindNextToRun   ()
{
    ASSERT ( kernel -> interrupt -> getLevel ()   ==   IntOff );

     if   ( readyList -> IsEmpty ())   {
     return  NULL ;
     }   else   {
         return  readyList -> RemoveFront ();
     }
}

//----------------------------------------------------------------------
// Scheduler::Run
//  Dispatch the CPU to nextThread.  Save the state of the old thread,
//  and load the state of the new thread, by calling the machine
//  dependent context switch routine, SWITCH.
//
//      Note: we assume the state of the previously running thread has
//  already been changed from running to blocked or ready (depending).
// Side effect:
//  The global variable kernel->currentThread becomes nextThread.
//
//  "nextThread" is the thread to be put into the CPU.
//  "finishing" is set if the current thread is to be deleted
//      once we're no longer running on its stack
//      (when the next thread starts running)
//----------------------------------------------------------------------

void
Scheduler :: Run   ( Thread   * nextThread ,   bool  finishing )
{
     Thread   * oldThread  =  kernel -> currentThread ;
    
    ASSERT ( kernel -> interrupt -> getLevel ()   ==   IntOff );

     if   ( finishing )   {      // mark that we need to delete current thread
         ASSERT ( toBeDestroyed  ==  NULL );
     toBeDestroyed  =  oldThread ;
     }
    
     if   ( oldThread -> space  !=  NULL )   {   // if this thread is a user program,
        oldThread -> SaveUserState ();       // save the user's CPU registers
    oldThread -> space -> SaveState ();
     }
    
    oldThread -> CheckOverflow ();           // check if the old thread
                         // had an undetected stack overflow

    kernel -> currentThread  =  nextThread ;    // switch to the next thread
    nextThread -> setStatus ( RUNNING );        // nextThread is now running
    
    DEBUG ( dbgThread ,   "Switching from: "   <<  oldThread -> getName ()   <<   " to: "   <<  nextThread -> getName ());
    
     // This is a machine-dependent assembly language routine defined 
     // in switch.s.  You may have to think
     // a bit to figure out what happens after this, both from the point
     // of view of the thread and from the perspective of the "outside world".

    SWITCH ( oldThread ,  nextThread );

     // we're back, running oldThread
      
     // interrupts are off when we return from switch!
    ASSERT ( kernel -> interrupt -> getLevel ()   ==   IntOff );

    DEBUG ( dbgThread ,   "Now in thread: "   <<  oldThread -> getName ());

     CheckToBeDestroyed ();         // check if thread we were running
                     // before this one has finished
                     // and needs to be cleaned up
    
     if   ( oldThread -> space  !=  NULL )   {       // if there is an address space
        oldThread -> RestoreUserState ();       // to restore, do it.
    oldThread -> space -> RestoreState ();
     }
}

//----------------------------------------------------------------------
// Scheduler::CheckToBeDestroyed
//  If the old thread gave up the processor because it was finishing,
//  we need to delete its carcass.  Note we cannot delete the thread
//  before now (for example, in Thread::Finish()), because up to this
//  point, we were still running on the old thread's stack!
//----------------------------------------------------------------------

void
Scheduler :: CheckToBeDestroyed ()
{
     if   ( toBeDestroyed  !=  NULL )   {
         delete  toBeDestroyed ;
    toBeDestroyed  =  NULL ;
     }
}
 
//----------------------------------------------------------------------
// Scheduler::Print
//  Print the scheduler state -- in other words, the contents of
//  the ready list.  For debugging.
//----------------------------------------------------------------------
void
Scheduler :: Print ()
{
    cout  <<   "Ready list contents:\n" ;
    readyList -> Apply ( ThreadPrint );
}

nachos/code/threads/kernel.h

// kernel.h // Global variables for the Nachos kernel. // // Copyright (c) 1992-1996 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef KERNEL_H #define KERNEL_H #include "copyright.h" #include "debug.h" #include "utility.h" #include "thread.h" #include "scheduler.h" #include "interrupt.h" #include "stats.h" #include "alarm.h" #include "filesys.h" #include "machine.h" class PostOfficeInput; class PostOfficeOutput; class SynchConsoleInput; class SynchConsoleOutput; class SynchDisk; class Kernel { public: Kernel(int argc, char **argv); // Interpret command line arguments ~Kernel(); // deallocate the kernel void Initialize(); // initialize the kernel -- separated // from constructor because // refers to "kernel" as a global void ThreadSelfTest(); // self test of threads and synchronization void ConsoleTest(); // interactive console self test void NetworkTest(); // interactive 2-machine network test // These are public for notational convenience; really, // they're global variables used everywhere. Thread *currentThread; // the thread holding the CPU Scheduler *scheduler; // the ready list Interrupt *interrupt; // interrupt status Statistics *stats; // performance metrics Alarm *alarm; // the software alarm clock Machine *machine; // the simulated CPU SynchConsoleInput *synchConsoleIn; SynchConsoleOutput *synchConsoleOut; SynchDisk *synchDisk; FileSystem *fileSystem; PostOfficeInput *postOfficeIn; PostOfficeOutput *postOfficeOut; int hostName; // machine identifier private: bool randomSlice; // enable pseudo-random time slicing bool debugUserProg; // single step user program double reliability; // likelihood messages are dropped char *consoleIn; // file to read console input from char *consoleOut; // file to send console output to #ifndef FILESYS_STUB bool formatFlag; // format the disk if this is true #endif }; #endif // KERNEL_H

nachos/code/build.linux/Makefile.dep

################################################################## # Machine Dependencies - this file is included automatically # into the main Makefile # # This file contains definitions below for x86 running Linux # It has *not* been tested! ################################################################## HOSTCFLAGS = -Dx86 -DLINUX #----------------------------------------------------------------- # Do not put anything below this point - it will be destroyed by # "make depend" # # DO NOT DELETE THIS LINE -- make depend uses it bitmap.o: ../lib/bitmap.cc /usr/include/stdc-predef.h ../lib/copyright.h \ ../lib/debug.h ../lib/utility.h ../lib/sysdep.h \ /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h \ ../lib/bitmap.h debug.o: ../lib/debug.cc /usr/include/stdc-predef.h ../lib/copyright.h \ ../lib/utility.h ../lib/debug.h ../lib/sysdep.h \ /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h hash.o: ../lib/hash.cc /usr/include/stdc-predef.h ../lib/copyright.h libtest.o: ../lib/libtest.cc /usr/include/stdc-predef.h \ ../lib/copyright.h ../lib/libtest.h ../lib/bitmap.h ../lib/utility.h \ ../lib/list.h ../lib/debug.h ../lib/sysdep.h /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h \ ../lib/list.cc ../lib/hash.h ../lib/hash.cc list.o: ../lib/list.cc /usr/include/stdc-predef.h ../lib/copyright.h sysdep.o: ../lib/sysdep.cc /usr/include/stdc-predef.h ../lib/copyright.h \ ../lib/debug.h ../lib/utility.h ../lib/sysdep.h \ /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h \ /usr/include/unistd.h /usr/include/x86_64-linux-gnu/bits/posix_opt.h \ /usr/include/x86_64-linux-gnu/bits/environments.h \ /usr/include/x86_64-linux-gnu/bits/confname.h /usr/include/getopt.h \ /usr/include/x86_64-linux-gnu/sys/time.h \ /usr/include/x86_64-linux-gnu/sys/file.h /usr/include/fcntl.h \ /usr/include/x86_64-linux-gnu/bits/fcntl.h \ /usr/include/x86_64-linux-gnu/bits/fcntl-linux.h \ /usr/include/x86_64-linux-gnu/bits/uio.h \ /usr/include/x86_64-linux-gnu/bits/stat.h \ /usr/include/x86_64-linux-gnu/sys/socket.h \ /usr/include/x86_64-linux-gnu/sys/uio.h \ /usr/include/x86_64-linux-gnu/bits/socket.h \ /usr/include/x86_64-linux-gnu/bits/socket_type.h \ /usr/include/x86_64-linux-gnu/bits/sockaddr.h \ /usr/include/x86_64-linux-gnu/asm/socket.h \ /usr/include/asm-generic/socket.h \ /usr/include/x86_64-linux-gnu/asm/sockios.h \ /usr/include/asm-generic/sockios.h \ /usr/include/x86_64-linux-gnu/sys/un.h /usr/include/c++/5/cerrno \ /usr/include/errno.h /usr/include/x86_64-linux-gnu/bits/errno.h \ /usr/include/linux/errno.h /usr/include/x86_64-linux-gnu/asm/errno.h \ /usr/include/asm-generic/errno.h /usr/include/asm-generic/errno-base.h \ /usr/include/signal.h /usr/include/x86_64-linux-gnu/bits/signum.h \ /usr/include/x86_64-linux-gnu/bits/siginfo.h \ /usr/include/x86_64-linux-gnu/bits/sigaction.h \ /usr/include/x86_64-linux-gnu/bits/sigcontext.h \ /usr/include/x86_64-linux-gnu/bits/sigstack.h \ /usr/include/x86_64-linux-gnu/sys/ucontext.h \ /usr/include/x86_64-linux-gnu/bits/sigthread.h interrupt.o: ../machine/interrupt.cc /usr/include/stdc-predef.h \ ../lib/copyright.h ../machine/interrupt.h ../lib/list.h ../lib/debug.h \ ../lib/utility.h ../lib/sysdep.h /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h \ ../lib/list.cc ../machine/callback.h ../threads/main.h \ ../threads/kernel.h ../threads/thread.h ../machine/machine.h \ ../machine/translate.h ../userprog/addrspace.h ../filesys/filesys.h \ ../filesys/openfile.h ../threads/scheduler.h ../machine/stats.h \ ../threads/alarm.h ../machine/timer.h stats.o: ../machine/stats.cc /usr/include/stdc-predef.h \ ../lib/copyright.h ../lib/debug.h ../lib/utility.h ../lib/sysdep.h \ /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h \ ../machine/stats.h timer.o: ../machine/timer.cc /usr/include/stdc-predef.h \ ../lib/copyright.h ../machine/timer.h ../lib/utility.h \ ../machine/callback.h ../threads/main.h ../lib/debug.h ../lib/sysdep.h \ /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h \ ../threads/kernel.h ../threads/thread.h ../machine/machine.h \ ../machine/translate.h ../userprog/addrspace.h ../filesys/filesys.h \ ../filesys/openfile.h ../threads/scheduler.h ../lib/list.h \ ../lib/list.cc ../machine/interrupt.h ../machine/stats.h \ ../threads/alarm.h console.o: ../machine/console.cc /usr/include/stdc-predef.h \ ../lib/copyright.h ../machine/console.h ../lib/utility.h \ ../machine/callback.h ../threads/main.h ../lib/debug.h ../lib/sysdep.h \ /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h \ ../threads/kernel.h ../threads/thread.h ../machine/machine.h \ ../machine/translate.h ../userprog/addrspace.h ../filesys/filesys.h \ ../filesys/openfile.h ../threads/scheduler.h ../lib/list.h \ ../lib/list.cc ../machine/interrupt.h ../machine/stats.h \ ../threads/alarm.h ../machine/timer.h machine.o: ../machine/machine.cc /usr/include/stdc-predef.h \ ../lib/copyright.h ../machine/machine.h ../lib/utility.h \ ../machine/translate.h ../threads/main.h ../lib/debug.h ../lib/sysdep.h \ /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h \ ../threads/kernel.h ../threads/thread.h ../userprog/addrspace.h \ ../filesys/filesys.h ../filesys/openfile.h ../threads/scheduler.h \ ../lib/list.h ../lib/list.cc ../machine/interrupt.h \ ../machine/callback.h ../machine/stats.h ../threads/alarm.h \ ../machine/timer.h mipssim.o: ../machine/mipssim.cc /usr/include/stdc-predef.h \ ../lib/copyright.h ../lib/debug.h ../lib/utility.h ../lib/sysdep.h \ /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h \ ../machine/machine.h ../machine/translate.h ../machine/mipssim.h \ ../threads/main.h ../threads/kernel.h ../threads/thread.h \ ../userprog/addrspace.h ../filesys/filesys.h ../filesys/openfile.h \ ../threads/scheduler.h ../lib/list.h ../lib/list.cc \ ../machine/interrupt.h ../machine/callback.h ../machine/stats.h \ ../threads/alarm.h ../machine/timer.h translate.o: ../machine/translate.cc /usr/include/stdc-predef.h \ ../lib/copyright.h ../threads/main.h ../lib/debug.h ../lib/utility.h \ ../lib/sysdep.h /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h \ ../threads/kernel.h ../threads/thread.h ../machine/machine.h \ ../machine/translate.h ../userprog/addrspace.h ../filesys/filesys.h \ ../filesys/openfile.h ../threads/scheduler.h ../lib/list.h \ ../lib/list.cc ../machine/interrupt.h ../machine/callback.h \ ../machine/stats.h ../threads/alarm.h ../machine/timer.h network.o: ../machine/network.cc /usr/include/stdc-predef.h \ ../lib/copyright.h ../machine/network.h ../lib/utility.h \ ../machine/callback.h ../threads/main.h ../lib/debug.h ../lib/sysdep.h \ /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h \ ../threads/kernel.h ../threads/thread.h ../machine/machine.h \ ../machine/translate.h ../userprog/addrspace.h ../filesys/filesys.h \ ../filesys/openfile.h ../threads/scheduler.h ../lib/list.h \ ../lib/list.cc ../machine/interrupt.h ../machine/stats.h \ ../threads/alarm.h ../machine/timer.h disk.o: ../machine/disk.cc /usr/include/stdc-predef.h ../lib/copyright.h \ ../machine/disk.h ../lib/utility.h ../machine/callback.h ../lib/debug.h \ ../lib/sysdep.h /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h \ ../threads/main.h ../threads/kernel.h ../threads/thread.h \ ../machine/machine.h ../machine/translate.h ../userprog/addrspace.h \ ../filesys/filesys.h ../filesys/openfile.h ../threads/scheduler.h \ ../lib/list.h ../lib/list.cc ../machine/interrupt.h ../machine/stats.h \ ../threads/alarm.h ../machine/timer.h alarm.o: ../threads/alarm.cc /usr/include/stdc-predef.h \ ../lib/copyright.h ../threads/alarm.h ../lib/utility.h \ ../machine/callback.h ../machine/timer.h ../threads/main.h \ ../lib/debug.h ../lib/sysdep.h /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h \ ../threads/kernel.h ../threads/thread.h ../machine/machine.h \ ../machine/translate.h ../userprog/addrspace.h ../filesys/filesys.h \ ../filesys/openfile.h ../threads/scheduler.h ../lib/list.h \ ../lib/list.cc ../machine/interrupt.h ../machine/stats.h kernel.o: ../threads/kernel.cc /usr/include/stdc-predef.h \ ../lib/copyright.h ../lib/debug.h ../lib/utility.h ../lib/sysdep.h \ /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h \ ../threads/main.h ../threads/kernel.h ../threads/thread.h \ ../machine/machine.h ../machine/translate.h ../userprog/addrspace.h \ ../filesys/filesys.h ../filesys/openfile.h ../threads/scheduler.h \ ../lib/list.h ../lib/list.cc ../machine/interrupt.h \ ../machine/callback.h ../machine/stats.h ../threads/alarm.h \ ../machine/timer.h ../threads/synch.h ../threads/synchlist.h \ ../threads/synchlist.cc ../lib/libtest.h ../userprog/synchconsole.h \ ../machine/console.h ../filesys/synchdisk.h ../machine/disk.h \ ../network/post.h ../machine/network.h main.o: ../threads/main.cc /usr/include/stdc-predef.h ../lib/copyright.h \ ../threads/main.h ../lib/debug.h ../lib/utility.h ../lib/sysdep.h \ /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h \ ../threads/kernel.h ../threads/thread.h ../machine/machine.h \ ../machine/translate.h ../userprog/addrspace.h ../filesys/filesys.h \ ../filesys/openfile.h ../threads/scheduler.h ../lib/list.h \ ../lib/list.cc ../machine/interrupt.h ../machine/callback.h \ ../machine/stats.h ../threads/alarm.h ../machine/timer.h scheduler.o: ../threads/scheduler.cc /usr/include/stdc-predef.h \ ../lib/copyright.h ../lib/debug.h ../lib/utility.h ../lib/sysdep.h \ /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h \ ../threads/scheduler.h ../lib/list.h ../lib/list.cc ../threads/thread.h \ ../machine/machine.h ../machine/translate.h ../userprog/addrspace.h \ ../filesys/filesys.h ../filesys/openfile.h ../threads/main.h \ ../threads/kernel.h ../machine/interrupt.h ../machine/callback.h \ ../machine/stats.h ../threads/alarm.h ../machine/timer.h synch.o: ../threads/synch.cc /usr/include/stdc-predef.h \ ../lib/copyright.h ../threads/synch.h ../threads/thread.h \ ../lib/utility.h ../lib/sysdep.h /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h \ ../machine/machine.h ../machine/translate.h ../userprog/addrspace.h \ ../filesys/filesys.h ../filesys/openfile.h ../lib/list.h ../lib/debug.h \ ../lib/list.cc ../threads/main.h ../threads/kernel.h \ ../threads/scheduler.h ../machine/interrupt.h ../machine/callback.h \ ../machine/stats.h ../threads/alarm.h ../machine/timer.h synchlist.o: ../threads/synchlist.cc /usr/include/stdc-predef.h \ ../lib/copyright.h ../threads/synchlist.h ../lib/list.h ../lib/debug.h \ ../lib/utility.h ../lib/sysdep.h /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h \ ../lib/list.cc ../threads/synch.h ../threads/thread.h \ ../machine/machine.h ../machine/translate.h ../userprog/addrspace.h \ ../filesys/filesys.h ../filesys/openfile.h ../threads/main.h \ ../threads/kernel.h ../threads/scheduler.h ../machine/interrupt.h \ ../machine/callback.h ../machine/stats.h ../threads/alarm.h \ ../machine/timer.h ../threads/synchlist.cc thread.o: ../threads/thread.cc /usr/include/stdc-predef.h \ ../lib/copyright.h ../threads/thread.h ../lib/utility.h ../lib/sysdep.h \ /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h \ ../machine/machine.h ../machine/translate.h ../userprog/addrspace.h \ ../filesys/filesys.h ../filesys/openfile.h ../threads/switch.h \ ../threads/synch.h ../lib/list.h ../lib/debug.h ../lib/list.cc \ ../threads/main.h ../threads/kernel.h ../threads/scheduler.h \ ../machine/interrupt.h ../machine/callback.h ../machine/stats.h \ ../threads/alarm.h ../machine/timer.h threadtest.o: ../threads/threadtest.cc /usr/include/stdc-predef.h \ ../threads/kernel.h ../lib/copyright.h ../lib/debug.h ../lib/utility.h \ ../lib/sysdep.h /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h \ ../threads/thread.h ../machine/machine.h ../machine/translate.h \ ../userprog/addrspace.h ../filesys/filesys.h ../filesys/openfile.h \ ../threads/scheduler.h ../lib/list.h ../lib/list.cc \ ../machine/interrupt.h ../machine/callback.h ../machine/stats.h \ ../threads/alarm.h ../machine/timer.h addrspace.o: ../userprog/addrspace.cc /usr/include/stdc-predef.h \ ../lib/copyright.h ../threads/main.h ../lib/debug.h ../lib/utility.h \ ../lib/sysdep.h /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h \ ../threads/kernel.h ../threads/thread.h ../machine/machine.h \ ../machine/translate.h ../userprog/addrspace.h ../filesys/filesys.h \ ../filesys/openfile.h ../threads/scheduler.h ../lib/list.h \ ../lib/list.cc ../machine/interrupt.h ../machine/callback.h \ ../machine/stats.h ../threads/alarm.h ../machine/timer.h \ ../userprog/noff.h exception.o: ../userprog/exception.cc /usr/include/stdc-predef.h \ ../lib/copyright.h ../threads/main.h ../lib/debug.h ../lib/utility.h \ ../lib/sysdep.h /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h \ ../threads/kernel.h ../threads/thread.h ../machine/machine.h \ ../machine/translate.h ../userprog/addrspace.h ../filesys/filesys.h \ ../filesys/openfile.h ../threads/scheduler.h ../lib/list.h \ ../lib/list.cc ../machine/interrupt.h ../machine/callback.h \ ../machine/stats.h ../threads/alarm.h ../machine/timer.h \ ../userprog/syscall.h ../userprog/errno.h ../userprog/ksyscall.h synchconsole.o: ../userprog/synchconsole.cc /usr/include/stdc-predef.h \ ../lib/copyright.h ../userprog/synchconsole.h ../lib/utility.h \ ../machine/callback.h ../machine/console.h ../threads/synch.h \ ../threads/thread.h ../lib/sysdep.h /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h \ ../machine/machine.h ../machine/translate.h ../userprog/addrspace.h \ ../filesys/filesys.h ../filesys/openfile.h ../lib/list.h ../lib/debug.h \ ../lib/list.cc ../threads/main.h ../threads/kernel.h \ ../threads/scheduler.h ../machine/interrupt.h ../machine/stats.h \ ../threads/alarm.h ../machine/timer.h directory.o: ../filesys/directory.cc /usr/include/stdc-predef.h \ ../lib/copyright.h ../lib/utility.h ../filesys/filehdr.h \ ../machine/disk.h ../machine/callback.h ../filesys/pbitmap.h \ ../lib/bitmap.h ../filesys/openfile.h ../lib/sysdep.h \ /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h \ ../filesys/directory.h filehdr.o: ../filesys/filehdr.cc /usr/include/stdc-predef.h \ ../lib/copyright.h ../filesys/filehdr.h ../machine/disk.h \ ../lib/utility.h ../machine/callback.h ../filesys/pbitmap.h \ ../lib/bitmap.h ../filesys/openfile.h ../lib/sysdep.h \ /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h \ ../lib/debug.h ../filesys/synchdisk.h ../threads/synch.h \ ../threads/thread.h ../machine/machine.h ../machine/translate.h \ ../userprog/addrspace.h ../filesys/filesys.h ../lib/list.h \ ../lib/list.cc ../threads/main.h ../threads/kernel.h \ ../threads/scheduler.h ../machine/interrupt.h ../machine/stats.h \ ../threads/alarm.h ../machine/timer.h filesys.o: ../filesys/filesys.cc /usr/include/stdc-predef.h pbitmap.o: ../filesys/pbitmap.cc /usr/include/stdc-predef.h \ ../lib/copyright.h ../filesys/pbitmap.h ../lib/bitmap.h ../lib/utility.h \ ../filesys/openfile.h ../lib/sysdep.h /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h openfile.o: ../filesys/openfile.cc /usr/include/stdc-predef.h synchdisk.o: ../filesys/synchdisk.cc /usr/include/stdc-predef.h \ ../lib/copyright.h ../filesys/synchdisk.h ../machine/disk.h \ ../lib/utility.h ../machine/callback.h ../threads/synch.h \ ../threads/thread.h ../lib/sysdep.h /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h \ ../machine/machine.h ../machine/translate.h ../userprog/addrspace.h \ ../filesys/filesys.h ../filesys/openfile.h ../lib/list.h ../lib/debug.h \ ../lib/list.cc ../threads/main.h ../threads/kernel.h \ ../threads/scheduler.h ../machine/interrupt.h ../machine/stats.h \ ../threads/alarm.h ../machine/timer.h post.o: ../network/post.cc /usr/include/stdc-predef.h ../lib/copyright.h \ ../network/post.h ../lib/utility.h ../machine/callback.h \ ../machine/network.h ../threads/synchlist.h ../lib/list.h ../lib/debug.h \ ../lib/sysdep.h /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h \ ../lib/list.cc ../threads/synch.h ../threads/thread.h \ ../machine/machine.h ../machine/translate.h ../userprog/addrspace.h \ ../filesys/filesys.h ../filesys/openfile.h ../threads/main.h \ ../threads/kernel.h ../threads/scheduler.h ../machine/interrupt.h \ ../machine/stats.h ../threads/alarm.h ../machine/timer.h \ ../threads/synchlist.cc # DEPENDENCIES MUST END AT END OF FILE # IF YOU PUT STUFF HERE IT WILL GO AWAY # see make depend above

nachos/code/build.linux/Makefile

# Copyright (c) 1992-1996 The Regents of the University of California. # All rights reserved. See copyright.h for copyright notice and limitation # of liability and disclaimer of warranty provisions. # # This is a GNU Makefile. It must be used with the GNU make program. # At UW, the GNU make program is /software/gnu/bin/make. # In many other places it is known as "gmake". # You may wish to include /software/gnu/bin/ early in your command # search path, so that you will be using GNU make when you type "make". # # About this Makefile: # -------------------- # # This Makefile is used to build the Nachos system, which includes # the MIPS machine simulation and a simple operating system. # # There is a separate Makefile, in the "test" directory, that is # used to build the Nachos test programs (which run on the # simulated machine). # # There are several "build" directories, one for each type # of machine in the MFCF computing environment # (build.solaris, build.sunos, and build.ultrix), as well # as a build directory for Linux (build.linux) and a generic # build directory (build.other) for those who wish to try # building Nachos on other platforms. # # This Makefile appears to be located in all of the build directories. # If you edit it in one directory, the copies in all of the other # directories appear to change as well. This is the desired behaviour, # since this file is machine independent. (The file actually lives # in build.solaris, with symbolic links from the other build directories.) # # The platform-dependent parts of make's instructions are located # in the file Makefile.dep. # There is a different Makefile.dep in each build directory. # # If you are in the MFCF environment, you should not have to edit # the Makefile.dep files by hand. Any changes to the make instructions # can be made in this file (see the instructions below) - they will # apply no matter where you build Nachos. # If you are not in the MFCF environment, e.g., if you are trying # to build Nachos on Linux at home, you will probably need # to edit Makefile.dep (in the appropriate build directory) to # customize the make procedure to your environment. # # How to build Nachos for the first time: # --------------------------------------- # # (1) Make sure than you are in the build directory for the # type of machine you are logged in to (the "host" machine): # # host type examples build directory # ----------- ----------- ---------------- # # sparc/SunOS cayley,napier, build.sunos # (SunOS 4.1.3) descartes # # sparc/Solaris picard.math, build.solaris # (SunOS 5.x) hermite.math, # markov.math, # hypatia.math, # hume.math # # mips/ULTRIX cantor.math build.ultrix # (ULTRIX 4.2) noether.math # # If you are not sure what type of machine you are on, # try the command "uname -a". # # (2) Type "make depend" # - this computes file dependencies and records them # at the end of the file Makefile.dep in # your build directory. Have a look... # # (3) Type "make nachos" (or just "make"). # - make echos the commands it is executing, so that # you can observe its progress. When the # build is finished, you should have an # executable "nachos" in the build directory. # # (4) There is no 4th step. You are done. Try running "./nachos -u". # # # How to Re-build Nachos after you have changed the code: #-------------------------------------------------------- # # - The Nachos source code is located in the code subdirectories: # threads, userprog, filesys, network, and lib. You may # change the files in any of these directories, and you can # add new files and/or remove files. The "machine" subdirectory # contains the hardware simulation (which is also part of # Nachos. You may look at it, but # you may not change it, except as noted in machine/machine.h # - When you want to re-make Nachos, always do it in the # "build" directory that is appropriate for the machine # type that you are running on. # DO NOT TRY TO MAKE NACHOS IN THE SOURCE CODE DIRECTORIES. # # - IF all you have done is changed C++ code in existing files # (since the last time you made Nachos in this build directory), # THEN all you need to do to re-make Nachos is to type # # "make nachos" # # in the build directory. # # - IF you have done any of the following since the last build in # this directory: # added new .cc files or new .h files # added or deleted #include's from existing files # THEN # you must do # "make depend" # followed by # "make nachos" # # in the build directory. # # Note that is is always safe to do "make depend" followed by # "make nachos", so if you are not sure what changes you have # made, do "make depend". # # - IF you have added new files (.cc or .h) since the last build, # you should edit this Makefile before running "make depend" # and "make nachos". # For new .h files, simply update the appropriate "_H" list below. # For example, if you create a file called # "bigfile.h" in the filesys subdirectory, you should add # "../filesys/bigfile.h" to FILESYS_H, which is defined below # For new .cc files, update the appropriate "_C" and "_O" lists. # For example, if you create a file called "filetable.cc" in # the directory "userprog", you should add # "../userprog/filetable.cc" to USERPROG_C, # and you should add "filetable.o" to USERPROG_O. # Note that the entry in the "_C" list includes the subdirectory # name, while the entry on the "_O" list does not. # # Some Important Notes: # --------------------- # # * You can clean up all of the .o and other files left behind # by make by typeing "make clean" in the build directory. # * You can clean up .o and other files, as well as the nachos # executable, DISK, core, SOCKET, and other files by typing # make "distclean" # # These are good ways to save space, but the next build that # you do after cleaning will take longer than usual, since # much of the stuff you cleaned will need to be rebuilt. # # * When you build Nachos on an ULTRIX machine (in build.ultrix), # you will get lots of warning messages like this: # # openfile.o: does not have gp tables for all it's sectons # # from the loader. Ignore them. Or better yet, figure out # how to make them go away. # # The Most Important Note: # ----------------------- # # * If "make" is behaving strangely and you cannot figure out # why, you should REBUILD the program FROM SCRATCH. # Yes, it is slow. # But, there are lots of little things that can go wrong, especially # with all of these different types of machines available. # Rebuilding from scratch at least gives you a known starting # place. To rebuild from scratch, go to the appropriate # build directory and do: # # make distclean # make depend # make nachos # ################################################################ # READ THIS: CONFIGURING NACHOS # # Change DEFINES (below) to # DEFINES = -DUSE_TLB -DFILESYS_STUB # if you want the simulated machine to use its TLB # # If you want to use the real Nachos file system (based on # the simulated disk), rather than the stub, remove # the -DFILESYS_STUB from DEFINES. # # There is a a fix to the MIPS simulator to enable it to properly # handle unaligned data access. This fix is enabled by the addition # of "-DSIM_FIX" to the DEFINES. This should be enabled by default # and eventually will not require the symbol definition ################################################################ DEFINES = -DFILESYS_STUB -DRDATA -DSIM_FIX ##################################################################### # # You might want to play with the CFLAGS, but if you use -O it may # break the thread system. You might want to use -fno-inline if # you need to call some inline functions from the debugger. CFLAGS = -g -Wall $(INCPATH) $(DEFINES) $(HOSTCFLAGS) -DCHANGED -m32 LDFLAGS = -m32 CPP_AS_FLAGS= -m32 ##################################################################### CPP=/lib/cpp CC = g++ LD = g++ AS = as RM = /bin/rm INCPATH = -I../network -I../filesys -I../userprog -I../threads -I../machine -I../lib -I- PROGRAM = nachos # # Edit these lists as if you add files to the source directories. # See the instructions at the top of the file for more information. # LIB_H = ../lib/bitmap.h\ ../lib/copyright.h\ ../lib/debug.h\ ../lib/hash.h\ ../lib/libtest.h\ ../lib/list.h\ ../lib/sysdep.h\ ../lib/utility.h LIB_C = ../lib/bitmap.cc\ ../lib/debug.cc\ ../lib/hash.cc\ ../lib/libtest.cc\ ../lib/list.cc\ ../lib/sysdep.cc LIB_O = bitmap.o debug.o libtest.o sysdep.o MACHINE_H = ../machine/callback.h\ ../machine/interrupt.h\ ../machine/stats.h\ ../machine/timer.h\ ../machine/console.h\ ../machine/machine.h\ ../machine/mipssim.h\ ../machine/translate.h\ ../machine/network.h\ ../machine/disk.h MACHINE_C = ../machine/interrupt.cc\ ../machine/stats.cc\ ../machine/timer.cc\ ../machine/console.cc\ ../machine/machine.cc\ ../machine/mipssim.cc\ ../machine/translate.cc\ ../machine/network.cc\ ../machine/disk.cc MACHINE_O = interrupt.o stats.o timer.o console.o machine.o mipssim.o\ translate.o network.o disk.o THREAD_H = ../threads/alarm.h\ ../threads/kernel.h\ ../threads/main.h\ ../threads/scheduler.h\ ../threads/switch.h\ ../threads/synch.h\ ../threads/synchlist.h\ ../threads/thread.h THREAD_C = ../threads/alarm.cc\ ../threads/kernel.cc\ ../threads/main.cc\ ../threads/scheduler.cc\ ../threads/synch.cc\ ../threads/synchlist.cc\ ../threads/thread.cc\ ../threads/threadtest.cc THREAD_O = alarm.o kernel.o main.o scheduler.o synch.o thread.o threadtest.o USERPROG_H = ../userprog/addrspace.h\ ../userprog/syscall.h\ ../userprog/synchconsole.h\ ../userprog/noff.h USERPROG_C = ../userprog/addrspace.cc\ ../userprog/exception.cc\ ../userprog/synchconsole.cc USERPROG_O = addrspace.o exception.o synchconsole.o FILESYS_H =../filesys/directory.h \ ../filesys/filehdr.h\ ../filesys/filesys.h \ ../filesys/openfile.h\ ../filesys/pbitmap.h\ ../filesys/synchdisk.h FILESYS_C =../filesys/directory.cc\ ../filesys/filehdr.cc\ ../filesys/filesys.cc\ ../filesys/pbitmap.cc\ ../filesys/openfile.cc\ ../filesys/synchdisk.cc FILESYS_O =directory.o filehdr.o filesys.o pbitmap.o openfile.o synchdisk.o NETWORK_H = ../network/post.h NETWORK_C = ../network/post.cc NETWORK_O = post.o ################################################################## # You probably don't want to change anything below this point in # the file unless you are comfortable with GNU make and know what # you are doing... ################################################################## THREAD_S = ../threads/switch.s HFILES = $(LIB_H) $(MACHINE_H) $(THREAD_H) $(USERPROG_H) $(FILESYS_H) $(NETWORK_H) CFILES = $(LIB_C) $(MACHINE_C) $(THREAD_C) $(USERPROG_C) $(FILESYS_C) $(NETWORK_C) C_OFILES = $(LIB_O) $(MACHINE_O) $(THREAD_O) $(USERPROG_O) $(FILESYS_O) $(NETWORK_O) S_OFILES = switch.o OFILES = $(C_OFILES) $(S_OFILES) $(PROGRAM): $(OFILES) $(LD) $(OFILES) $(LDFLAGS) -o $(PROGRAM) $(C_OFILES): %.o: $(CC) $(CFLAGS) -c $< switch.o: ../threads/switch.S $(CC) $(CPP_AS_FLAGS) -P $(INCPATH) $(HOSTCFLAGS) -c ../threads/switch.S depend: $(CFILES) $(HFILES) $(CC) $(INCPATH) $(DEFINES) $(HOSTCFLAGS) -DCHANGED -M $(CFILES) > makedep @echo '/^# DO NOT DELETE THIS LINE/+1,$$d' >eddep @echo '$$r makedep' >>eddep @echo 'w' >>eddep @echo 'q' >>eddep ed - Makefile.dep < eddep rm eddep makedep @echo '# DEPENDENCIES MUST END AT END OF FILE' >> Makefile.dep @echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >> Makefile.dep @echo '# see make depend above' >> Makefile.dep clean: $(RM) -f $(OFILES) nachos DISK_0 distclean: clean $(RM) -f $(PROGRAM) $(RM) -f DISK_? $(RM) -f core $(RM) -f SOCKET_? @echo '/^# DO NOT DELETE THIS LINE/+1,$$d' >eddep @echo 'w' >>eddep @echo 'q' >>eddep ed - Makefile.dep < eddep rm eddep @echo '# DEPENDENCIES MUST END AT END OF FILE' >> Makefile.dep @echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >> Makefile.dep @echo '# see make depend above' >> Makefile.dep include Makefile.dep

nachos/code/userprog/noff.h

/* noff.h * Data structures defining the Nachos Object Code Format * * Basically, we only know about three types of segments: * code (read-only), initialized data, and unitialized data */ #define NOFFMAGIC 0xbadfad /* magic number denoting Nachos * object code file */ typedef struct segment { int virtualAddr; /* location of segment in virt addr space */ int inFileAddr; /* location of segment in this file */ int size; /* size of segment */ } Segment; typedef struct noffHeader { int noffMagic; /* should be NOFFMAGIC */ Segment code; /* executable code segment */ Segment initData; /* initialized data segment */ #ifdef RDATA Segment readonlyData; /* read only data */ #endif Segment uninitData; /* uninitialized data segment -- * should be zero'ed before use */ } NoffHeader;

nachos/code/userprog/errno.h

/* errno.h * Error codes for system calls. * * Do not modify the contents of this file. * * Try to use the most descriptive error number for the error. * You may find it helpful to see what errors equivalent UNIX * system calls return under various error conditions. * For example the man page for the write system call "man 2 write" * provides a list of different error number values for different * conditions. * NOTE: there are way more errors here than you should be supporting * and many more error conditions listed in man pages than * Nachos can possibly generate. The list here is to give you * some ideas and to hopefully standardize on some error numbers. * * ALSO NOTE: These definitions may not correspond to Solaris definitions * (for copyright reasons these are taken from Linux). */ #ifndef ERRNO_H #define ERRNO_H #include "copyright.h" #define EPERM -1 /* Operation not permitted */ #define ENOENT -2 /* No such file or directory */ #define ESRCH -3 /* No such process */ #define EINTR -4 /* Interrupted system call */ #define EIO -5 /* I/O error */ #define ENXIO -6 /* No such device or address */ #define E2BIG -7 /* Arg list too long */ #define ENOEXEC -8 /* Exec format error */ #define EBADF -9 /* Bad file number */ #define ECHILD -10 /* No child processes */ #define EAGAIN -11 /* Try again */ #define ENOMEM -12 /* Out of memory */ #define EACCES -13 /* Permission denied */ #define EFAULT -14 /* Bad address */ #define ENOTBLK -15 /* Block device required */ #define EBUSY -16 /* Device or resource busy */ #define EEXIST -17 /* File exists */ #define EXDEV -18 /* Cross-device link */ #define ENODEV -19 /* No such device */ #define ENOTDIR -20 /* Not a directory */ #define EISDIR -21 /* Is a directory */ #define EINVAL -22 /* Invalid argument */ #define ENFILE -23 /* File table overflow */ #define EMFILE -24 /* Too many open files */ #define ENOTTY -25 /* Not a typewriter */ #define ETXTBSY -26 /* Text file busy */ #define EFBIG -27 /* File too large */ #define ENOSPC -28 /* No space left on device */ #define ESPIPE -29 /* Illegal seek */ #define EROFS -30 /* Read-only file system */ #define EMLINK -31 /* Too many links */ #define EPIPE -32 /* Broken pipe */ #define EDOM -33 /* Math argument out of domain of func */ #define ERANGE -34 /* Math result not representable */ #define EDEADLK -35 /* Resource deadlock would occur */ #define ENAMETOOLONG -36 /* File name too long */ #define ENOLCK -37 /* No record locks available */ #define ENOSYS -38 /* Function not implemented */ #define ENOTEMPTY -39 /* Directory not empty */ #define ELOOP -40 /* Too many symbolic links encountered */ #define EWOULDBLOCK EAGAIN /* Operation would block */ #define ENOMSG -42 /* No message of desired type */ #define EIDRM -43 /* Identifier removed */ #define ECHRNG -44 /* Channel number out of range */ #define EL2NSYNC -45 /* Level 2 not synchronized */ #define EL3HLT -46 /* Level 3 halted */ #define EL3RST -47 /* Level 3 reset */ #define ELNRNG -48 /* Link number out of range */ #define EUNATCH -49 /* Protocol driver not attached */ #define ENOCSI -50 /* No CSI structure available */ #define EL2HLT -51 /* Level 2 halted */ #define EBADE -52 /* Invalid exchange */ #define EBADR -53 /* Invalid request descriptor */ #define EXFULL -54 /* Exchange full */ #define ENOANO -55 /* No anode */ #define EBADRQC -56 /* Invalid request code */ #define EBADSLT -57 /* Invalid slot */ #endif // ERRNO_H

nachos/code/userprog/ksyscall.h

/************************************************************** * * userprog/ksyscall.h * * Kernel interface for systemcalls * * by Marcus Voelp (c) Universitaet Karlsruhe * **************************************************************/ #ifndef __USERPROG_KSYSCALL_H__ #define __USERPROG_KSYSCALL_H__ #include "kernel.h" void SysHalt() { kernel->interrupt->Halt(); } int SysAdd(int op1, int op2) { return op1 + op2; } #endif /* ! __USERPROG_KSYSCALL_H__ */

nachos/code/userprog/syscall.h

/* syscalls.h * Nachos system call interface. These are Nachos kernel operations * that can be invoked from user programs, by trapping to the kernel * via the "syscall" instruction. * * This file is included by user programs and by the Nachos kernel. * * Copyright (c) 1992-1993 The Regents of the University of California. * All rights reserved. See copyright.h for copyright notice and limitation * of liability and disclaimer of warranty provisions. */ #ifndef SYSCALLS_H #define SYSCALLS_H #include "copyright.h" #include "errno.h" /* system call codes -- used by the stubs to tell the kernel which system call * is being asked for */ #define SC_Halt 0 #define SC_Exit 1 #define SC_Exec 2 #define SC_Join 3 #define SC_Create 4 #define SC_Remove 5 #define SC_Open 6 #define SC_Read 7 #define SC_Write 8 #define SC_Seek 9 #define SC_Close 10 #define SC_ThreadFork 11 #define SC_ThreadYield 12 #define SC_ExecV 13 #define SC_ThreadExit 14 #define SC_ThreadJoin 15 #define SC_Add 42 #ifndef IN_ASM /* The system call interface. These are the operations the Nachos * kernel needs to support, to be able to run user programs. * * Each of these is invoked by a user program by simply calling the * procedure; an assembly language stub stuffs the system call code * into a register, and traps to the kernel. The kernel procedures * are then invoked in the Nachos kernel, after appropriate error checking, * from the system call entry point in exception.cc. */ /* Stop Nachos, and print out performance stats */ void Halt(); /* * Add the two operants and return the result */ int Add(int op1, int op2); /* Address space control operations: Exit, Exec, Execv, and Join */ /* This user program is done (status = 0 means exited normally). */ void Exit(int status); /* A unique identifier for an executing user program (address space) */ typedef int SpaceId; /* A unique identifier for a thread within a task */ typedef int ThreadId; /* Run the specified executable, with no args */ /* This can be implemented as a call to ExecV. */ SpaceId Exec(char* exec_name); /* Run the executable, stored in the Nachos file "argv[0]", with * parameters stored in argv[1..argc-1] and return the * address space identifier */ SpaceId ExecV(int argc, char* argv[]); /* Only return once the user program "id" has finished. * Return the exit status. */ int Join(SpaceId id); /* File system operations: Create, Remove, Open, Read, Write, Close * These functions are patterned after UNIX -- files represent * both files *and* hardware I/O devices. * * Note that the Nachos file system has a stub implementation, which * can be used to support these system calls if the regular Nachos * file system has not been implemented. */ /* A unique identifier for an open Nachos file. */ typedef int OpenFileId; /* when an address space starts up, it has two open files, representing * keyboard input and display output (in UNIX terms, stdin and stdout). * Read and Write can be used directly on these, without first opening * the console device. */ #define ConsoleInput 0 #define ConsoleOutput 1 /* Create a Nachos file, with name "name" */ /* Note: Create does not open the file. */ /* Return 1 on success, negative error code on failure */ int Create(char *name); /* Remove a Nachos file, with name "name" */ int Remove(char *name); /* Open the Nachos file "name", and return an "OpenFileId" that can * be used to read and write to the file. */ OpenFileId Open(char *name); /* Write "size" bytes from "buffer" to the open file. * Return the number of bytes actually read on success. * On failure, a negative error code is returned. */ int Write(char *buffer, int size, OpenFileId id); /* Read "size" bytes from the open file into "buffer". * Return the number of bytes actually read -- if the open file isn't * long enough, or if it is an I/O device, and there aren't enough * characters to read, return whatever is available (for I/O devices, * you should always wait until you can return at least one character). */ int Read(char *buffer, int size, OpenFileId id); /* Set the seek position of the open file "id" * to the byte "position". */ int Seek(int position, OpenFileId id); /* Close the file, we're done reading and writing to it. * Return 1 on success, negative error code on failure */ int Close(OpenFileId id); /* User-level thread operations: Fork and Yield. To allow multiple * threads to run within a user program. * * Could define other operations, such as LockAcquire, LockRelease, etc. */ /* Fork a thread to run a procedure ("func") in the *same* address space * as the current thread. * Return a positive ThreadId on success, negative error code on failure */ ThreadId ThreadFork(void (*func)()); /* Yield the CPU to another runnable thread, whether in this address space * or not. */ void ThreadYield(); /* * Blocks current thread until lokal thread ThreadID exits with ThreadExit. * Function returns the ExitCode of ThreadExit() of the exiting thread. */ int ThreadJoin(ThreadId id); /* * Deletes current thread and returns ExitCode to every waiting lokal thread. */ void ThreadExit(int ExitCode); #endif /* IN_ASM */ #endif /* SYSCALL_H */

nachos/code/userprog/exception.cc

nachos/code/userprog/exception.cc

// exception.cc 
//  Entry point into the Nachos kernel from user programs.
//  There are two kinds of things that can cause control to
//  transfer back to here from user code:
//
//  syscall -- The user code explicitly requests to call a procedure
//  in the Nachos kernel.  Right now, the only function we support is
//  "Halt".
//
//  exceptions -- The user code does something that the CPU can't handle.
//  For instance, accessing memory that doesn't exist, arithmetic errors,
//  etc.  
//
//  Interrupts (which can also cause control to transfer from user
//  code into the Nachos kernel) are handled elsewhere.
//
// For now, this only handles the Halt() system call.
// Everything else core dumps.
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include   "copyright.h"
#include   "main.h"
#include   "syscall.h"
#include   "ksyscall.h"
//----------------------------------------------------------------------
// ExceptionHandler
//  Entry point into the Nachos kernel.  Called when a user program
//  is executing, and either does a syscall, or generates an addressing
//  or arithmetic exception.
//
//  For system calls, the following is the calling convention:
//
//  system call code -- r2
//      arg1 -- r4
//      arg2 -- r5
//      arg3 -- r6
//      arg4 -- r7
//
//  The result of the system call, if any, must be put back into r2. 
//
// If you are handling a system call, don't forget to increment the pc
// before returning. (Or else you'll loop making the same system call forever!)
//
//  "which" is the kind of exception.  The list of possible exceptions 
//  is in machine.h.
//----------------------------------------------------------------------

void
ExceptionHandler ( ExceptionType  which )
{
     int  type  =  kernel -> machine -> ReadRegister ( 2 );

    DEBUG ( dbgSys ,   "Received Exception "   <<  which  <<   " type: "   <<  type  <<   "\n" );

     switch   ( which )   {
     case   SyscallException :
       switch ( type )   {
       case   SC_Halt :
    DEBUG ( dbgSys ,   "Shutdown, initiated by user program.\n" );

     SysHalt ();

    ASSERTNOTREACHED ();
     break ;

       case   SC_Add :
    DEBUG ( dbgSys ,   "Add "   <<  kernel -> machine -> ReadRegister ( 4 )   <<   " + "   <<  kernel -> machine -> ReadRegister ( 5 )   <<   "\n" );
    
     /* Process SysAdd Systemcall*/
     int  result ;
    result  =   SysAdd ( /* int op1 */ ( int ) kernel -> machine -> ReadRegister ( 4 ),
             /* int op2 */ ( int ) kernel -> machine -> ReadRegister ( 5 ));

    DEBUG ( dbgSys ,   "Add returning with "   <<  result  <<   "\n" );
     /* Prepare Result */
    kernel -> machine -> WriteRegister ( 2 ,   ( int ) result );
    
     /* Modify return point */
     {
       /* set previous programm counter (debugging only)*/
      kernel -> machine -> WriteRegister ( PrevPCReg ,  kernel -> machine -> ReadRegister ( PCReg ));

       /* set programm counter to next instruction (all Instructions are 4 byte wide)*/
      kernel -> machine -> WriteRegister ( PCReg ,  kernel -> machine -> ReadRegister ( PCReg )   +   4 );
      
       /* set next programm counter for brach execution */
      kernel -> machine -> WriteRegister ( NextPCReg ,  kernel -> machine -> ReadRegister ( PCReg ) + 4 );
     }

     return ;
    
    ASSERTNOTREACHED ();

     break ;

       default :
    cerr  <<   "Unexpected system call "   <<  type  <<   "\n" ;
     break ;
       }
       break ;
     default :
      cerr  <<   "Unexpected user mode exception"   <<   ( int ) which  <<   "\n" ;
       break ;
     }
    ASSERTNOTREACHED ();
}

nachos/code/userprog/addrspace.cc

nachos/code/userprog/addrspace.cc

// addrspace.cc 
//  Routines to manage address spaces (executing user programs).
//
//  In order to run a user program, you must:
//
//  1. link with the -n -T 0 option 
//  2. run coff2noff to convert the object file to Nachos format
//      (Nachos object code format is essentially just a simpler
//      version of the UNIX executable object code format)
//  3. load the NOFF file into the Nachos file system
//      (if you are using the "stub" file system, you
//      don't need to do this last step)
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include   "copyright.h"
#include   "main.h"
#include   "addrspace.h"
#include   "machine.h"
#include   "noff.h"

//----------------------------------------------------------------------
// SwapHeader
//  Do little endian to big endian conversion on the bytes in the 
//  object file header, in case the file was generated on a little
//  endian machine, and we're now running on a big endian machine.
//----------------------------------------------------------------------

static   void  
SwapHeader   ( NoffHeader   * noffH )
{
    noffH -> noffMagic  =   WordToHost ( noffH -> noffMagic );
    noffH -> code . size  =   WordToHost ( noffH -> code . size );
    noffH -> code . virtualAddr  =   WordToHost ( noffH -> code . virtualAddr );
    noffH -> code . inFileAddr  =   WordToHost ( noffH -> code . inFileAddr );
#ifdef  RDATA
    noffH -> readonlyData . size  =   WordToHost ( noffH -> readonlyData . size );
    noffH -> readonlyData . virtualAddr  =  
            WordToHost ( noffH -> readonlyData . virtualAddr );
    noffH -> readonlyData . inFileAddr  =  
            WordToHost ( noffH -> readonlyData . inFileAddr );
#endif  
    noffH -> initData . size  =   WordToHost ( noffH -> initData . size );
    noffH -> initData . virtualAddr  =   WordToHost ( noffH -> initData . virtualAddr );
    noffH -> initData . inFileAddr  =   WordToHost ( noffH -> initData . inFileAddr );
    noffH -> uninitData . size  =   WordToHost ( noffH -> uninitData . size );
    noffH -> uninitData . virtualAddr  =   WordToHost ( noffH -> uninitData . virtualAddr );
    noffH -> uninitData . inFileAddr  =   WordToHost ( noffH -> uninitData . inFileAddr );

#ifdef  RDATA
    DEBUG ( dbgAddr ,   "code = "   <<  noffH -> code . size  <<   
                    " readonly = "   <<  noffH -> readonlyData . size  <<
                    " init = "   <<  noffH -> initData . size  <<
                    " uninit = "   <<  noffH -> uninitData . size  <<   "\n" );
#endif
}

//----------------------------------------------------------------------
// AddrSpace::AddrSpace
//  Create an address space to run a user program.
//  Set up the translation from program memory to physical 
//  memory.  For now, this is really simple (1:1), since we are
//  only uniprogramming, and we have a single unsegmented page table
//----------------------------------------------------------------------

AddrSpace :: AddrSpace ()
{
    pageTable  =   new   TranslationEntry [ NumPhysPages ];
     for   ( int  i  =   0 ;  i  <   NumPhysPages ;  i ++ )   {
    pageTable [ i ]. virtualPage  =  i ;     // for now, virt page # = phys page #
    pageTable [ i ]. physicalPage  =  i ;
    pageTable [ i ]. valid  =  TRUE ;
    pageTable [ i ]. use  =  FALSE ;
    pageTable [ i ]. dirty  =  FALSE ;
    pageTable [ i ]. readOnly  =  FALSE ;   
     }
    
     // zero out the entire address space
    bzero ( kernel -> machine -> mainMemory ,   MemorySize );
}

//----------------------------------------------------------------------
// AddrSpace::~AddrSpace
//  Dealloate an address space.
//----------------------------------------------------------------------

AddrSpace ::~ AddrSpace ()
{
    delete  pageTable ;
}


//----------------------------------------------------------------------
// AddrSpace::Load
//  Load a user program into memory from a file.
//
//  Assumes that the page table has been initialized, and that
//  the object code file is in NOFF format.
//
//  "fileName" is the file containing the object code to load into memory
//----------------------------------------------------------------------

bool  
AddrSpace :: Load ( char   * fileName )  
{
     OpenFile   * executable  =  kernel -> fileSystem -> Open ( fileName );
     NoffHeader  noffH ;
     unsigned   int  size ;

     if   ( executable  ==  NULL )   {
    cerr  <<   "Unable to open file "   <<  fileName  <<   "\n" ;
     return  FALSE ;
     }

    executable -> ReadAt (( char   * ) & noffH ,   sizeof ( noffH ),   0 );
     if   (( noffH . noffMagic  !=  NOFFMAGIC )   &&  
         ( WordToHost ( noffH . noffMagic )   ==  NOFFMAGIC ))
         SwapHeader ( & noffH );
    ASSERT ( noffH . noffMagic  ==  NOFFMAGIC );

#ifdef  RDATA
// how big is address space?
    size  =  noffH . code . size  +  noffH . readonlyData . size  +  noffH . initData . size  +
           noffH . uninitData . size  +   UserStackSize ;    
                                                 // we need to increase the size
                         // to leave room for the stack
#else
// how big is address space?
    size  =  noffH . code . size  +  noffH . initData . size  +  noffH . uninitData . size 
             +   UserStackSize ;      // we need to increase the size
                         // to leave room for the stack
#endif
    numPages  =  divRoundUp ( size ,   PageSize );
    size  =  numPages  *   PageSize ;

    ASSERT ( numPages  <=   NumPhysPages );         // check we're not trying
                         // to run anything too big --
                         // at least until we have
                         // virtual memory

    DEBUG ( dbgAddr ,   "Initializing address space: "   <<  numPages  <<   ", "   <<  size );

// then, copy in the code and data segments into memory
// Note: this code assumes that virtual address = physical address
     if   ( noffH . code . size  >   0 )   {
        DEBUG ( dbgAddr ,   "Initializing code segment." );
    DEBUG ( dbgAddr ,  noffH . code . virtualAddr  <<   ", "   <<  noffH . code . size );
        executable -> ReadAt (
         & ( kernel -> machine -> mainMemory [ noffH . code . virtualAddr ]),  
            noffH . code . size ,  noffH . code . inFileAddr );
     }
     if   ( noffH . initData . size  >   0 )   {
        DEBUG ( dbgAddr ,   "Initializing data segment." );
    DEBUG ( dbgAddr ,  noffH . initData . virtualAddr  <<   ", "   <<  noffH . initData . size );
        executable -> ReadAt (
         & ( kernel -> machine -> mainMemory [ noffH . initData . virtualAddr ]),
            noffH . initData . size ,  noffH . initData . inFileAddr );
     }

#ifdef  RDATA
     if   ( noffH . readonlyData . size  >   0 )   {
        DEBUG ( dbgAddr ,   "Initializing read only data segment." );
    DEBUG ( dbgAddr ,  noffH . readonlyData . virtualAddr  <<   ", "   <<  noffH . readonlyData . size );
        executable -> ReadAt (
         & ( kernel -> machine -> mainMemory [ noffH . readonlyData . virtualAddr ]),
            noffH . readonlyData . size ,  noffH . readonlyData . inFileAddr );
     }
#endif

     delete  executable ;            // close file
     return  TRUE ;              // success
}

//----------------------------------------------------------------------
// AddrSpace::Execute
//  Run a user program using the current thread
//
//      The program is assumed to have already been loaded into
//      the address space
//
//----------------------------------------------------------------------

void  
AddrSpace :: Execute ()  
{

    kernel -> currentThread -> space  =   this ;

     this -> InitRegisters ();        // set the initial register values
     this -> RestoreState ();         // load page table register

    kernel -> machine -> Run ();       // jump to the user progam

    ASSERTNOTREACHED ();           // machine->Run never returns;
                     // the address space exits
                     // by doing the syscall "exit"
}


//----------------------------------------------------------------------
// AddrSpace::InitRegisters
//  Set the initial values for the user-level register set.
//
//  We write these directly into the "machine" registers, so
//  that we can immediately jump to user code.  Note that these
//  will be saved/restored into the currentThread->userRegisters
//  when this thread is context switched out.
//----------------------------------------------------------------------

void
AddrSpace :: InitRegisters ()
{
     Machine   * machine  =  kernel -> machine ;
     int  i ;

     for   ( =   0 ;  i  <   NumTotalRegs ;  i ++ )
    machine -> WriteRegister ( i ,   0 );

     // Initial program counter -- must be location of "Start", which
     //  is assumed to be virtual address zero
    machine -> WriteRegister ( PCReg ,   0 );    

     // Need to also tell MIPS where next instruction is, because
     // of branch delay possibility
     // Since instructions occupy four bytes each, the next instruction
     // after start will be at virtual address four.
    machine -> WriteRegister ( NextPCReg ,   4 );

    // Set the stack register to the end of the address space, where we
    // allocated the stack; but subtract off a bit, to make sure we don't
    // accidentally reference off the end!
    machine -> WriteRegister ( StackReg ,  numPages  *   PageSize   -   16 );
    DEBUG ( dbgAddr ,   "Initializing stack pointer: "   <<  numPages  *   PageSize   -   16 );
}

//----------------------------------------------------------------------
// AddrSpace::SaveState
//  On a context switch, save any machine state, specific
//  to this address space, that needs saving.
//
//  For now, don't need to save anything!
//----------------------------------------------------------------------

void   AddrSpace :: SaveState ()  
{}

//----------------------------------------------------------------------
// AddrSpace::RestoreState
//  On a context switch, restore the machine state so that
//  this address space can run.
//
//      For now, tell the machine where to find the page table.
//----------------------------------------------------------------------

void   AddrSpace :: RestoreState ()  
{
    kernel -> machine -> pageTable  =  pageTable ;
    kernel -> machine -> pageTableSize  =  numPages ;
}


//----------------------------------------------------------------------
// AddrSpace::Translate
//  Translate the virtual address in _vaddr_ to a physical address
//  and store the physical address in _paddr_.
//  The flag _isReadWrite_ is false (0) for read-only access; true (1)
//  for read-write access.
//  Return any exceptions caused by the address translation.
//----------------------------------------------------------------------
ExceptionType
AddrSpace :: Translate ( unsigned   int  vaddr ,   unsigned   int   * paddr ,   int  isReadWrite )
{
     TranslationEntry   * pte ;
     int                pfn ;
     unsigned   int       vpn     =  vaddr  /   PageSize ;
     unsigned   int       offset  =  vaddr  %   PageSize ;

     if ( vpn  >=  numPages )   {
         return   AddressErrorException ;
     }

    pte  =   & pageTable [ vpn ];

     if ( isReadWrite  &&  pte -> readOnly )   {
         return   ReadOnlyException ;
     }

    pfn  =  pte -> physicalPage ;

     // if the pageFrame is too big, there is something really wrong!
     // An invalid translation was loaded into the page table or TLB.
     if   ( pfn  >=   NumPhysPages )   {
        DEBUG ( dbgAddr ,   "Illegal physical page "   <<  pfn );
         return   BusErrorException ;
     }

    pte -> use  =  TRUE ;            // set the use, dirty bits

     if ( isReadWrite )
        pte -> dirty  =  TRUE ;

     * paddr  =  pfn * PageSize   +  offset ;

    ASSERT (( * paddr  <   MemorySize ));

     //cerr << " -- AddrSpace::Translate(): vaddr: " << vaddr <<
     //  ", paddr: " << *paddr << "\n";

     return   NoException ;
}




nachos/code/userprog/addrspace.h

// addrspace.h // Data structures to keep track of executing user programs // (address spaces). // // For now, we don't keep any information about address spaces. // The user level CPU state is saved and restored in the thread // executing the user program (see thread.h). // // Copyright (c) 1992-1996 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef ADDRSPACE_H #define ADDRSPACE_H #include "copyright.h" #include "filesys.h" #define UserStackSize 1024 // increase this as necessary! class AddrSpace { public: AddrSpace(); // Create an address space. ~AddrSpace(); // De-allocate an address space bool Load(char *fileName); // Load a program into addr space from // a file // return false if not found void Execute(); // Run a program // assumes the program has already // been loaded void SaveState(); // Save/restore address space-specific void RestoreState(); // info on a context switch // Translate virtual address _vaddr_ // to physical address _paddr_. _mode_ // is 0 for Read, 1 for Write. ExceptionType Translate(unsigned int vaddr, unsigned int *paddr, int mode); private: TranslationEntry *pageTable; // Assume linear page table translation // for now! unsigned int numPages; // Number of pages in the virtual // address space void InitRegisters(); // Initialize user-level CPU registers, // before jumping to user code }; #endif // ADDRSPACE_H

nachos/code/userprog/synchconsole.h

// synchconsole.h // Data structures for synchronized access to the keyboard // and console display devices. // // NOTE: this abstraction is not completely implemented. // // Copyright (c) 1992-1996 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef SYNCHCONSOLE_H #define SYNCHCONSOLE_H #include "copyright.h" #include "utility.h" #include "callback.h" #include "console.h" #include "synch.h" // The following two classes define synchronized input and output to // a console device class SynchConsoleInput : public CallBackObj { public: SynchConsoleInput(char *inputFile); // Initialize the console device ~SynchConsoleInput(); // Deallocate console device char GetChar(); // Read a character, waiting if necessary private: ConsoleInput *consoleInput; // the hardware keyboard Lock *lock; // only one reader at a time Semaphore *waitFor; // wait for callBack void CallBack(); // called when a keystroke is available }; class SynchConsoleOutput : public CallBackObj { public: SynchConsoleOutput(char *outputFile); // Initialize the console device ~SynchConsoleOutput(); void PutChar(char ch); // Write a character, waiting if necessary private: ConsoleOutput *consoleOutput;// the hardware display Lock *lock; // only one writer at a time Semaphore *waitFor; // wait for callBack void CallBack(); // called when more data can be written }; #endif // SYNCHCONSOLE_H

nachos/code/userprog/synchconsole.cc

nachos/code/userprog/synchconsole.cc

// synchconsole.cc 
//  Routines providing synchronized access to the keyboard 
//  and console display hardware devices.
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include   "copyright.h"
#include   "synchconsole.h"

//----------------------------------------------------------------------
// SynchConsoleInput::SynchConsoleInput
//      Initialize synchronized access to the keyboard
//
//      "inputFile" -- if NULL, use stdin as console device
//              otherwise, read from this file
//----------------------------------------------------------------------

SynchConsoleInput :: SynchConsoleInput ( char   * inputFile )
{
    consoleInput  =   new   ConsoleInput ( inputFile ,   this );
    lock  =   new   Lock ( "console in" );
    waitFor  =   new   Semaphore ( "console in" ,   0 );
}

//----------------------------------------------------------------------
// SynchConsoleInput::~SynchConsoleInput
//      Deallocate data structures for synchronized access to the keyboard
//----------------------------------------------------------------------

SynchConsoleInput ::~ SynchConsoleInput ()
{  
     delete  consoleInput ;  
     delete  lock ;  
     delete  waitFor ;
}

//----------------------------------------------------------------------
// SynchConsoleInput::GetChar
//      Read a character typed at the keyboard, waiting if necessary.
//----------------------------------------------------------------------

char
SynchConsoleInput :: GetChar ()
{
     char  ch ;

    lock -> Acquire ();
    waitFor -> P ();     // wait for EOF or a char to be available.
    ch  =  consoleInput -> GetChar ();
    lock -> Release ();
     return  ch ;
}

//----------------------------------------------------------------------
// SynchConsoleInput::CallBack
//      Interrupt handler called when keystroke is hit; wake up
//  anyone waiting.
//----------------------------------------------------------------------

void
SynchConsoleInput :: CallBack ()
{
    waitFor -> V ();
}

//----------------------------------------------------------------------
// SynchConsoleOutput::SynchConsoleOutput
//      Initialize synchronized access to the console display
//
//      "outputFile" -- if NULL, use stdout as console device
//              otherwise, read from this file
//----------------------------------------------------------------------

SynchConsoleOutput :: SynchConsoleOutput ( char   * outputFile )
{
    consoleOutput  =   new   ConsoleOutput ( outputFile ,   this );
    lock  =   new   Lock ( "console out" );
    waitFor  =   new   Semaphore ( "console out" ,   0 );
}

//----------------------------------------------------------------------
// SynchConsoleOutput::~SynchConsoleOutput
//      Deallocate data structures for synchronized access to the keyboard
//----------------------------------------------------------------------

SynchConsoleOutput ::~ SynchConsoleOutput ()
{  
     delete  consoleOutput ;  
     delete  lock ;  
     delete  waitFor ;
}

//----------------------------------------------------------------------
// SynchConsoleOutput::PutChar
//      Write a character to the console display, waiting if necessary.
//----------------------------------------------------------------------

void
SynchConsoleOutput :: PutChar ( char  ch )
{
    lock -> Acquire ();
    consoleOutput -> PutChar ( ch );
    waitFor -> P ();
    lock -> Release ();
}

//----------------------------------------------------------------------
// SynchConsoleOutput::CallBack
//      Interrupt handler called when it's safe to send the next 
//  character can be sent to the display.
//----------------------------------------------------------------------

void
SynchConsoleOutput :: CallBack ()
{
    waitFor -> V ();
}

nachos/COPYRIGHT

Copyright (c) 1992-1993 The Regents of the University of California. All rights reserved. Permission to use, copy, modify, and distribute this software and its documentation for any purpose, without fee, and without written agreement is hereby granted, provided that the above copyright notice and the following two paragraphs appear in all copies of this software. IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

project4/project4-1.pdf

Nachos Project 4, Part 1 (40 points of 100 points):

Multiprogramming and Round-robin Scheduling

Due date: 11:59PM, Friday, November 23, 2018.

(5 point bonus, if submitted on November 23, 2018). The usual grace period applies.

Note: Part 1 is relatively easy. You may not need the entire two weeks for this part.

However, Part 2 will be quite challenging; therefore, I recommend you to finish Part 1 soon

and start Part 2 as soon as the description becomes available.

1 An Important Reminder

It is a good time to review the academic integrity policy of the university (http://class.syr.

edu/academic-integrity) and the course honor pledge you submitted at the beginning of the

semester. For this programming project (Part 1 and Part 2), we will use moss (https://theory.

stanford.edu/~aiken/moss/), A System for Detecting Software Similarity, extensively to detect

plagiarism among your program submissions. Please remember that violating academic integrity

policy will greatly jeopardize your grade as you agreed on the honor pledge.

2 Overview

The original distribution of Nachos implements uni-programming, allowing one program execution

at a time. When a user-level program is executed, the main thread is used to run the user program.

For example, you can use the following command to run the user program prog1:

./nachos -x ../test/prog1

To support multiprogramming, we will provide a simple contiguous memory management scheme.

Use the diff command to see the differences between the new addrspace.[cc|h] and the original

files. The memory management is done for you but you will still need to modify Nachos so it uses

separate threads to run user programs. (See Section 3 below.) In addition, You need to implement

1

a new flag “-quantum” that is used to set the size of time slice for round-robin scheduling. With

everything implemented, the command:

./nachos -quantum <quantum size> -x ../test/prog1 -x ../test/prog2

should run prog1 and prog2 with round-robin scheduling.

Two testing user programs, prog1.c, prog2.c, are provided. They call Write() to print mes-

sages to screen and Exit() at the end to quit. The implementations of these system calls are

provided. Note: the implementations given are not full Nachos implementation using Nachos con-

sole device.

3 Requirements

1. By default, Nachos can only load one user program in main memory. The loading process is

defined in RunUserProg() function in main.cc, which creates an address space, then loads

and executes the user program. However, the AddressSpace::Execute() function never

returns. Since main thread is used for the user program, no other programs can run. In

order to load and run multiple user programs, you need to create a new thread for each user

program.

2. The simulated hardware Timer object of Nachos is created in the Alarm class found in alarm.h

and alarm.cc. By default, a timer interrupt occurs at every 100 timer ticks. When the

timer interrupt happens, the timer interrupt handler, which is Alarm::CallBack(), is in-

voked. This handler makes the currently running thread gives up the CPU by setting the

interrupt->YieldOnReturn flag. Therefore, the default quantum of Nachos is 100 ticks. To

change this behavior, you need to make sure the interrupt->YieldOnReturn flag is only set

after the given “quantum” number of ticks.

3. Note that since the hardware timer gives a timer interrupt every 100 ticks, the granularity

of quantum is 100 ticks, i.e., the actual quantum is rounded to the next multiple of 100 no

matter what value is given to the “-quantum” flag.

4. When implementing the argument parsing for “-quantum” flag, you may get hint from the

parsing of “-rs” flag found in kernel.cc.

4 Tests and Output

Your program will be tested with the following command:

./nachos -quantum <quantum size> -x ../test/prog1 -x ../test/prog2

2

The correct output contains messages from 2 user programs, 5 from each. The order of the

messages changes with the value of <quantum size>.

5 What to Submit

The project is due by the end of November 23, 2018. Please compress your whole os folder and a

screenshot of your output, name the compressed file LastName,FirstName.zip (NOTE: .zip ONLY!)

and submit it on Blackboard.

3

  • An Important Reminder
  • Overview
  • Requirements
  • Tests and Output
  • What to Submit

__MACOSX/project4/._project4-1.pdf

project4/lab1(1).pdf

Lab 1 --- Nachos

1. Copy Nachos source code to your account:

• We will use a Ubuntu virtual machine (VM) at lcs-vc-cis486.syr.edu for programming assignments and projects. You should have received an email containing the credentials needed to login to your VM account.

• We will use ssh (Secure SHell) to connect to your VM account. Open a Terminal and type:

ssh <netid>@lcs-vc-cis486.syr.edu # <netid> is your NetID

• Then type your password to connect.

• Copy nachos source code to your account with command:

cp /home/cis486/nachos.tar . # there is a dot at the end

• Untar the file with command:

tar xvf nachos.tar

• Now if you do a ls, you should see the nachos directory.

2. Compile and run Nachos

• Go to the build directory:

cd nachos/code/build.linux

• Build nachos:

make

• There will be some warnings, but that is OK. If you see the executable file nachos with ls, the compilation is successful.

• Run nachos with command:

./nachos -K

• You should see the output loop starting with “*** thread 1 looped 0 times”. Find out where this loop is defined.

• Find out how does the function containing the loop get called. Note: all the files you need to look at are in nachos/code/threads/ directory.

• Modify the source file where the loop is defined, in order to print a “Hello World!” statement after each line of “*** thread 1 looped 0 times”.

• Show your result to the TA.

3. Download/upload files from/to local machine

• You can use sftp (SSH File Transfer Protocol) to manage (download/upload) the files on your VM account. You can either use the Terminal of the Macintosh machine for sftp or use your own GUI-based sftp software, e.g. FileZilla. In fact, you’re encouraged to use a GUI software because those are much easier to use. However, if you prefer the command line, check out some tutorials such as this one: http://www.tecmint.com/ sftp-command-examples/

• To connect to the VM with sftp on command line, use the command:

sftp <netid>@lcs-vc-cis486.syr.edu # <netid> is your NetID

__MACOSX/project4/._lab1(1).pdf

project4/nachos/coff2noff/Makefile.dep

############################################################################# # Machine-specific definitions # # In the MFCF environment, this attempts to determine automatically # the machine type and OS type. If it cannot, it gives up and # prints a message. # # If you are not in the MFCF environment, you can either add a new # automatic test for your machine/OS type, or you can set the # necessary variables "manually" here ############################################################################# # unfortunately, command line arguments to uname are not # very consistent across UNIX flavours. However, the following # seem to work almost everywhere in MFCF land osname = $(shell uname -s) osrelease = $(shell uname -r) hosttype = unknown # Test for Solaris (5.6) # At Waterloo: agnesi,bacon,fenchel,fitch,lassar,magnus,merrill # If Solaris, we assume we are on a SPARC, which is not necessarily # a good assumption outside of MFCF ifeq ($(osname),SunOS) ifeq ($(osrelease),5.6) HOSTCFLAGS = -DHOST_IS_BIG_ENDIAN hosttype = sparcSolaris endif endif # Test for Solaris (5.5) # At Waterloo: hermite.math,markov.math,picard.math,wronski.math,... # If Solaris, we assume we are on a SPARC, which is not necessarily # a good assumption outside of MFCF ifeq ($(osname),SunOS) ifeq ($(osrelease),5.5) HOSTCFLAGS = -DHOST_IS_BIG_ENDIAN hosttype = sparcSolaris endif endif # Test for Solaris (5.4) # At Waterloo: hume.math, hypatia.math,... # This is the same setup as Solaris 5.5 # If Solaris, we assume we are on a SPARC, which is not necessarily # a good assumption outside of MFCF ifeq ($(osname),SunOS) ifeq ($(osrelease),5.4) HOSTCFLAGS = -DHOST_IS_BIG_ENDIAN hosttype = sparcSolaris endif endif # Test for SunOS 4.xx # At Waterloo: descartes,cayley,napier,.... # If SunOS, we assume we are on a SPARC, which is not necessarily # a good assumption outside of MFCF ifeq ($(osname),SunOS) ifeq ($(osrelease),4.1.3_U1) HOSTCFLAGS = -DHOST_IS_BIG_ENDIAN hosttype = sparcSunOS endif endif # Test for ULTRIX # At Waterloo: cantor.math,noether.math # Assume ULTRIX on a MIPS architecture ifeq ($(osname),ULTRIX) HOSTCFLAGS = hosttype = mipsUltrix endif # Note: # If you are trying to build on Linux on an x86 # try something like this, substituting whatever # uname -s returns on your machine for the XXX # ifeq ($(osname),Linux) HOSTCFLAGS = hosttype = x86Linux endif ifeq ($(osname),CYGWIN_NT-5.1) HOSTCFLAGS = hosttype = x86Linux endif

project4/nachos/coff2noff/Makefile

# Makefile for: # coff2noff -- converts a normal MIPS executable into a Nachos executable # # This is a GNU Makefile. It must be used with the GNU make program. # At UW, the GNU make program is /software/gnu/bin/make. # In many other places it is known as "gmake". # You may wish to include /software/gnu/bin/ early in your command # search path, so that you will be using GNU make when you type "make". # # Use "make" to build the executable(s) # Use "make clean" to remove .o files # Use "make distclean" to remove all files produced by make, including # the executable # # # Copyright (c) 1992-1996 The Regents of the University of California. # All rights reserved. See copyright.h for copyright notice and limitation # of liability and disclaimer of warranty provisions. # # This file has been modified for use at Waterloo # ############################################################################# # Makefile.dep contains all machine-dependent definitions # If you are trying to build coff2noff somewhere outside # of the MFCF environment, you will almost certainly want # to visit and edit Makefile.dep before doing so ############################################################################# include Makefile.dep CC=gcc CFLAGS= $(HOSTCFLAGS) -DRDATA -m32 LD=gcc -m32 RM = /bin/rm MV = /bin/mv ifeq ($(hosttype),unknown) buildtargets = unknownhost else buildtargets = coff2noff.$(hosttype) endif all: $(buildtargets) # converts a COFF file to Nachos object format coff2noff.$(hosttype): coff2noff.o $(LD) coff2noff.o -o coff2noff.$(hosttype) strip coff2noff.$(hosttype) clean: $(RM) -f coff2noff.o distclean: clean $(MV) coff2noff.c temp.c $(RM) -f coff2noff.* $(MV) temp.c coff2noff.c unknownhost: @echo Host type could not be determined. @echo make is terminating @echo If you are on an MFCF machine, contact the instructor @echo to report this problem @echo Otherwise, edit Makefile.dep and try again.

project4/nachos/coff2noff/coff2noff.c

/* coff2noff.c * * This program reads in a COFF format file, and outputs a NOFF format file. * The NOFF format is essentially just a simpler version of the COFF file, * recording where each segment is in the NOFF file, and where it is to * go in the virtual address space. * * Assumes coff file is linked with either * gld with -N -Ttext 0 * ld with -N -T 0 * to make sure the object file has no shared text. * * Also assumes that the COFF file has at most 3 segments: * .text -- read-only executable instructions * .data -- initialized data * .bss/.sbss -- uninitialized data (should be zero'd on program startup) #ifdef RDATA * .rdata -- read-only data (e.g., string literals). * mark this segment readonly to prevent it from being modified #endif * * * Copyright (c) 1992-1993 The Regents of the University of California. * All rights reserved. See copyright.h for copyright notice and limitation * of liability and disclaimer of warranty provisions. */ /* * Modified at UW by KMS, August, 1997 * The modified program always writes the NOFF header in little-endian * format, rather than host format. This is to avoid the problem * that user programs run through coff2noff on a big-endian host * would not run properly on Nachos machines running on little-endian * hosts. * * Note that the Nachos address space loading code * (in AddrSpace::Load) on big-endian hosts converts the header * to big-endian format when it is read in. * Thus, the little-endian header NOFF * header should work OK whether Nachos is running on a little-endian * host or a big-endian host. */ #define MAIN #include "copyright.h" #undef MAIN #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <limits.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include "coff.h" #include "noff.h" /****************************************************************/ /* Routines for converting words and short words to and from the * simulated machine's format of little endian. These end up * being NOPs when the host machine is little endian. */ unsigned int WordToHost(unsigned int word) { #ifdef HOST_IS_BIG_ENDIAN register unsigned long result; result = (word >> 24) & 0x000000ff; result |= (word >> 8) & 0x0000ff00; result |= (word << 8) & 0x00ff0000; result |= (word << 24) & 0xff000000; return result; #else return word; #endif /* HOST_IS_BIG_ENDIAN */ } unsigned short ShortToHost(unsigned short shortword) { #if HOST_IS_BIG_ENDIAN register unsigned short result; result = (shortword << 8) & 0xff00; result |= (shortword >> 8) & 0x00ff; return result; #else return shortword; #endif /* HOST_IS_BIG_ENDIAN */ } unsigned int WordToMachine(unsigned int word) { return WordToHost(word); } unsigned short ShortToMachine(unsigned short shortword) { return ShortToHost(shortword); } // this routine was borrowed from userprog/addrspace.cc // on a big-endian machine, it converts all fields of // the NOFF header to little-endian format // on a little-endian machine, where the header is already // in little-endian format, it does nothing static void SwapHeader (NoffHeader *noffH) { noffH->noffMagic = WordToHost(noffH->noffMagic); noffH->code.size = WordToHost(noffH->code.size); noffH->code.virtualAddr = WordToHost(noffH->code.virtualAddr); noffH->code.inFileAddr = WordToHost(noffH->code.inFileAddr); #ifdef RDATA noffH->readonlyData.size = WordToHost(noffH->readonlyData.size); noffH->readonlyData.virtualAddr = WordToHost(noffH->readonlyData.virtualAddr); noffH->readonlyData.inFileAddr = WordToHost(noffH->readonlyData.inFileAddr); #endif noffH->initData.size = WordToHost(noffH->initData.size); noffH->initData.virtualAddr = WordToHost(noffH->initData.virtualAddr); noffH->initData.inFileAddr = WordToHost(noffH->initData.inFileAddr); noffH->uninitData.size = WordToHost(noffH->uninitData.size); noffH->uninitData.virtualAddr = WordToHost(noffH->uninitData.virtualAddr); noffH->uninitData.inFileAddr = WordToHost(noffH->uninitData.inFileAddr); } /****************************************************************/ #define ReadStruct(f,s) Read(f,(char *)&s,sizeof(s)) char *noffFileName = NULL; /* read and check for error */ void Read(int fd, char *buf, int nBytes) { if (read(fd, buf, nBytes) != nBytes) { fprintf(stderr, "File is too short\n"); unlink(noffFileName); exit(1); } } /* write and check for error */ void Write(int fd, char *buf, int nBytes) { if (write(fd, buf, nBytes) != nBytes) { fprintf(stderr, "Unable to write file\n"); unlink(noffFileName); exit(1); } } int main(int argc, char **argv) { int fdIn, fdOut, numsections, i, inNoffFile; struct filehdr fileh; struct aouthdr systemh; struct scnhdr *sections; char *buffer; NoffHeader noffH; if (argc < 2) { fprintf(stderr, "Usage: %s <coffFileName> <noffFileName>\n", argv[0]); exit(1); } /* open the COFF file (input) */ fdIn = open(argv[1], O_RDONLY, 0); if (fdIn == -1) { perror(argv[1]); exit(1); } /* open the NOFF file (output) */ fdOut = open(argv[2], O_WRONLY|O_CREAT|O_TRUNC , 0666); if (fdIn == -1) { perror(argv[2]); exit(1); } noffFileName = argv[2]; /* Read in the file header and check the magic number. */ ReadStruct(fdIn,fileh); fileh.f_magic = ShortToHost(fileh.f_magic); fileh.f_nscns = ShortToHost(fileh.f_nscns); if (fileh.f_magic != MIPSELMAGIC) { fprintf(stderr, "File is not a MIPSEL COFF file\n"); unlink(noffFileName); exit(1); } /* Read in the system header and check the magic number */ ReadStruct(fdIn,systemh); systemh.magic = ShortToHost(systemh.magic); if (systemh.magic != OMAGIC) { fprintf(stderr, "File is not a OMAGIC file\n"); unlink(noffFileName); exit(1); } /* Read in the section headers. */ numsections = fileh.f_nscns; printf("numsections %d \n",numsections); sections = (struct scnhdr *)malloc(numsections * sizeof(struct scnhdr)); Read(fdIn, (char *) sections, numsections * sizeof(struct scnhdr)); for (i = 0; i < numsections; i++) { sections[i].s_paddr = WordToHost(sections[i].s_paddr); sections[i].s_size = WordToHost(sections[i].s_size); sections[i].s_scnptr = WordToHost(sections[i].s_scnptr); } /* initialize the NOFF header, in case not all the segments are defined * in the COFF file */ noffH.noffMagic = NOFFMAGIC; noffH.code.size = 0; noffH.initData.size = 0; noffH.uninitData.size = 0; #ifdef RDATA noffH.readonlyData.size = 0; #endif /* Copy the segments in */ inNoffFile = sizeof(NoffHeader); lseek(fdOut, inNoffFile, 0); printf("Loading %d sections:\n", numsections); for (i = 0; i < numsections; i++) { printf("\t\"%s\", filepos 0x%x, mempos 0x%x, size 0x%x\n", sections[i].s_name, (unsigned int)sections[i].s_scnptr, (unsigned int)sections[i].s_paddr, (unsigned int)sections[i].s_size); if (sections[i].s_size == 0) { /* do nothing! */ } else if (!strcmp(sections[i].s_name, ".text")) { noffH.code.virtualAddr = sections[i].s_paddr; noffH.code.inFileAddr = inNoffFile; noffH.code.size = sections[i].s_size; lseek(fdIn, sections[i].s_scnptr, 0); buffer = malloc(sections[i].s_size); Read(fdIn, buffer, sections[i].s_size); Write(fdOut, buffer, sections[i].s_size); free(buffer); inNoffFile += sections[i].s_size; } else if (!strcmp(sections[i].s_name, ".data")){ noffH.initData.virtualAddr = sections[i].s_paddr; noffH.initData.inFileAddr = inNoffFile; noffH.initData.size = sections[i].s_size; lseek(fdIn, sections[i].s_scnptr, 0); buffer = malloc(sections[i].s_size); Read(fdIn, buffer, sections[i].s_size); Write(fdOut, buffer, sections[i].s_size); free(buffer); inNoffFile += sections[i].s_size; #ifdef RDATA } else if (!strcmp(sections[i].s_name, ".rdata")){ noffH.readonlyData.virtualAddr = sections[i].s_paddr; noffH.readonlyData.inFileAddr = inNoffFile; noffH.readonlyData.size = sections[i].s_size; lseek(fdIn, sections[i].s_scnptr, 0); buffer = malloc(sections[i].s_size); Read(fdIn, buffer, sections[i].s_size); Write(fdOut, buffer, sections[i].s_size); free(buffer); inNoffFile += sections[i].s_size; #endif } else if (!strcmp(sections[i].s_name, ".bss")){ /* need to check if we have both .bss and .sbss -- make sure they * are contiguous */ if (noffH.uninitData.size != 0) { if (sections[i].s_paddr == (noffH.uninitData.virtualAddr + noffH.uninitData.size)) { fprintf(stderr, "Can't handle both bss and sbss\n"); unlink(noffFileName); exit(1); } noffH.uninitData.size += sections[i].s_size; } else { noffH.uninitData.virtualAddr = sections[i].s_paddr; noffH.uninitData.size = sections[i].s_size; } /* we don't need to copy the uninitialized data! */ } else { fprintf(stderr, "Unknown segment type: %s\n", sections[i].s_name); unlink(noffFileName); exit(1); } } lseek(fdOut, 0, 0); // convert the NOFF header to little-endian before // writing it to the file SwapHeader(&noffH); Write(fdOut, (char *)&noffH, sizeof(NoffHeader)); close(fdIn); close(fdOut); exit(0); }

project4/nachos/coff2noff/copyright.h

/* Copyright (c) 1992-1996 The Regents of the University of California. All rights reserved. Permission to use, copy, modify, and distribute this software and its documentation for any purpose, without fee, and without written agreement is hereby granted, provided that the above copyright notice and the following two paragraphs appear in all copies of this software. IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */ #ifdef MAIN /* include the copyright message in every executable */ static char *copyright = "Copyright (c) 1992-1993 The Regents of the University of California. All rights reserved."; #endif // MAIN

project4/nachos/coff2noff/coff.h

/* coff.h * Data structures that describe the MIPS COFF format. */ struct filehdr { unsigned short f_magic; /* magic number */ unsigned short f_nscns; /* number of sections */ long f_timdat; /* time & date stamp */ long f_symptr; /* file pointer to symbolic header */ long f_nsyms; /* sizeof(symbolic hdr) */ unsigned short f_opthdr; /* sizeof(optional hdr) */ unsigned short f_flags; /* flags */ }; #define MIPSELMAGIC 0x0162 #define OMAGIC 0407 #define SOMAGIC 0x0701 typedef struct aouthdr { short magic; /* see above */ short vstamp; /* version stamp */ long tsize; /* text size in bytes, padded to DW bdry*/ long dsize; /* initialized data " " */ long bsize; /* uninitialized data " " */ long entry; /* entry pt. */ long text_start; /* base of text used for this file */ long data_start; /* base of data used for this file */ long bss_start; /* base of bss used for this file */ long gprmask; /* general purpose register mask */ long cprmask[4]; /* co-processor register masks */ long gp_value; /* the gp value used for this object */ } AOUTHDR; #define AOUTHSZ sizeof(AOUTHDR) struct scnhdr { char s_name[8]; /* section name */ long s_paddr; /* physical address, aliased s_nlib */ long s_vaddr; /* virtual address */ long s_size; /* section size */ long s_scnptr; /* file ptr to raw data for section */ long s_relptr; /* file ptr to relocation */ long s_lnnoptr; /* file ptr to gp histogram */ unsigned short s_nreloc; /* number of relocation entries */ unsigned short s_nlnno; /* number of gp histogram entries */ long s_flags; /* flags */ };

project4/nachos/coff2noff/noff.h

/* noff.h * Data structures defining the Nachos Object Code Format * * Basically, we only know about three types of segments: * code (read-only), initialized data, and unitialized data */ #define NOFFMAGIC 0xbadfad /* magic number denoting Nachos * object code file */ typedef struct segment { int virtualAddr; /* location of segment in virt addr space */ int inFileAddr; /* location of segment in this file */ int size; /* size of segment */ } Segment; typedef struct noffHeader { int noffMagic; /* should be NOFFMAGIC */ Segment code; /* executable code segment */ Segment initData; /* initialized data segment */ #ifdef RDATA Segment readonlyData; /* read only data */ #endif Segment uninitData; /* uninitialized data segment -- * should be zero'ed before use */ } NoffHeader;

project4/nachos/coff2noff/coff2noff.x86Linux

project4/nachos/coff2noff/coff2noff.o

project4/nachos/.DS_Store

__MACOSX/project4/nachos/._.DS_Store

project4/nachos/code/.DS_Store

__MACOSX/project4/nachos/code/._.DS_Store

project4/nachos/code/test/Makefile.dep

############################################################################# # Machine-specific definitions # # If you are not in the MFCF environment, you can either add a new # automatic test for your machine/OS type, or you should set the # necessary variables "manually" here ############################################################################# # unfortunately, command line arguments to uname are not # very consistent across UNIX flavours. However, the following # seem to work almost everywhere in MFCF land osname = $(shell uname -s) osrelease = $(shell uname -r) hosttype = unknown # Test for x86 Linux # !!! COMMENT THE FOLLOWING LINES OUT IF BUILDING FOR SOLARIS HOST !!! # !!! ADD PATH TO CPP and CROSS COMPILER ifeq ($(osname),Linux) # full path name of your cpp program i.e.: CPP = /usr/local/nachos/lib/gcc-lib/decstation-ultrix/2.95.2/cpp # directory in which your gcc cross-compiler lives i.e.: GCCDIR = /usr/local/nachos/bin/decstation-ultrix- LDFLAGS = -T script -N ASFLAGS = -mips2 CPPFLAGS = $(INCDIR) COFF2NOFF = ../../coff2noff/coff2noff.x86Linux hosttype = x86Linux endif ifeq ($(osname),Windows) CPP = /usr/local/nachosxdev/lib/gcc-lib/decstation-ultrix/2.95.3/cpp0 # directory in which your gcc cross-compiler lives i.e.: GCCDIR = /usr/local/nachosxdev/bin/decstation-ultrix- LDFLAGS = -T script -N ASFLAGS = -mips2 CPPFLAGS = $(INCDIR) COFF2NOFF = ../../coff2noff/coff2noff.Windows hosttype = Windows endif # Note: # If you are trying to build on MacOS X # try something like this, substituting whatever # uname -s returns on your machine for the XXX # #ifeq ($(osname),XXX) #CPP = full path name of your cpp program #GCCDIR = directory in which your gcc cross-compiler lives #LDFLAGS = -T script -N #ASFLAGS = -mips2 #CPPFLAGS = $(INCDIR) #COFF2NOFF = full pathname of your coff2noff program # Note: it has been moved to part of the Nachos distribution # COFF2NOFF = ../../coff2noff.mipsUltrix #hosttype = MacOS #endif

project4/nachos/code/test/matmult.o

project4/nachos/code/test/segments.c

/* segments.c * Simple program to illustrate different segments and to show * how parameters are passed and the syscall is generated. * * objdump below refers to: * /software/gcc_nachos/bin/decstation-ultrix-objdump * * Compile this "gmake segments" * Then use objdump to examine output. * objdump -d segments.coff - to disassemble * objdump -s segments.coff - to see contents of segments * objdump -x segments.coff - to see symbol table information * nachos -d m -s -x segments */ #define N (5) /* N is replaced by the preprocessor */ unsigned int initdata1 = 0xdeadbeef; /* initialized data put in .data segment */ int initdata2 = 0xbb; /* same as above */ const int blah = 0xff; /* into .rdata segment */ int uninitdata[N]; /* allocate space in .bss segment */ main() { /* automatic variable stored on stack or in register */ int i; int stack1 = 0xaa; int stack2; const int stack3 = 0xee; /* in reg or on stack not .rdata */ char *str = "Hello World .rdata segment\n"; /* str is stored on the stack or in a register * but text that is initialized is stored in .rdata */ for (i=0; i<N; i++) { uninitdata[i] = i; } Halt(); }

project4/nachos/code/test/shell.o

project4/nachos/code/test/halt.o

project4/nachos/code/test/add.coff

project4/nachos/code/test/sort

project4/nachos/code/test/shell.coff

project4/nachos/code/test/prog2.o

project4/nachos/code/test/prog2.coff

project4/nachos/code/test/Makefile

# # Makefile for building user programs to run on top of Nachos # # Use "make" to build the test executable(s) # Use "make clean" to remove .o files and .coff files # Use "make distclean" to remove all files produced by make, including # the test executables # # This is a GNU Makefile. It must be used with the GNU make program. # At UW, the GNU make program is /software/gnu/bin/make. # In many other places it is known as "gmake". # You may wish to include /software/gnu/bin/ early in your command # search path, so that you will be using GNU make when you type "make". # # Several things to be aware of: # # It should not be necessary to build the test executables for # every type of host machine on which Nachos runs. You should # be able to build them once, and then use them regardless of # the host machine type. That is because the test executables # run on the simulated MIPS machine, and not on the host. # # However: # (1) if you are experiencing problems with the test executables, # it would be prudent to rebuild them on the host machine # on which you are currently running Nachos. To do this, # just type "make distclean", and then "make" # # (2) the procedure used to build the test executables does # depend on the host machine you are on. All of the machine # dependencies are isolated in the Makefile.dep file. # It should be possible to build the test executables on # any MFCF machine. In the MFCF environment, this makefile # should automatically figure out what type of host you are # on, and should use the appropriate procedure. # However, if you are working outside the MFCF environment, # you will need to build a cross-compiler, build coff2noff, # and edit Makefile.dep in this directory before you # can build the test programs. # # Nachos assumes that the location of the program startup routine (the # location the kernel jumps to when the program initially starts up) # is at location 0. This means: start.o must be the first .o passed # to ld, in order for the routine "Start" to be loaded at location 0 # # When you make the test programs, you will see messages like these: # numsections 3 # Loading 3 sections: # ".text", filepos 0xd0, mempos 0x0, size 0x440 # ".data", filepos 0x510, mempos 0x440, size 0x0 # ".bss", filepos 0x0, mempos 0x440, size 0x12c0 # These messages are normal. They come from the coff2noff program. # They are useful in that they tell you how big the various parts of your # compiled user program are, and where in the address space # coff2noff is going to place them. This information is also # recorded in the header of the executable file that coff2noff # creates. See the method AddrSpace::Load (in userprog/addrspace.cc) # for an example of how this header is used by the Nachos OS to set up the # address space for a new process that will run the executable. # # # Adding New Test Programs: # # You are free to write new test programs, and to modify the # existing programs. If you write a new program, you will # need to modify this makefile so that the new program will # get built. # You will need to make the following changes for each program # you add: # (1) add the program's name to PROGRAMS variable definition # (2) add dependencies and build commands for the new # program. The easiest way to do this is to # copy the dependencies and commands for an # existing program, and then change the names. # # For example, if you write a test program in foo.c, for which # the executable is to be called foo, you should do the following: # # change the PROGRAMS definition to look like this: # # PROGRAMS = halt shell matmult sort foo # # add these dependencies/commands: # # foo.o: foo.c # $(CC) $(CFLAGS) -c foo.c # foo: foo.o start.o # $(LD) $(LDFLAGS) start.o foo.o -o foo.coff # $(COFF2NOFF) foo.coff foo # # Be careful when you copy the commands! The commands # must be indented with a *TAB*, not a bunch of spaces. # # ############################################################################# # Makefile.dep contains all machine-dependent definitions # If you are trying to build coff2noff somewhere outside # of the MFCF environment, you will almost certainly want # to visit and edit Makefile.dep before doing so ############################################################################# include Makefile.dep CC = $(GCCDIR)gcc AS = $(GCCDIR)as LD = $(GCCDIR)ld INCDIR =-I../userprog -I../lib CFLAGS = -G 0 -c $(INCDIR) -B/usr/local/nachos/lib/gcc-lib/decstation-ultrix/2.95.2/ -B/usr/local/nachos/decstation-ultrix/bin/ ifeq ($(hosttype),unknown) PROGRAMS = unknownhost else # change this if you create a new test program! PROGRAMS = add halt shell matmult sort segments prog1 prog2 endif all: $(PROGRAMS) start.o: start.S ../userprog/syscall.h $(CC) $(CFLAGS) $(ASFLAGS) -c start.S halt.o: halt.c $(CC) $(CFLAGS) -c halt.c halt: halt.o start.o $(LD) $(LDFLAGS) start.o halt.o -o halt.coff $(COFF2NOFF) halt.coff halt add.o: add.c $(CC) $(CFLAGS) -c add.c add: add.o start.o $(LD) $(LDFLAGS) start.o add.o -o add.coff $(COFF2NOFF) add.coff add shell.o: shell.c $(CC) $(CFLAGS) -c shell.c shell: shell.o start.o $(LD) $(LDFLAGS) start.o shell.o -o shell.coff $(COFF2NOFF) shell.coff shell sort.o: sort.c $(CC) $(CFLAGS) -c sort.c sort: sort.o start.o $(LD) $(LDFLAGS) start.o sort.o -o sort.coff $(COFF2NOFF) sort.coff sort segments.o: segments.c $(CC) $(CFLAGS) -c segments.c segments: segments.o start.o $(LD) $(LDFLAGS) start.o segments.o -o segments.coff $(COFF2NOFF) segments.coff segments matmult.o: matmult.c $(CC) $(CFLAGS) -c matmult.c matmult: matmult.o start.o $(LD) $(LDFLAGS) start.o matmult.o -o matmult.coff $(COFF2NOFF) matmult.coff matmult prog1.o: prog1.c $(CC) $(CFLAGS) -c prog1.c prog1: prog1.o start.o $(LD) $(LDFLAGS) start.o prog1.o -o prog1.coff $(COFF2NOFF) prog1.coff prog1 prog2.o: prog2.c $(CC) $(CFLAGS) -c prog2.c prog2: prog2.o start.o $(LD) $(LDFLAGS) start.o prog2.o -o prog2.coff $(COFF2NOFF) prog2.coff prog2 clean: $(RM) -f *.o *.ii $(RM) -f *.coff distclean: clean $(RM) -f $(PROGRAMS) unknownhost: @echo Host type could not be determined. @echo make is terminating. @echo If you are on an MFCF machine, contact the instructor to report this problem @echo Otherwise, edit Makefile.dep and try again.

project4/nachos/code/test/shell

project4/nachos/code/test/sort.c

/* sort.c * Test program to sort a large number of integers. * * Intention is to stress virtual memory system. * * Ideally, we could read the unsorted array off of the file system, * and store the result back to the file system! */ /* #define UNIX #define UNIX_DEBUG */ #ifdef UNIX #include <stdio.h> #define Exit exit #else #include "syscall.h" #endif /* UNIX */ #define SIZE (1024) int A[SIZE]; /* size of physical memory; with code, we'll run out of space!*/ int main() { int i, j, tmp; /* first initialize the array, in reverse sorted order */ for (i = 0; i < SIZE; i++) { A[i] = (SIZE-1) - i; } /* then sort! */ for (i = 0; i < SIZE; i++) { for (j = 0; j < (SIZE-1); j++) { if (A[j] > A[j + 1]) { /* out of order -> need to swap ! */ tmp = A[j]; A[j] = A[j + 1]; A[j + 1] = tmp; } } } #ifdef UNIX_DEBUG for (i=0; i<SIZE; i++) { printf("%4d ", A[i]); if (((i+1) % 15) == 0) { printf("\n"); } if (A[i] != i) { fprintf(stderr, "Out of order A[%d] = %d\n", i, A[i]); Exit(1); } } printf("\n"); #endif /* UNIX_DEBUG */ for (i=0; i<SIZE; i++) { if (A[i] != i) { Exit(1); } } Exit(0); }

project4/nachos/code/test/DISK_0

project4/nachos/code/test/add.o

project4/nachos/code/test/sort.coff

project4/nachos/code/test/halt

project4/nachos/code/test/start.S

/* Start.s * Assembly language assist for user programs running on top of Nachos. * * Since we don't want to pull in the entire C library, we define * what we need for a user program here, namely Start and the system * calls. */ #define IN_ASM #include "syscall.h" .text .align 2 /* ------------------------------------------------------------- * __start * Initialize running a C program, by calling "main". * * NOTE: This has to be first, so that it gets loaded at location 0. * The Nachos kernel always starts a program by jumping to location 0. * ------------------------------------------------------------- */ .globl __start .ent __start __start: jal main move $4,$0 jal Exit /* if we return from main, exit(0) */ .end __start /* ------------------------------------------------------------- * System call stubs: * Assembly language assist to make system calls to the Nachos kernel. * There is one stub per system call, that places the code for the * system call into register r2, and leaves the arguments to the * system call alone (in other words, arg1 is in r4, arg2 is * in r5, arg3 is in r6, arg4 is in r7) * * The return value is in r2. This follows the standard C calling * convention on the MIPS. * ------------------------------------------------------------- */ .globl Halt .ent Halt Halt: addiu $2,$0,SC_Halt syscall j $31 .end Halt .globl Add .ent Add Add: addiu $2,$0,SC_Add syscall j $31 .end Add .globl Exit .ent Exit Exit: addiu $2,$0,SC_Exit syscall j $31 .end Exit .globl Exec .ent Exec Exec: addiu $2,$0,SC_Exec syscall j $31 .end Exec .globl ExecV .ent ExecV ExecV: addiu $2,$0,SC_ExecV syscall j $31 .end ExecV .globl Join .ent Join Join: addiu $2,$0,SC_Join syscall j $31 .end Join .globl Create .ent Create Create: addiu $2,$0,SC_Create syscall j $31 .end Create .globl Remove .ent Remove Remove: addiu $2,$0,SC_Remove syscall j $31 .end Remove .globl Open .ent Open Open: addiu $2,$0,SC_Open syscall j $31 .end Open .globl Read .ent Read Read: addiu $2,$0,SC_Read syscall j $31 .end Read .globl Write .ent Write Write: addiu $2,$0,SC_Write syscall j $31 .end Write .globl Close .ent Close Close: addiu $2,$0,SC_Close syscall j $31 .end Close .globl Seek .ent Seek Seek: addiu $2,$0,SC_Seek syscall j $31 .end Seek .globl ThreadFork .ent ThreadFork ThreadFork: addiu $2,$0,SC_ThreadFork syscall j $31 .end ThreadFork .globl ThreadYield .ent ThreadYield ThreadYield: addiu $2,$0,SC_ThreadYield syscall j $31 .end ThreadYield .globl ThreadExit .ent ThreadExit ThreadExit: addiu $2, $0, SC_ThreadExit syscall j $31 .end ThreadExit .globl ThreadJoin .ent ThreadJoin ThreadJoin: addiu $2, $0, SC_ThreadJoin syscall j $31 .end ThreadJoin /* dummy function to keep gcc happy */ .globl __main .ent __main __main: j $31 .end __main

project4/nachos/code/test/prog1.o

project4/nachos/code/test/script

OUTPUT_FORMAT("ecoff-littlemips") ENTRY(__start) SECTIONS { .text 0 : { _ftext = . ; *(.init) eprol = .; *(.text) *(.fini) etext = .; _etext = .; } .rdata . : { *(.rdata) } _fdata = .; .data . : { *(.data) CONSTRUCTORS } edata = .; _edata = .; _fbss = .; .sbss . : { *(.sbss) *(.scommon) } .bss . : { *(.bss) *(COMMON) } end = .; _end = .; }

project4/nachos/code/test/start.o

project4/nachos/code/test/prog2

project4/nachos/code/test/shell.c

#include "syscall.h" int main() { SpaceId newProc; OpenFileId input = ConsoleInput; OpenFileId output = ConsoleOutput; char prompt[2], ch, buffer[60]; int i; prompt[0] = '-'; prompt[1] = '-'; while( 1 ) { Write(prompt, 2, output); i = 0; do { Read(&buffer[i], 1, input); } while( buffer[i++] != '\n' ); buffer[--i] = '\0'; if( i > 0 ) { newProc = Exec(buffer); Join(newProc); } } }

project4/nachos/code/test/segments.o

project4/nachos/code/test/matmult.c

/* matmult.c * Test program to do matrix multiplication on large arrays. * * Intended to stress virtual memory system. * * Ideally, we could read the matrices off of the file system, * and store the result back to the file system! */ #include "syscall.h" #define Dim 20 /* sum total of the arrays doesn't fit in * physical memory */ int A[Dim][Dim]; int B[Dim][Dim]; int C[Dim][Dim]; int main() { int i, j, k; for (i = 0; i < Dim; i++) /* first initialize the matrices */ for (j = 0; j < Dim; j++) { A[i][j] = i; B[i][j] = j; C[i][j] = 0; } for (i = 0; i < Dim; i++) /* then multiply them together */ for (j = 0; j < Dim; j++) for (k = 0; k < Dim; k++) C[i][j] += A[i][k] * B[k][j]; Exit(C[Dim-1][Dim-1]); /* and then we're done */ }

project4/nachos/code/test/add

project4/nachos/code/test/prog2.c

#include "syscall.h" int main() { OpenFileId output = ConsoleOutput; char* str = "Hello from prog2\n"; int i,j; for (i = 0; i < 5; i++) { Write(str, 18, output); for (j = 0; j < 10000; j++); } Exit(0); }

project4/nachos/code/test/halt.coff

project4/nachos/code/test/prog1.coff

project4/nachos/code/test/halt.c

/* halt.c * Simple program to test whether running a user program works. * * Just do a "syscall" that shuts down the OS. * * NOTE: for some reason, user programs with global data structures * sometimes haven't worked in the Nachos environment. So be careful * out there! One option is to allocate data structures as * automatics within a procedure, but if you do this, you have to * be careful to allocate a big enough stack to hold the automatics! */ #include "syscall.h" int main() { Halt(); /* not reached */ }

project4/nachos/code/test/matmult.coff

project4/nachos/code/test/add.c

/* add.c * Simple program to test whether the systemcall interface works. * * Just do a add syscall that adds two values and returns the result. * */ #include "syscall.h" int main() { int result; result = Add(42, 23); Halt(); /* not reached */ }

project4/nachos/code/test/matmult

project4/nachos/code/test/sort.o

project4/nachos/code/test/segments.coff

project4/nachos/code/test/prog1.c

#include "syscall.h" char data[2048]; int main() { OpenFileId output = ConsoleOutput; char* str = "Hello from prog1\n"; int i,j; for (i = 0; i < 5; i++) { Write(str, 18, output); for (j = 0; j < 10000; j++); } Exit(0); }

project4/nachos/code/test/segments

project4/nachos/code/test/prog1

project4/nachos/code/network/post.h

// post.h // Data structures for providing the abstraction of unreliable, // ordered, fixed-size message delivery to mailboxes on other // (directly connected) machines. Messages can be dropped by // the network, but they are never corrupted. // // The US Post Office (and Canada Post! -KMS) // delivers mail to the addressed mailbox. // By analogy, our post office delivers packets to a specific buffer // (MailBox), based on the mailbox number stored in the packet header. // Mail waits in the box until a thread asks for it; if the mailbox // is empty, threads can wait for mail to arrive in it. // // Thus, the service our post office provides is to de-multiplex // incoming packets, delivering them to the appropriate thread. // // With each message, you get a return address, which consists of a "from // address", which is the id of the machine that sent the message, and // a "from box", which is the number of a mailbox on the sending machine // to which you can send an acknowledgement, if your protocol requires // this. // // Copyright (c) 1992-1996 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef POST_H #define POST_H #include "copyright.h" #include "utility.h" #include "callback.h" #include "network.h" #include "synchlist.h" #include "synch.h" // Mailbox address -- uniquely identifies a mailbox on a given machine. // A mailbox is just a place for temporary storage for messages. typedef int MailBoxAddress; // The following class defines part of the message header. // This is prepended to the message by the PostOffice, before the message // is sent to the Network. class MailHeader { public: MailBoxAddress to; // Destination mail box MailBoxAddress from; // Mail box to reply to unsigned length; // Bytes of message data (excluding the // mail header) }; // Maximum "payload" -- real data -- that can included in a single message // Excluding the MailHeader and the PacketHeader #define MaxMailSize (MaxPacketSize - sizeof(MailHeader)) // The following class defines the format of an incoming/outgoing // "Mail" message. The message format is layered: // network header (PacketHeader) // post office header (MailHeader) // data class Mail { public: Mail(PacketHeader pktH, MailHeader mailH, char *msgData); // Initialize a mail message by // concatenating the headers to the data PacketHeader pktHdr; // Header appended by Network MailHeader mailHdr; // Header appended by PostOffice char data[MaxMailSize]; // Payload -- message data }; // The following class defines a single mailbox, or temporary storage // for messages. Incoming messages are put by the PostOffice into the // appropriate mailbox, and these messages can then be retrieved by // threads on this machine. class MailBox { public: MailBox(); // Allocate and initialize mail box ~MailBox(); // De-allocate mail box void Put(PacketHeader pktHdr, MailHeader mailHdr, char *data); // Atomically put a message into the mailbox void Get(PacketHeader *pktHdr, MailHeader *mailHdr, char *data); // Atomically get a message out of the // mailbox (and wait if there is no message // to get!) private: SynchList<Mail *> *messages; // A mailbox is just a list of arrived messages }; // The following two classes defines a "Post Office", or a collection of // mailboxes. The Post Office provides two main operations: // Send -- send a message to a mailbox on a remote machine // Receive -- wait until a message is in the mailbox, then remove and // return it. // // Incoming messages are put by the PostOffice into the // appropriate mailbox, waking up any threads waiting on Receive. class PostOfficeInput : public CallBackObj { public: PostOfficeInput(int nBoxes); // Allocate and initialize Post Office ~PostOfficeInput(); // De-allocate Post Office data void Receive(int box, PacketHeader *pktHdr, MailHeader *mailHdr, char *data); // Retrieve a message from "box". Wait if // there is no message in the box. static void PostalDelivery(void* data); // Wait for incoming messages, // and then put them in the correct mailbox void CallBack(); // Called when incoming packet has arrived // and can be pulled off of network // (i.e., time to call PostalDelivery) private: NetworkInput *network; // Physical network connection MailBox *boxes; // Table of mail boxes to hold incoming mail int numBoxes; // Number of mail boxes Semaphore *messageAvailable;// V'ed when message has arrived from network }; class PostOfficeOutput : public CallBackObj { public: PostOfficeOutput(double reliability); // Allocate and initialize output // "reliability" is how many packets // get dropped by the underlying network ~PostOfficeOutput(); // De-allocate Post Office data void Send(PacketHeader pktHdr, MailHeader mailHdr, char *data); // Send a message to a mailbox on a remote // machine. The fromBox in the MailHeader is // the return box for ack's. void CallBack(); // Called when outgoing packet has been // put on network; next packet can now be sent private: NetworkOutput *network; // Physical network connection Semaphore *messageSent; // V'ed when next message can be sent to network Lock *sendLock; // Only one outgoing message at a time }; #endif

project4/nachos/code/network/post.cc

project4/nachos/code/network/post.cc

// post.cc 
//  Routines to deliver incoming network messages to the correct
//  "address" -- a mailbox, or a holding area for incoming messages.
//  This module operates just like the US postal service (in other
//  words, it works, but it's slow, and you can't really be sure if
//  your mail really got through!).
//
//  Note that once we prepend the MailHdr to the outgoing message data,
//  the combination (MailHdr plus data) looks like "data" to the Network 
//  device.
//
//  The implementation synchronizes incoming messages with threads
//  waiting for those messages.
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include   "copyright.h"
#include   "post.h"

//----------------------------------------------------------------------
// Mail::Mail
//      Initialize a single mail message, by concatenating the headers to
//  the data.
//
//  "pktH" -- source, destination machine ID's
//  "mailH" -- source, destination mailbox ID's
//  "data" -- payload data
//----------------------------------------------------------------------

Mail :: Mail ( PacketHeader  pktH ,   MailHeader  mailH ,   char   * msgData )
{
    ASSERT ( mailH . length  <=   MaxMailSize );

    pktHdr  =  pktH ;
    mailHdr  =  mailH ;
    bcopy ( msgData ,  data ,  mailHdr . length );
}

//----------------------------------------------------------------------
// MailBox::MailBox
//      Initialize a single mail box within the post office, so that it
//  can receive incoming messages.
//
//  Just initialize a list of messages, representing the mailbox.
//----------------------------------------------------------------------


MailBox :: MailBox ()
{  
    messages  =   new   SynchList < Mail   *> ();  
}

//----------------------------------------------------------------------
// MailBox::~MailBox
//      De-allocate a single mail box within the post office.
//
//  Just delete the mailbox, and throw away all the queued messages 
//  in the mailbox.
//----------------------------------------------------------------------

MailBox ::~ MailBox ()
{  
     delete  messages ;  
}

//----------------------------------------------------------------------
// PrintHeader
//  Print the message header -- the destination machine ID and mailbox
//  #, source machine ID and mailbox #, and message length.
//
//  "pktHdr" -- source, destination machine ID's
//  "mailHdr" -- source, destination mailbox ID's
//----------------------------------------------------------------------

static   void  
PrintHeader ( PacketHeader  pktHdr ,   MailHeader  mailHdr )
{
    cout  <<   "From ("   <<  pktHdr . from  <<   ", "   <<  mailHdr . from  <<   ") to ("   <<  
    pktHdr . to  <<   ", "   <<  mailHdr . to  <<   ") bytes "   <<  mailHdr . length  <<   "\n" ;
}

//----------------------------------------------------------------------
// MailBox::Put
//  Add a message to the mailbox.  If anyone is waiting for message
//  arrival, wake them up!
//
//  We need to reconstruct the Mail message (by concatenating the headers
//  to the data), to simplify queueing the message on the SynchList.
//
//  "pktHdr" -- source, destination machine ID's
//  "mailHdr" -- source, destination mailbox ID's
//  "data" -- payload message data
//----------------------------------------------------------------------

void  
MailBox :: Put ( PacketHeader  pktHdr ,   MailHeader  mailHdr ,   char   * data )
{  
     Mail   * mail  =   new   Mail ( pktHdr ,  mailHdr ,  data );  

    messages -> Append ( mail );       // put on the end of the list of 
                     // arrived messages, and wake up 
                     // any waiters
}

//----------------------------------------------------------------------
// MailBox::Get
//  Get a message from a mailbox, parsing it into the packet header,
//  mailbox header, and data. 
//
//  The calling thread waits if there are no messages in the mailbox.
//
//  "pktHdr" -- address to put: source, destination machine ID's
//  "mailHdr" -- address to put: source, destination mailbox ID's
//  "data" -- address to put: payload message data
//----------------------------------------------------------------------

void  
MailBox :: Get ( PacketHeader   * pktHdr ,   MailHeader   * mailHdr ,   char   * data )  
{  
    DEBUG ( dbgNet ,   "Waiting for mail in mailbox" );
     Mail   * mail  =  messages -> RemoveFront ();     // remove message from list;
                         // will wait if list is empty

     * pktHdr  =  mail -> pktHdr ;
     * mailHdr  =  mail -> mailHdr ;
     if   ( debug -> IsEnabled ( 'n' ))   {
    cout  <<   "Got mail from mailbox: " ;
     PrintHeader ( * pktHdr ,   * mailHdr );
     }
    bcopy ( mail -> data ,  data ,  mail -> mailHdr . length );
                     // copy the message data into
                     // the caller's buffer
     delete  mail ;              // we've copied out the stuff we
                     // need, we can now discard the message
}

//----------------------------------------------------------------------
// PostOfficeInput::PostOfficeInput
//  Initialize the post office input queues as a collection of mailboxes.
//  Also initialize the network device, to allow post offices
//  on different machines to deliver messages to one another.
//
//      We use a separate thread "the postal worker" to wait for messages 
//  to arrive, and deliver them to the correct mailbox.  Note that
//  delivering messages to the mailboxes can't be done directly
//  by the interrupt handlers, because it requires a Lock.
//
//  "nBoxes" is the number of mail boxes in this Post Office
//----------------------------------------------------------------------

PostOfficeInput :: PostOfficeInput ( int  nBoxes )
{
    messageAvailable  =   new   Semaphore ( "message available" ,   0 );

    numBoxes  =  nBoxes ;
    boxes  =   new   MailBox [ nBoxes ];

    network  =   new   NetworkInput ( this );

     Thread   * =   new   Thread ( "postal worker" );

    t -> Fork ( PostOfficeInput :: PostalDelivery ,   this );
}

//----------------------------------------------------------------------
// PostOfficeInput::~PostOfficeInput
//  De-allocate the post office data structures.
//  
//  Since the postal helper is waiting on the "messageAvail" semaphore,
//  we don't deallocate it!  This leaves garbage lying about,
//  but the alternative is worse!
//----------------------------------------------------------------------

PostOfficeInput ::~ PostOfficeInput ()
{
     delete  network ;
     delete   []  boxes ;
}

//----------------------------------------------------------------------
// PostOffice::PostalDelivery
//  Wait for incoming messages, and put them in the right mailbox.
//
//      Incoming messages have had the PacketHeader stripped off,
//  but the MailHeader is still tacked on the front of the data.
//----------------------------------------------------------------------

void
PostOfficeInput :: PostalDelivery ( void *  data )
{
     PostOfficeInput *  _this  =   ( PostOfficeInput * ) data ;
     PacketHeader  pktHdr ;
     MailHeader  mailHdr ;
     char   * buffer  =   new   char [ MaxPacketSize ];

     for   (;;)   {
         // first, wait for a message
        _this -> messageAvailable -> P ();    
        pktHdr  =  _this -> network -> Receive ( buffer );

        mailHdr  =   * ( MailHeader   * ) buffer ;
         if   ( debug -> IsEnabled ( 'n' ))   {
        cout  <<   "Putting mail into mailbox: " ;
         PrintHeader ( pktHdr ,  mailHdr );
         }

     // check that arriving message is legal!
    ASSERT ( 0   <=  mailHdr . to  &&  mailHdr . to  <  _this -> numBoxes );
    ASSERT ( mailHdr . length  <=   MaxMailSize );

     // put into mailbox
        _this -> boxes [ mailHdr . to ]. Put ( pktHdr ,  mailHdr ,  buffer  +   sizeof ( MailHeader ));
     }
}

//----------------------------------------------------------------------
// PostOfficeInput::Receive
//  Retrieve a message from a specific box if one is available, 
//  otherwise wait for a message to arrive in the box.
//
//  Note that the MailHeader + data looks just like normal payload
//  data to the Network.
//
//
//  "box" -- mailbox ID in which to look for message
//  "pktHdr" -- address to put: source, destination machine ID's
//  "mailHdr" -- address to put: source, destination mailbox ID's
//  "data" -- address to put: payload message data
//----------------------------------------------------------------------

void
PostOfficeInput :: Receive ( int  box ,   PacketHeader   * pktHdr ,  
                 MailHeader   * mailHdr ,   char *  data )
{
    ASSERT (( box  >=   0 )   &&   ( box  <  numBoxes ));

    boxes [ box ]. Get ( pktHdr ,  mailHdr ,  data );
    ASSERT ( mailHdr -> length  <=   MaxMailSize );
}

//----------------------------------------------------------------------
// PostOffice::CallBack
//  Interrupt handler, called when a packet arrives from the network.
//
//  Signal the PostalDelivery routine that it is time to get to work!
//----------------------------------------------------------------------

void
PostOfficeInput :: CallBack ()
{  
    messageAvailable -> V ();  
}

//----------------------------------------------------------------------
// PostOfficeOutput::PostOfficeOutput
//  Initialize the post office output queue.
//
//  "reliability" is the probability that a network packet will
//    be delivered (e.g., reliability = 1 means the network never
//    drops any packets; reliability = 0 means the network never
//    delivers any packets)
//----------------------------------------------------------------------

PostOfficeOutput :: PostOfficeOutput ( double  reliability )
{
    messageSent  =   new   Semaphore ( "message sent" ,   0 );
    sendLock  =   new   Lock ( "message send lock" );

    network  =   new   NetworkOutput ( reliability ,   this );
}

//----------------------------------------------------------------------
// PostOfficeOutput::~PostOfficeOutput
//  De-allocate the post office data structures.
//----------------------------------------------------------------------

PostOfficeOutput ::~ PostOfficeOutput ()
{
     delete  network ;
     delete  messageSent ;
     delete  sendLock ;
}

//----------------------------------------------------------------------
// PostOfficeOutput::Send
//  Concatenate the MailHeader to the front of the data, and pass 
//  the result to the Network for delivery to the destination machine.
//
//  Note that the MailHeader + data looks just like normal payload
//  data to the Network.
//
//  "pktHdr" -- source, destination machine ID's
//  "mailHdr" -- source, destination mailbox ID's
//  "data" -- payload message data
//----------------------------------------------------------------------

void
PostOfficeOutput :: Send ( PacketHeader  pktHdr ,   MailHeader  mailHdr ,   char *  data )
{
     char *  buffer  =   new   char [ MaxPacketSize ];   // space to hold concatenated
                         // mailHdr + data

     if   ( debug -> IsEnabled ( 'n' ))   {
    cout  <<   "Post send: " ;
     PrintHeader ( pktHdr ,  mailHdr );
     }
    ASSERT ( mailHdr . length  <=   MaxMailSize );
    ASSERT ( 0   <=  mailHdr . to );
    
     // fill in pktHdr, for the Network layer
    pktHdr . from  =  kernel -> hostName ;
    pktHdr . length  =  mailHdr . length  +   sizeof ( MailHeader );

     // concatenate MailHeader and data
    bcopy (( char   * ) & mailHdr ,  buffer ,   sizeof ( MailHeader ));
    bcopy ( data ,  buffer  +   sizeof ( MailHeader ),  mailHdr . length );

    sendLock -> Acquire ();          // only one message can be sent
                     // to the network at any one time
    network -> Send ( pktHdr ,  buffer );
    messageSent -> P ();             // wait for interrupt to tell us
                     // ok to send the next message
    sendLock -> Release ();

     delete   []  buffer ;             // we've sent the message, so
                     // we can delete our buffer
}

//----------------------------------------------------------------------
// PostOfficeOutput::CallBack
//  Interrupt handler, called when the next packet can be put onto the 
//  network.
//
//  Called even if the previous packet was dropped.
//----------------------------------------------------------------------

void  
PostOfficeOutput :: CallBack ()
{  
    messageSent -> V ();
}

project4/nachos/code/filesys/synchdisk.cc

project4/nachos/code/filesys/synchdisk.cc

// synchdisk.cc 
//  Routines to synchronously access the disk.  The physical disk 
//  is an asynchronous device (disk requests return immediately, and
//  an interrupt happens later on).  This is a layer on top of
//  the disk providing a synchronous interface (requests wait until
//  the request completes).
//
//  Use a semaphore to synchronize the interrupt handlers with the
//  pending requests.  And, because the physical disk can only
//  handle one operation at a time, use a lock to enforce mutual
//  exclusion.
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include   "copyright.h"
#include   "synchdisk.h"


//----------------------------------------------------------------------
// SynchDisk::SynchDisk
//  Initialize the synchronous interface to the physical disk, in turn
//  initializing the physical disk.
//
//----------------------------------------------------------------------

SynchDisk :: SynchDisk ()
{
    semaphore  =   new   Semaphore ( "synch disk" ,   0 );
    lock  =   new   Lock ( "synch disk lock" );
    disk  =   new   Disk ( this );
}

//----------------------------------------------------------------------
// SynchDisk::~SynchDisk
//  De-allocate data structures needed for the synchronous disk
//  abstraction.
//----------------------------------------------------------------------

SynchDisk ::~ SynchDisk ()
{
     delete  disk ;
     delete  lock ;
     delete  semaphore ;
}

//----------------------------------------------------------------------
// SynchDisk::ReadSector
//  Read the contents of a disk sector into a buffer.  Return only
//  after the data has been read.
//
//  "sectorNumber" -- the disk sector to read
//  "data" -- the buffer to hold the contents of the disk sector
//----------------------------------------------------------------------

void
SynchDisk :: ReadSector ( int  sectorNumber ,   char *  data )
{
    lock -> Acquire ();              // only one disk I/O at a time
    disk -> ReadRequest ( sectorNumber ,  data );
    semaphore -> P ();           // wait for interrupt
    lock -> Release ();
}

//----------------------------------------------------------------------
// SynchDisk::WriteSector
//  Write the contents of a buffer into a disk sector.  Return only
//  after the data has been written.
//
//  "sectorNumber" -- the disk sector to be written
//  "data" -- the new contents of the disk sector
//----------------------------------------------------------------------

void
SynchDisk :: WriteSector ( int  sectorNumber ,   char *  data )
{
    lock -> Acquire ();              // only one disk I/O at a time
    disk -> WriteRequest ( sectorNumber ,  data );
    semaphore -> P ();           // wait for interrupt
    lock -> Release ();
}

//----------------------------------------------------------------------
// SynchDisk::CallBack
//  Disk interrupt handler.  Wake up any thread waiting for the disk
//  request to finish.
//----------------------------------------------------------------------

void
SynchDisk :: CallBack ()
{  
    semaphore -> V ();
}

project4/nachos/code/filesys/filehdr.h

// filehdr.h // Data structures for managing a disk file header. // // A file header describes where on disk to find the data in a file, // along with other information about the file (for instance, its // length, owner, etc.) // // Copyright (c) 1992-1993 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #include "copyright.h" #ifndef FILEHDR_H #define FILEHDR_H #include "disk.h" #include "pbitmap.h" #define NumDirect ((SectorSize - 2 * sizeof(int)) / sizeof(int)) #define MaxFileSize (NumDirect * SectorSize) // The following class defines the Nachos "file header" (in UNIX terms, // the "i-node"), describing where on disk to find all of the data in the file. // The file header is organized as a simple table of pointers to // data blocks. // // The file header data structure can be stored in memory or on disk. // When it is on disk, it is stored in a single sector -- this means // that we assume the size of this data structure to be the same // as one disk sector. Without indirect addressing, this // limits the maximum file length to just under 4K bytes. // // There is no constructor; rather the file header can be initialized // by allocating blocks for the file (if it is a new file), or by // reading it from disk. class FileHeader { public: bool Allocate(PersistentBitmap *bitMap, int fileSize);// Initialize a file header, // including allocating space // on disk for the file data void Deallocate(PersistentBitmap *bitMap); // De-allocate this file's // data blocks void FetchFrom(int sectorNumber); // Initialize file header from disk void WriteBack(int sectorNumber); // Write modifications to file header // back to disk int ByteToSector(int offset); // Convert a byte offset into the file // to the disk sector containing // the byte int FileLength(); // Return the length of the file // in bytes void Print(); // Print the contents of the file. private: int numBytes; // Number of bytes in the file int numSectors; // Number of data sectors in the file int dataSectors[NumDirect]; // Disk sector numbers for each data // block in the file }; #endif // FILEHDR_H

project4/nachos/code/filesys/filesys.h

// filesys.h // Data structures to represent the Nachos file system. // // A file system is a set of files stored on disk, organized // into directories. Operations on the file system have to // do with "naming" -- creating, opening, and deleting files, // given a textual file name. Operations on an individual // "open" file (read, write, close) are to be found in the OpenFile // class (openfile.h). // // We define two separate implementations of the file system. // The "STUB" version just re-defines the Nachos file system // operations as operations on the native UNIX file system on the machine // running the Nachos simulation. // // The other version is a "real" file system, built on top of // a disk simulator. The disk is simulated using the native UNIX // file system (in a file named "DISK"). // // In the "real" implementation, there are two key data structures used // in the file system. There is a single "root" directory, listing // all of the files in the file system; unlike UNIX, the baseline // system does not provide a hierarchical directory structure. // In addition, there is a bitmap for allocating // disk sectors. Both the root directory and the bitmap are themselves // stored as files in the Nachos file system -- this causes an interesting // bootstrap problem when the simulated disk is initialized. // // Copyright (c) 1992-1993 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef FS_H #define FS_H #include "copyright.h" #include "sysdep.h" #include "openfile.h" #ifdef FILESYS_STUB // Temporarily implement file system calls as // calls to UNIX, until the real file system // implementation is available class FileSystem { public: FileSystem() {} bool Create(char *name) { int fileDescriptor = OpenForWrite(name); if (fileDescriptor == -1) return FALSE; Close(fileDescriptor); return TRUE; } OpenFile* Open(char *name) { int fileDescriptor = OpenForReadWrite(name, FALSE); if (fileDescriptor == -1) return NULL; return new OpenFile(fileDescriptor); } bool Remove(char *name) { return Unlink(name) == 0; } }; #else // FILESYS class FileSystem { public: FileSystem(bool format); // Initialize the file system. // Must be called *after* "synchDisk" // has been initialized. // If "format", there is nothing on // the disk, so initialize the directory // and the bitmap of free blocks. bool Create(char *name, int initialSize); // Create a file (UNIX creat) OpenFile* Open(char *name); // Open a file (UNIX open) bool Remove(char *name); // Delete a file (UNIX unlink) void List(); // List all the files in the file system void Print(); // List all the files and their contents private: OpenFile* freeMapFile; // Bit map of free disk blocks, // represented as a file OpenFile* directoryFile; // "Root" directory -- list of // file names, represented as a file }; #endif // FILESYS #endif // FS_H

project4/nachos/code/filesys/directory.cc

project4/nachos/code/filesys/directory.cc

// directory.cc 
//  Routines to manage a directory of file names.
//
//  The directory is a table of fixed length entries; each
//  entry represents a single file, and contains the file name,
//  and the location of the file header on disk.  The fixed size
//  of each directory entry means that we have the restriction
//  of a fixed maximum size for file names.
//
//  The constructor initializes an empty directory of a certain size;
//  we use ReadFrom/WriteBack to fetch the contents of the directory
//  from disk, and to write back any modifications back to disk.
//
//  Also, this implementation has the restriction that the size
//  of the directory cannot expand.  In other words, once all the
//  entries in the directory are used, no more files can be created.
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include   "copyright.h"
#include   "utility.h"
#include   "filehdr.h"
#include   "directory.h"

//----------------------------------------------------------------------
// Directory::Directory
//  Initialize a directory; initially, the directory is completely
//  empty.  If the disk is being formatted, an empty directory
//  is all we need, but otherwise, we need to call FetchFrom in order
//  to initialize it from disk.
//
//  "size" is the number of entries in the directory
//----------------------------------------------------------------------

Directory :: Directory ( int  size )
{
    table  =   new   DirectoryEntry [ size ];
    tableSize  =  size ;
     for   ( int  i  =   0 ;  i  <  tableSize ;  i ++ )
    table [ i ]. inUse  =  FALSE ;
}

//----------------------------------------------------------------------
// Directory::~Directory
//  De-allocate directory data structure.
//----------------------------------------------------------------------

Directory ::~ Directory ()
{  
     delete   []  table ;
}  

//----------------------------------------------------------------------
// Directory::FetchFrom
//  Read the contents of the directory from disk.
//
//  "file" -- file containing the directory contents
//----------------------------------------------------------------------

void
Directory :: FetchFrom ( OpenFile   * file )
{
     ( void )  file -> ReadAt (( char   * ) table ,  tableSize  *   sizeof ( DirectoryEntry ),   0 );
}

//----------------------------------------------------------------------
// Directory::WriteBack
//  Write any modifications to the directory back to disk
//
//  "file" -- file to contain the new directory contents
//----------------------------------------------------------------------

void
Directory :: WriteBack ( OpenFile   * file )
{
     ( void )  file -> WriteAt (( char   * ) table ,  tableSize  *   sizeof ( DirectoryEntry ),   0 );
}

//----------------------------------------------------------------------
// Directory::FindIndex
//  Look up file name in directory, and return its location in the table of
//  directory entries.  Return -1 if the name isn't in the directory.
//
//  "name" -- the file name to look up
//----------------------------------------------------------------------

int
Directory :: FindIndex ( char   * name )
{
     for   ( int  i  =   0 ;  i  <  tableSize ;  i ++ )
         if   ( table [ i ]. inUse  &&   ! strncmp ( table [ i ]. name ,  name ,   FileNameMaxLen ))
         return  i ;
     return   - 1 ;        // name not in directory
}

//----------------------------------------------------------------------
// Directory::Find
//  Look up file name in directory, and return the disk sector number
//  where the file's header is stored. Return -1 if the name isn't 
//  in the directory.
//
//  "name" -- the file name to look up
//----------------------------------------------------------------------

int
Directory :: Find ( char   * name )
{
     int  i  =   FindIndex ( name );

     if   ( !=   - 1 )
     return  table [ i ]. sector ;
     return   - 1 ;
}

//----------------------------------------------------------------------
// Directory::Add
//  Add a file into the directory.  Return TRUE if successful;
//  return FALSE if the file name is already in the directory, or if
//  the directory is completely full, and has no more space for
//  additional file names.
//
//  "name" -- the name of the file being added
//  "newSector" -- the disk sector containing the added file's header
//----------------------------------------------------------------------

bool
Directory :: Add ( char   * name ,   int  newSector )
{  
     if   ( FindIndex ( name )   !=   - 1 )
     return  FALSE ;

     for   ( int  i  =   0 ;  i  <  tableSize ;  i ++ )
         if   ( ! table [ i ]. inUse )   {
            table [ i ]. inUse  =  TRUE ;
            strncpy ( table [ i ]. name ,  name ,   FileNameMaxLen );  
            table [ i ]. sector  =  newSector ;
         return  TRUE ;
     }
     return  FALSE ;     // no space.  Fix when we have extensible files.
}

//----------------------------------------------------------------------
// Directory::Remove
//  Remove a file name from the directory.  Return TRUE if successful;
//  return FALSE if the file isn't in the directory. 
//
//  "name" -- the file name to be removed
//----------------------------------------------------------------------

bool
Directory :: Remove ( char   * name )
{  
     int  i  =   FindIndex ( name );

     if   ( ==   - 1 )
     return  FALSE ;         // name not in directory
    table [ i ]. inUse  =  FALSE ;
     return  TRUE ;     
}

//----------------------------------------------------------------------
// Directory::List
//  List all the file names in the directory. 
//----------------------------------------------------------------------

void
Directory :: List ()
{
    for   ( int  i  =   0 ;  i  <  tableSize ;  i ++ )
     if   ( table [ i ]. inUse )
        printf ( "%s\n" ,  table [ i ]. name );
}

//----------------------------------------------------------------------
// Directory::Print
//  List all the file names in the directory, their FileHeader locations,
//  and the contents of each file.  For debugging.
//----------------------------------------------------------------------

void
Directory :: Print ()
{  
     FileHeader   * hdr  =   new   FileHeader ;

    printf ( "Directory contents:\n" );
     for   ( int  i  =   0 ;  i  <  tableSize ;  i ++ )
     if   ( table [ i ]. inUse )   {
        printf ( "Name: %s, Sector: %d\n" ,  table [ i ]. name ,  table [ i ]. sector );
        hdr -> FetchFrom ( table [ i ]. sector );
        hdr -> Print ();
     }
    printf ( "\n" );
     delete  hdr ;
}

project4/nachos/code/filesys/openfile.cc

project4/nachos/code/filesys/openfile.cc

// openfile.cc 
//  Routines to manage an open Nachos file.  As in UNIX, a
//  file must be open before we can read or write to it.
//  Once we're all done, we can close it (in Nachos, by deleting
//  the OpenFile data structure).
//
//  Also as in UNIX, for convenience, we keep the file header in
//  memory while the file is open.
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.
#ifndef  FILESYS_STUB

#include   "copyright.h"
#include   "main.h"
#include   "filehdr.h"
#include   "openfile.h"
#include   "synchdisk.h"

//----------------------------------------------------------------------
// OpenFile::OpenFile
//  Open a Nachos file for reading and writing.  Bring the file header
//  into memory while the file is open.
//
//  "sector" -- the location on disk of the file header for this file
//----------------------------------------------------------------------

OpenFile :: OpenFile ( int  sector )
{  
    hdr  =   new   FileHeader ;
    hdr -> FetchFrom ( sector );
    seekPosition  =   0 ;
}

//----------------------------------------------------------------------
// OpenFile::~OpenFile
//  Close a Nachos file, de-allocating any in-memory data structures.
//----------------------------------------------------------------------

OpenFile ::~ OpenFile ()
{
     delete  hdr ;
}

//----------------------------------------------------------------------
// OpenFile::Seek
//  Change the current location within the open file -- the point at
//  which the next Read or Write will start from.
//
//  "position" -- the location within the file for the next Read/Write
//----------------------------------------------------------------------

void
OpenFile :: Seek ( int  position )
{
    seekPosition  =  position ;
}    

//----------------------------------------------------------------------
// OpenFile::Read/Write
//  Read/write a portion of a file, starting from seekPosition.
//  Return the number of bytes actually written or read, and as a
//  side effect, increment the current position within the file.
//
//  Implemented using the more primitive ReadAt/WriteAt.
//
//  "into" -- the buffer to contain the data to be read from disk 
//  "from" -- the buffer containing the data to be written to disk 
//  "numBytes" -- the number of bytes to transfer
//----------------------------------------------------------------------

int
OpenFile :: Read ( char   * into ,   int  numBytes )
{
    int  result  =   ReadAt ( into ,  numBytes ,  seekPosition );
   seekPosition  +=  result ;
    return  result ;
}

int
OpenFile :: Write ( char   * into ,   int  numBytes )
{
    int  result  =   WriteAt ( into ,  numBytes ,  seekPosition );
   seekPosition  +=  result ;
    return  result ;
}

//----------------------------------------------------------------------
// OpenFile::ReadAt/WriteAt
//  Read/write a portion of a file, starting at "position".
//  Return the number of bytes actually written or read, but has
//  no side effects (except that Write modifies the file, of course).
//
//  There is no guarantee the request starts or ends on an even disk sector
//  boundary; however the disk only knows how to read/write a whole disk
//  sector at a time.  Thus:
//
//  For ReadAt:
//     We read in all of the full or partial sectors that are part of the
//     request, but we only copy the part we are interested in.
//  For WriteAt:
//     We must first read in any sectors that will be partially written,
//     so that we don't overwrite the unmodified portion.  We then copy
//     in the data that will be modified, and write back all the full
//     or partial sectors that are part of the request.
//
//  "into" -- the buffer to contain the data to be read from disk 
//  "from" -- the buffer containing the data to be written to disk 
//  "numBytes" -- the number of bytes to transfer
//  "position" -- the offset within the file of the first byte to be
//          read/written
//----------------------------------------------------------------------

int
OpenFile :: ReadAt ( char   * into ,   int  numBytes ,   int  position )
{
     int  fileLength  =  hdr -> FileLength ();
     int  i ,  firstSector ,  lastSector ,  numSectors ;
     char   * buf ;

     if   (( numBytes  <=   0 )   ||   ( position  >=  fileLength ))
         return   0 ;                 // check request
     if   (( position  +  numBytes )   >  fileLength )      
    numBytes  =  fileLength  -  position ;
    DEBUG ( dbgFile ,   "Reading "   <<  numBytes  <<   " bytes at "   <<  position  <<   " from file of length "   <<  fileLength );

    firstSector  =  divRoundDown ( position ,   SectorSize );
    lastSector  =  divRoundDown ( position  +  numBytes  -   1 ,   SectorSize );
    numSectors  =   1   +  lastSector  -  firstSector ;

     // read in all the full and partial sectors that we need
    buf  =   new   char [ numSectors  *   SectorSize ];
     for   ( =  firstSector ;  i  <=  lastSector ;  i ++ )  
        kernel -> synchDisk -> ReadSector ( hdr -> ByteToSector ( *   SectorSize ),  
                     & buf [( -  firstSector )   *   SectorSize ]);

     // copy the part we want
    bcopy ( & buf [ position  -   ( firstSector  *   SectorSize )],  into ,  numBytes );
     delete   []  buf ;
     return  numBytes ;
}

int
OpenFile :: WriteAt ( char   * from ,   int  numBytes ,   int  position )
{
     int  fileLength  =  hdr -> FileLength ();
     int  i ,  firstSector ,  lastSector ,  numSectors ;
     bool  firstAligned ,  lastAligned ;
     char   * buf ;

     if   (( numBytes  <=   0 )   ||   ( position  >=  fileLength ))
     return   0 ;                 // check request
     if   (( position  +  numBytes )   >  fileLength )
    numBytes  =  fileLength  -  position ;
    DEBUG ( dbgFile ,   "Writing "   <<  numBytes  <<   " bytes at "   <<  position  <<   " from file of length "   <<  fileLength );

    firstSector  =  divRoundDown ( position ,   SectorSize );
    lastSector  =  divRoundDown ( position  +  numBytes  -   1 ,   SectorSize );
    numSectors  =   1   +  lastSector  -  firstSector ;

    buf  =   new   char [ numSectors  *   SectorSize ];

    firstAligned  =   ( position  ==   ( firstSector  *   SectorSize ));
    lastAligned  =   (( position  +  numBytes )   ==   (( lastSector  +   1 )   *   SectorSize ));

// read in first and last sector, if they are to be partially modified
     if   ( ! firstAligned )
         ReadAt ( buf ,   SectorSize ,  firstSector  *   SectorSize );   
     if   ( ! lastAligned  &&   (( firstSector  !=  lastSector )   ||  firstAligned ))
         ReadAt ( & buf [( lastSector  -  firstSector )   *   SectorSize ],  
                 SectorSize ,  lastSector  *   SectorSize );    

// copy in the bytes we want to change 
    bcopy ( from ,   & buf [ position  -   ( firstSector  *   SectorSize )],  numBytes );

// write modified sectors back
     for   ( =  firstSector ;  i  <=  lastSector ;  i ++ )  
        kernel -> synchDisk -> WriteSector ( hdr -> ByteToSector ( *   SectorSize ),  
                     & buf [( -  firstSector )   *   SectorSize ]);
     delete   []  buf ;
     return  numBytes ;
}

//----------------------------------------------------------------------
// OpenFile::Length
//  Return the number of bytes in the file.
//----------------------------------------------------------------------

int
OpenFile :: Length ()  
{  
     return  hdr -> FileLength ();  
}

#endif   //FILESYS_STUB

project4/nachos/code/filesys/pbitmap.cc

project4/nachos/code/filesys/pbitmap.cc

// pbitmap.c 
//  Routines to manage a persistent bitmap -- a bitmap that is
//  stored on disk.
//
// Copyright (c) 1992,1993,1995 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include   "copyright.h"
#include   "pbitmap.h"

//----------------------------------------------------------------------
// PersistentBitmap::PersistentBitmap(int)
//  Initialize a bitmap with "numItems" bits, so that every bit is clear.
//  it can be added somewhere on a list.
//
//  "numItems" is the number of bits in the bitmap.
//
//      This constructor does not initialize the bitmap from a disk file
//----------------------------------------------------------------------

PersistentBitmap :: PersistentBitmap ( int  numItems ) : Bitmap ( numItems )  
{  
}

//----------------------------------------------------------------------
// PersistentBitmap::PersistentBitmap(OpenFile*,int)
//  Initialize a persistent bitmap with "numItems" bits,
//      so that every bit is clear.
//
//  "numItems" is the number of bits in the bitmap.
//      "file" refers to an open file containing the bitmap (written
//        by a previous call to PersistentBitmap::WriteBack
//
//      This constructor initializes the bitmap from a disk file
//----------------------------------------------------------------------

PersistentBitmap :: PersistentBitmap ( OpenFile   * file ,   int  numItems ) : Bitmap ( numItems )  
{  
     // map has already been initialized by the BitMap constructor,
     // but we will just overwrite that with the contents of the
     // map found in the file
    file -> ReadAt (( char   * ) map ,  numWords  *   sizeof ( unsigned ),   0 );
}

//----------------------------------------------------------------------
// PersistentBitmap::~PersistentBitmap
//  De-allocate a persistent bitmap.
//----------------------------------------------------------------------

PersistentBitmap ::~ PersistentBitmap ()
{  
}

//----------------------------------------------------------------------
// PersistentBitmap::FetchFrom
//  Initialize the contents of a persistent bitmap from a Nachos file.
//
//  "file" is the place to read the bitmap from
//----------------------------------------------------------------------

void
PersistentBitmap :: FetchFrom ( OpenFile   * file )  
{
    file -> ReadAt (( char   * ) map ,  numWords  *   sizeof ( unsigned ),   0 );
}

//----------------------------------------------------------------------
// PersistentBitmap::WriteBack
//  Store the contents of a persistent bitmap to a Nachos file.
//
//  "file" is the place to write the bitmap to
//----------------------------------------------------------------------

void
PersistentBitmap :: WriteBack ( OpenFile   * file )
{
   file -> WriteAt (( char   * ) map ,  numWords  *   sizeof ( unsigned ),   0 );
}

project4/nachos/code/filesys/directory.h

// directory.h // Data structures to manage a UNIX-like directory of file names. // // A directory is a table of pairs: <file name, sector #>, // giving the name of each file in the directory, and // where to find its file header (the data structure describing // where to find the file's data blocks) on disk. // // We assume mutual exclusion is provided by the caller. // // Copyright (c) 1992-1993 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #include "copyright.h" #ifndef DIRECTORY_H #define DIRECTORY_H #include "openfile.h" #define FileNameMaxLen 9 // for simplicity, we assume // file names are <= 9 characters long // The following class defines a "directory entry", representing a file // in the directory. Each entry gives the name of the file, and where // the file's header is to be found on disk. // // Internal data structures kept public so that Directory operations can // access them directly. class DirectoryEntry { public: bool inUse; // Is this directory entry in use? int sector; // Location on disk to find the // FileHeader for this file char name[FileNameMaxLen + 1]; // Text name for file, with +1 for // the trailing '\0' }; // The following class defines a UNIX-like "directory". Each entry in // the directory describes a file, and where to find it on disk. // // The directory data structure can be stored in memory, or on disk. // When it is on disk, it is stored as a regular Nachos file. // // The constructor initializes a directory structure in memory; the // FetchFrom/WriteBack operations shuffle the directory information // from/to disk. class Directory { public: Directory(int size); // Initialize an empty directory // with space for "size" files ~Directory(); // De-allocate the directory void FetchFrom(OpenFile *file); // Init directory contents from disk void WriteBack(OpenFile *file); // Write modifications to // directory contents back to disk int Find(char *name); // Find the sector number of the // FileHeader for file: "name" bool Add(char *name, int newSector); // Add a file name into the directory bool Remove(char *name); // Remove a file from the directory void List(); // Print the names of all the files // in the directory void Print(); // Verbose print of the contents // of the directory -- all the file // names and their contents. private: int tableSize; // Number of directory entries DirectoryEntry *table; // Table of pairs: // <file name, file header location> int FindIndex(char *name); // Find the index into the directory // table corresponding to "name" }; #endif // DIRECTORY_H

project4/nachos/code/filesys/openfile.h

// openfile.h // Data structures for opening, closing, reading and writing to // individual files. The operations supported are similar to // the UNIX ones -- type 'man open' to the UNIX prompt. // // There are two implementations. One is a "STUB" that directly // turns the file operations into the underlying UNIX operations. // (cf. comment in filesys.h). // // The other is the "real" implementation, that turns these // operations into read and write disk sector requests. // In this baseline implementation of the file system, we don't // worry about concurrent accesses to the file system // by different threads. // // Copyright (c) 1992-1993 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef OPENFILE_H #define OPENFILE_H #include "copyright.h" #include "utility.h" #include "sysdep.h" #ifdef FILESYS_STUB // Temporarily implement calls to // Nachos file system as calls to UNIX! // See definitions listed under #else class OpenFile { public: OpenFile(int f) { file = f; currentOffset = 0; } // open the file ~OpenFile() { Close(file); } // close the file int ReadAt(char *into, int numBytes, int position) { Lseek(file, position, 0); return ReadPartial(file, into, numBytes); } int WriteAt(char *from, int numBytes, int position) { Lseek(file, position, 0); WriteFile(file, from, numBytes); return numBytes; } int Read(char *into, int numBytes) { int numRead = ReadAt(into, numBytes, currentOffset); currentOffset += numRead; return numRead; } int Write(char *from, int numBytes) { int numWritten = WriteAt(from, numBytes, currentOffset); currentOffset += numWritten; return numWritten; } int Length() { Lseek(file, 0, 2); return Tell(file); } private: int file; int currentOffset; }; #else // FILESYS class FileHeader; class OpenFile { public: OpenFile(int sector); // Open a file whose header is located // at "sector" on the disk ~OpenFile(); // Close the file void Seek(int position); // Set the position from which to // start reading/writing -- UNIX lseek int Read(char *into, int numBytes); // Read/write bytes from the file, // starting at the implicit position. // Return the # actually read/written, // and increment position in file. int Write(char *from, int numBytes); int ReadAt(char *into, int numBytes, int position); // Read/write bytes from the file, // bypassing the implicit position. int WriteAt(char *from, int numBytes, int position); int Length(); // Return the number of bytes in the // file (this interface is simpler // than the UNIX idiom -- lseek to // end of file, tell, lseek back private: FileHeader *hdr; // Header for this file int seekPosition; // Current position within the file }; #endif // FILESYS #endif // OPENFILE_H

project4/nachos/code/filesys/synchdisk.h

// synchdisk.h // Data structures to export a synchronous interface to the raw // disk device. // // Copyright (c) 1992-1993 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #include "copyright.h" #ifndef SYNCHDISK_H #define SYNCHDISK_H #include "disk.h" #include "synch.h" #include "callback.h" // The following class defines a "synchronous" disk abstraction. // As with other I/O devices, the raw physical disk is an asynchronous device -- // requests to read or write portions of the disk return immediately, // and an interrupt occurs later to signal that the operation completed. // (Also, the physical characteristics of the disk device assume that // only one operation can be requested at a time). // // This class provides the abstraction that for any individual thread // making a request, it waits around until the operation finishes before // returning. class SynchDisk : public CallBackObj { public: SynchDisk(); // Initialize a synchronous disk, // by initializing the raw Disk. ~SynchDisk(); // De-allocate the synch disk data void ReadSector(int sectorNumber, char* data); // Read/write a disk sector, returning // only once the data is actually read // or written. These call // Disk::ReadRequest/WriteRequest and // then wait until the request is done. void WriteSector(int sectorNumber, char* data); void CallBack(); // Called by the disk device interrupt // handler, to signal that the // current disk operation is complete. private: Disk *disk; // Raw disk device Semaphore *semaphore; // To synchronize requesting thread // with the interrupt handler Lock *lock; // Only one read/write request // can be sent to the disk at a time }; #endif // SYNCHDISK_H

project4/nachos/code/filesys/filesys.cc

project4/nachos/code/filesys/filesys.cc

// filesys.cc 
//  Routines to manage the overall operation of the file system.
//  Implements routines to map from textual file names to files.
//
//  Each file in the file system has:
//     A file header, stored in a sector on disk 
//      (the size of the file header data structure is arranged
//      to be precisely the size of 1 disk sector)
//     A number of data blocks
//     An entry in the file system directory
//
//  The file system consists of several data structures:
//     A bitmap of free disk sectors (cf. bitmap.h)
//     A directory of file names and file headers
//
//      Both the bitmap and the directory are represented as normal
//  files.  Their file headers are located in specific sectors
//  (sector 0 and sector 1), so that the file system can find them 
//  on bootup.
//
//  The file system assumes that the bitmap and directory files are
//  kept "open" continuously while Nachos is running.
//
//  For those operations (such as Create, Remove) that modify the
//  directory and/or bitmap, if the operation succeeds, the changes
//  are written immediately back to disk (the two files are kept
//  open during all this time).  If the operation fails, and we have
//  modified part of the directory and/or bitmap, we simply discard
//  the changed version, without writing it back to disk.
//
//  Our implementation at this point has the following restrictions:
//
//     there is no synchronization for concurrent accesses
//     files have a fixed size, set when the file is created
//     files cannot be bigger than about 3KB in size
//     there is no hierarchical directory structure, and only a limited
//       number of files can be added to the system
//     there is no attempt to make the system robust to failures
//      (if Nachos exits in the middle of an operation that modifies
//      the file system, it may corrupt the disk)
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.
#ifndef  FILESYS_STUB

#include   "copyright.h"
#include   "debug.h"
#include   "disk.h"
#include   "pbitmap.h"
#include   "directory.h"
#include   "filehdr.h"
#include   "filesys.h"

// Sectors containing the file headers for the bitmap of free sectors,
// and the directory of files.  These file headers are placed in well-known 
// sectors, so that they can be located on boot-up.
#define   FreeMapSector         0
#define   DirectorySector       1

// Initial file sizes for the bitmap and directory; until the file system
// supports extensible files, the directory size sets the maximum number 
// of files that can be loaded onto the disk.
#define   FreeMapFileSize       ( NumSectors   /   BitsInByte )
#define   NumDirEntries         10
#define   DirectoryFileSize     ( sizeof ( DirectoryEntry )   *   NumDirEntries )

//----------------------------------------------------------------------
// FileSystem::FileSystem
//  Initialize the file system.  If format = TRUE, the disk has
//  nothing on it, and we need to initialize the disk to contain
//  an empty directory, and a bitmap of free sectors (with almost but
//  not all of the sectors marked as free).  
//
//  If format = FALSE, we just have to open the files
//  representing the bitmap and the directory.
//
//  "format" -- should we initialize the disk?
//----------------------------------------------------------------------

FileSystem :: FileSystem ( bool  format )
{  
    DEBUG ( dbgFile ,   "Initializing the file system." );
     if   ( format )   {
         PersistentBitmap   * freeMap  =   new   PersistentBitmap ( NumSectors );
         Directory   * directory  =   new   Directory ( NumDirEntries );
     FileHeader   * mapHdr  =   new   FileHeader ;
     FileHeader   * dirHdr  =   new   FileHeader ;

        DEBUG ( dbgFile ,   "Formatting the file system." );

     // First, allocate space for FileHeaders for the directory and bitmap
     // (make sure no one else grabs these!)
    freeMap -> Mark ( FreeMapSector );        
    freeMap -> Mark ( DirectorySector );

     // Second, allocate space for the data blocks containing the contents
     // of the directory and bitmap files.  There better be enough space!

    ASSERT ( mapHdr -> Allocate ( freeMap ,   FreeMapFileSize ));
    ASSERT ( dirHdr -> Allocate ( freeMap ,   DirectoryFileSize ));

     // Flush the bitmap and directory FileHeaders back to disk
     // We need to do this before we can "Open" the file, since open
     // reads the file header off of disk (and currently the disk has garbage
     // on it!).

        DEBUG ( dbgFile ,   "Writing headers back to disk." );
    mapHdr -> WriteBack ( FreeMapSector );     
    dirHdr -> WriteBack ( DirectorySector );

     // OK to open the bitmap and directory files now
     // The file system operations assume these two files are left open
     // while Nachos is running.

        freeMapFile  =   new   OpenFile ( FreeMapSector );
        directoryFile  =   new   OpenFile ( DirectorySector );
     
     // Once we have the files "open", we can write the initial version
     // of each file back to disk.  The directory at this point is completely
     // empty; but the bitmap has been changed to reflect the fact that
     // sectors on the disk have been allocated for the file headers and
     // to hold the file data for the directory and bitmap.

        DEBUG ( dbgFile ,   "Writing bitmap and directory back to disk." );
    freeMap -> WriteBack ( freeMapFile );       // flush changes to disk
    directory -> WriteBack ( directoryFile );

     if   ( debug -> IsEnabled ( 'f' ))   {
        freeMap -> Print ();
        directory -> Print ();
         }
         delete  freeMap ;  
     delete  directory ;  
     delete  mapHdr ;  
     delete  dirHdr ;
     }   else   {
     // if we are not formatting the disk, just open the files representing
     // the bitmap and directory; these are left open while Nachos is running
        freeMapFile  =   new   OpenFile ( FreeMapSector );
        directoryFile  =   new   OpenFile ( DirectorySector );
     }
}

//----------------------------------------------------------------------
// FileSystem::Create
//  Create a file in the Nachos file system (similar to UNIX create).
//  Since we can't increase the size of files dynamically, we have
//  to give Create the initial size of the file.
//
//  The steps to create a file are:
//    Make sure the file doesn't already exist
//        Allocate a sector for the file header
//    Allocate space on disk for the data blocks for the file
//    Add the name to the directory
//    Store the new file header on disk 
//    Flush the changes to the bitmap and the directory back to disk
//
//  Return TRUE if everything goes ok, otherwise, return FALSE.
//
//  Create fails if:
//          file is already in directory
//      no free space for file header
//      no free entry for file in directory
//      no free space for data blocks for the file 
//
//  Note that this implementation assumes there is no concurrent access
//  to the file system!
//
//  "name" -- name of file to be created
//  "initialSize" -- size of file to be created
//----------------------------------------------------------------------

bool
FileSystem :: Create ( char   * name ,   int  initialSize )
{
     Directory   * directory ;
     PersistentBitmap   * freeMap ;
     FileHeader   * hdr ;
     int  sector ;
     bool  success ;

    DEBUG ( dbgFile ,   "Creating file "   <<  name  <<   " size "   <<  initialSize );

    directory  =   new   Directory ( NumDirEntries );
    directory -> FetchFrom ( directoryFile );

     if   ( directory -> Find ( name )   !=   - 1 )
      success  =  FALSE ;            // file is already in directory
     else   {   
        freeMap  =   new   PersistentBitmap ( freeMapFile , NumSectors );
        sector  =  freeMap -> FindAndSet ();   // find a sector to hold the file header
         if   ( sector  ==   - 1 )        
            success  =  FALSE ;          // no free block for file header 
         else   if   ( ! directory -> Add ( name ,  sector ))
            success  =  FALSE ;      // no space in directory
     else   {
            hdr  =   new   FileHeader ;
         if   ( ! hdr -> Allocate ( freeMap ,  initialSize ))
                success  =  FALSE ;      // no space on disk for data
         else   {   
            success  =  TRUE ;
         // everthing worked, flush all changes back to disk
                hdr -> WriteBack ( sector );          
                directory -> WriteBack ( directoryFile );
                freeMap -> WriteBack ( freeMapFile );
         }
             delete  hdr ;
     }
         delete  freeMap ;
     }
     delete  directory ;
     return  success ;
}

//----------------------------------------------------------------------
// FileSystem::Open
//  Open a file for reading and writing.  
//  To open a file:
//    Find the location of the file's header, using the directory 
//    Bring the header into memory
//
//  "name" -- the text name of the file to be opened
//----------------------------------------------------------------------

OpenFile   *
FileSystem :: Open ( char   * name )
{  
     Directory   * directory  =   new   Directory ( NumDirEntries );
     OpenFile   * openFile  =  NULL ;
     int  sector ;

    DEBUG ( dbgFile ,   "Opening file"   <<  name );
    directory -> FetchFrom ( directoryFile );
    sector  =  directory -> Find ( name );  
     if   ( sector  >=   0 )         
    openFile  =   new   OpenFile ( sector );      // name was found in directory 
     delete  directory ;
     return  openFile ;                  // return NULL if not found
}

//----------------------------------------------------------------------
// FileSystem::Remove
//  Delete a file from the file system.  This requires:
//      Remove it from the directory
//      Delete the space for its header
//      Delete the space for its data blocks
//      Write changes to directory, bitmap back to disk
//
//  Return TRUE if the file was deleted, FALSE if the file wasn't
//  in the file system.
//
//  "name" -- the text name of the file to be removed
//----------------------------------------------------------------------

bool
FileSystem :: Remove ( char   * name )
{  
     Directory   * directory ;
     PersistentBitmap   * freeMap ;
     FileHeader   * fileHdr ;
     int  sector ;
    
    directory  =   new   Directory ( NumDirEntries );
    directory -> FetchFrom ( directoryFile );
    sector  =  directory -> Find ( name );
     if   ( sector  ==   - 1 )   {
        delete  directory ;
        return  FALSE ;               // file not found 
     }
    fileHdr  =   new   FileHeader ;
    fileHdr -> FetchFrom ( sector );

    freeMap  =   new   PersistentBitmap ( freeMapFile , NumSectors );

    fileHdr -> Deallocate ( freeMap );         // remove data blocks
    freeMap -> Clear ( sector );           // remove header block
    directory -> Remove ( name );

    freeMap -> WriteBack ( freeMapFile );          // flush to disk
    directory -> WriteBack ( directoryFile );          // flush to disk
     delete  fileHdr ;
     delete  directory ;
     delete  freeMap ;
     return  TRUE ;
}  

//----------------------------------------------------------------------
// FileSystem::List
//  List all the files in the file system directory.
//----------------------------------------------------------------------

void
FileSystem :: List ()
{
     Directory   * directory  =   new   Directory ( NumDirEntries );

    directory -> FetchFrom ( directoryFile );
    directory -> List ();
     delete  directory ;
}

//----------------------------------------------------------------------
// FileSystem::Print
//  Print everything about the file system:
//    the contents of the bitmap
//    the contents of the directory
//    for each file in the directory,
//        the contents of the file header
//        the data in the file
//----------------------------------------------------------------------

void
FileSystem :: Print ()
{
     FileHeader   * bitHdr  =   new   FileHeader ;
     FileHeader   * dirHdr  =   new   FileHeader ;
     PersistentBitmap   * freeMap  =   new   PersistentBitmap ( freeMapFile , NumSectors );
     Directory   * directory  =   new   Directory ( NumDirEntries );

    printf ( "Bit map file header:\n" );
    bitHdr -> FetchFrom ( FreeMapSector );
    bitHdr -> Print ();

    printf ( "Directory file header:\n" );
    dirHdr -> FetchFrom ( DirectorySector );
    dirHdr -> Print ();

    freeMap -> Print ();

    directory -> FetchFrom ( directoryFile );
    directory -> Print ();

     delete  bitHdr ;
     delete  dirHdr ;
     delete  freeMap ;
     delete  directory ;
}  

#endif   // FILESYS_STUB

project4/nachos/code/filesys/filehdr.cc

project4/nachos/code/filesys/filehdr.cc

// filehdr.cc 
//  Routines for managing the disk file header (in UNIX, this
//  would be called the i-node).
//
//  The file header is used to locate where on disk the 
//  file's data is stored.  We implement this as a fixed size
//  table of pointers -- each entry in the table points to the 
//  disk sector containing that portion of the file data
//  (in other words, there are no indirect or doubly indirect 
//  blocks). The table size is chosen so that the file header
//  will be just big enough to fit in one disk sector, 
//
//      Unlike in a real system, we do not keep track of file permissions, 
//  ownership, last modification date, etc., in the file header. 
//
//  A file header can be initialized in two ways:
//     for a new file, by modifying the in-memory data structure
//       to point to the newly allocated data blocks
//     for a file already on disk, by reading the file header from disk
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include   "copyright.h"

#include   "filehdr.h"
#include   "debug.h"
#include   "synchdisk.h"
#include   "main.h"

//----------------------------------------------------------------------
// FileHeader::Allocate
//  Initialize a fresh file header for a newly created file.
//  Allocate data blocks for the file out of the map of free disk blocks.
//  Return FALSE if there are not enough free blocks to accomodate
//  the new file.
//
//  "freeMap" is the bit map of free disk sectors
//  "fileSize" is the bit map of free disk sectors
//----------------------------------------------------------------------

bool
FileHeader :: Allocate ( PersistentBitmap   * freeMap ,   int  fileSize )
{  
    numBytes  =  fileSize ;
    numSectors   =  divRoundUp ( fileSize ,   SectorSize );
     if   ( freeMap -> NumClear ()   <  numSectors )
     return  FALSE ;         // not enough space

     for   ( int  i  =   0 ;  i  <  numSectors ;  i ++ )   {
    dataSectors [ i ]   =  freeMap -> FindAndSet ();
     // since we checked that there was enough free space,
     // we expect this to succeed
    ASSERT ( dataSectors [ i ]   >=   0 );
     }
     return  TRUE ;
}

//----------------------------------------------------------------------
// FileHeader::Deallocate
//  De-allocate all the space allocated for data blocks for this file.
//
//  "freeMap" is the bit map of free disk sectors
//----------------------------------------------------------------------

void  
FileHeader :: Deallocate ( PersistentBitmap   * freeMap )
{
     for   ( int  i  =   0 ;  i  <  numSectors ;  i ++ )   {
    ASSERT ( freeMap -> Test (( int )  dataSectors [ i ]));    // ought to be marked!
    freeMap -> Clear (( int )  dataSectors [ i ]);
     }
}

//----------------------------------------------------------------------
// FileHeader::FetchFrom
//  Fetch contents of file header from disk. 
//
//  "sector" is the disk sector containing the file header
//----------------------------------------------------------------------

void
FileHeader :: FetchFrom ( int  sector )
{
    kernel -> synchDisk -> ReadSector ( sector ,   ( char   * ) this );
}

//----------------------------------------------------------------------
// FileHeader::WriteBack
//  Write the modified contents of the file header back to disk. 
//
//  "sector" is the disk sector to contain the file header
//----------------------------------------------------------------------

void
FileHeader :: WriteBack ( int  sector )
{
    kernel -> synchDisk -> WriteSector ( sector ,   ( char   * ) this );  
}

//----------------------------------------------------------------------
// FileHeader::ByteToSector
//  Return which disk sector is storing a particular byte within the file.
//      This is essentially a translation from a virtual address (the
//  offset in the file) to a physical address (the sector where the
//  data at the offset is stored).
//
//  "offset" is the location within the file of the byte in question
//----------------------------------------------------------------------

int
FileHeader :: ByteToSector ( int  offset )
{
     return ( dataSectors [ offset  /   SectorSize ]);
}

//----------------------------------------------------------------------
// FileHeader::FileLength
//  Return the number of bytes in the file.
//----------------------------------------------------------------------

int
FileHeader :: FileLength ()
{
     return  numBytes ;
}

//----------------------------------------------------------------------
// FileHeader::Print
//  Print the contents of the file header, and the contents of all
//  the data blocks pointed to by the file header.
//----------------------------------------------------------------------

void
FileHeader :: Print ()
{
     int  i ,  j ,  k ;
     char   * data  =   new   char [ SectorSize ];

    printf ( "FileHeader contents.  File size: %d.  File blocks:\n" ,  numBytes );
     for   ( =   0 ;  i  <  numSectors ;  i ++ )
    printf ( "%d " ,  dataSectors [ i ]);
    printf ( "\nFile contents:\n" );
     for   ( =  k  =   0 ;  i  <  numSectors ;  i ++ )   {
    kernel -> synchDisk -> ReadSector ( dataSectors [ i ],  data );
         for   ( =   0 ;   ( <   SectorSize )   &&   ( <  numBytes );  j ++ ,  k ++ )   {
         if   ( '\040'   <=  data [ j ]   &&  data [ j ]   <=   '\176' )     // isprint(data[j])
        printf ( "%c" ,  data [ j ]);
             else
        printf ( "\\%x" ,   ( unsigned   char ) data [ j ]);
     }
        printf ( "\n" );  
     }
     delete   []  data ;
}

project4/nachos/code/filesys/pbitmap.h

// pbitmap.h // Data structures defining a "persistent" bitmap -- a bitmap // that can be stored and fetched off of disk // // A persistent bitmap can either be initialized from the disk // when it is created, or it can be initialized later using // the FetchFrom method // // Copyright (c) 1992,1993,1995 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef PBITMAP_H #define PBITMAP_H #include "copyright.h" #include "bitmap.h" #include "openfile.h" // The following class defines a persistent bitmap. It inherits all // the behavior of a bitmap (see bitmap.h), adding the ability to // be read from and stored to the disk. class PersistentBitmap : public Bitmap { public: PersistentBitmap(OpenFile *file,int numItems); //initialize bitmap from disk PersistentBitmap(int numItems); // or don't... ~PersistentBitmap(); // deallocate bitmap void FetchFrom(OpenFile *file); // read bitmap from the disk void WriteBack(OpenFile *file); // write bitmap contents to disk }; #endif // PBITMAP_H

project4/nachos/code/README

Building Instructions: * got to the directory build.<host>, where <host> is your working OS * do a "make depend" to build depenencies (DO IT!) * do a "make" to build NachOS Usage: see "nachos -u" for all command line options Building and starting user-level programs in NachOS: * use Mips cross-compiler to build and link coff-binaries * use coff2noff to translate the binaries to the NachOS-format * start binary with nachos -x <path_to_file/file>

project4/nachos/code/build.macosx/Makefile.dep

################################################################## # Machine Dependencies - this file is included automatically # into the main Makefile # ################################################################## HOSTCFLAGS = -DHOST_IS_BIG_ENDIAN -DPowerPC -DBSD -DAIX -DApplePowerPC CPP_AS_FLAGS = -D_ASM CPP = cpp #----------------------------------------------------------------- # Do not put anything below this point - it will be destroyed by # "make depend" # # DO NOT DELETE THIS LINE -- make depend uses it # DEPENDENCIES MUST END AT END OF FILE # IF YOU PUT STUFF HERE IT WILL GO AWAY # see make depend above

project4/nachos/code/build.macosx/Makefile

# Copyright (c) 1992-1996 The Regents of the University of California. # All rights reserved. See copyright.h for copyright notice and limitation # of liability and disclaimer of warranty provisions. # # This is a GNU Makefile. It must be used with the GNU make program. # At UW, the GNU make program is /software/gnu/bin/make. # In many other places it is known as "gmake". # You may wish to include /software/gnu/bin/ early in your command # search path, so that you will be using GNU make when you type "make". # # About this Makefile: # -------------------- # # This Makefile is used to build the Nachos system, which includes # the MIPS machine simulation and a simple operating system. # # There is a separate Makefile, in the "test" directory, that is # used to build the Nachos test programs (which run on the # simulated machine). # # There are several "build" directories, one for each type # of machine in the MFCF computing environment # (build.solaris, build.sunos, and build.ultrix), as well # as a build directory for Linux (build.linux) and a generic # build directory (build.other) for those who wish to try # building Nachos on other platforms. # # This Makefile appears to be located in all of the build directories. # If you edit it in one directory, the copies in all of the other # directories appear to change as well. This is the desired behaviour, # since this file is machine independent. (The file actually lives # in build.solaris, with symbolic links from the other build directories.) # # The platform-dependent parts of make's instructions are located # in the file Makefile.dep. # There is a different Makefile.dep in each build directory. # # If you are in the MFCF environment, you should not have to edit # the Makefile.dep files by hand. Any changes to the make instructions # can be made in this file (see the instructions below) - they will # apply no matter where you build Nachos. # If you are not in the MFCF environment, e.g., if you are trying # to build Nachos on Linux at home, you will probably need # to edit Makefile.dep (in the appropriate build directory) to # customize the make procedure to your environment. # # How to build Nachos for the first time: # --------------------------------------- # # (1) Make sure than you are in the build directory for the # type of machine you are logged in to (the "host" machine): # # host type examples build directory # ----------- ----------- ---------------- # # sparc/SunOS cayley,napier, build.sunos # (SunOS 4.1.3) descartes # # sparc/Solaris picard.math, build.solaris # (SunOS 5.x) hermite.math, # markov.math, # hypatia.math, # hume.math # # mips/ULTRIX cantor.math build.ultrix # (ULTRIX 4.2) noether.math # # If you are not sure what type of machine you are on, # try the command "uname -a". # # (2) Type "make depend" # - this computes file dependencies and records them # at the end of the file Makefile.dep in # your build directory. Have a look... # # (3) Type "make nachos" (or just "make"). # - make echos the commands it is executing, so that # you can observe its progress. When the # build is finished, you should have an # executable "nachos" in the build directory. # # (4) There is no 4th step. You are done. Try running "./nachos -u". # # # How to Re-build Nachos after you have changed the code: #-------------------------------------------------------- # # - The Nachos source code is located in the code subdirectories: # threads, userprog, filesys, network, and lib. You may # change the files in any of these directories, and you can # add new files and/or remove files. The "machine" subdirectory # contains the hardware simulation (which is also part of # Nachos. You may look at it, but # you may not change it, except as noted in machine/machine.h # - When you want to re-make Nachos, always do it in the # "build" directory that is appropriate for the machine # type that you are running on. # DO NOT TRY TO MAKE NACHOS IN THE SOURCE CODE DIRECTORIES. # # - IF all you have done is changed C++ code in existing files # (since the last time you made Nachos in this build directory), # THEN all you need to do to re-make Nachos is to type # # "make nachos" # # in the build directory. # # - IF you have done any of the following since the last build in # this directory: # added new .cc files or new .h files # added or deleted #include's from existing files # THEN # you must do # "make depend" # followed by # "make nachos" # # in the build directory. # # Note that is is always safe to do "make depend" followed by # "make nachos", so if you are not sure what changes you have # made, do "make depend". # # - IF you have added new files (.cc or .h) since the last build, # you should edit this Makefile before running "make depend" # and "make nachos". # For new .h files, simply update the appropriate "_H" list below. # For example, if you create a file called # "bigfile.h" in the filesys subdirectory, you should add # "../filesys/bigfile.h" to FILESYS_H, which is defined below # For new .cc files, update the appropriate "_C" and "_O" lists. # For example, if you create a file called "filetable.cc" in # the directory "userprog", you should add # "../userprog/filetable.cc" to USERPROG_C, # and you should add "filetable.o" to USERPROG_O. # Note that the entry in the "_C" list includes the subdirectory # name, while the entry on the "_O" list does not. # # Some Important Notes: # --------------------- # # * You can clean up all of the .o and other files left behind # by make by typeing "make clean" in the build directory. # * You can clean up .o and other files, as well as the nachos # executable, DISK, core, SOCKET, and other files by typing # make "distclean" # # These are good ways to save space, but the next build that # you do after cleaning will take longer than usual, since # much of the stuff you cleaned will need to be rebuilt. # # * When you build Nachos on an ULTRIX machine (in build.ultrix), # you will get lots of warning messages like this: # # openfile.o: does not have gp tables for all it's sectons # # from the loader. Ignore them. Or better yet, figure out # how to make them go away. # # The Most Important Note: # ----------------------- # # * If "make" is behaving strangely and you cannot figure out # why, you should REBUILD the program FROM SCRATCH. # Yes, it is slow. # But, there are lots of little things that can go wrong, especially # with all of these different types of machines available. # Rebuilding from scratch at least gives you a known starting # place. To rebuild from scratch, go to the appropriate # build directory and do: # # make distclean # make depend # make nachos # ################################################################ # READ THIS: CONFIGURING NACHOS # # Change DEFINES (below) to # DEFINES = -DUSE_TLB -DFILESYS_STUB # if you want the simulated machine to use its TLB # # If you want to use the real Nachos file system (based on # the simulated disk), rather than the stub, remove # the -DFILESYS_STUB from DEFINES. # # There is a a fix to the MIPS simulator to enable it to properly # handle unaligned data access. This fix is enabled by the addition # of "-DSIM_FIX" to the DEFINES. This should be enabled by default # and eventually will not require the symbol definition ################################################################ DEFINES = -DFILESYS_STUB -DRDATA -DSIM_FIX ##################################################################### # # You might want to play with the CFLAGS, but if you use -O it may # break the thread system. You might want to use -fno-inline if # you need to call some inline functions from the debugger. CFLAGS = -g -Wall -fwritable-strings $(INCPATH) $(DEFINES) $(HOSTCFLAGS) -DCHANGED LDFLAGS = ##################################################################### CPP=/lib/cpp CC = g++ LD = g++ AS = as RM = /bin/rm INCPATH = -I../network -I../filesys -I../userprog -I../threads -I../machine -I../lib PROGRAM = nachos # # Edit these lists as if you add files to the source directories. # See the instructions at the top of the file for more information. # LIB_H = ../lib/bitmap.h\ ../lib/copyright.h\ ../lib/debug.h\ ../lib/hash.h\ ../lib/libtest.h\ ../lib/list.h\ ../lib/sysdep.h\ ../lib/utility.h LIB_C = ../lib/bitmap.cc\ ../lib/debug.cc\ ../lib/hash.cc\ ../lib/libtest.cc\ ../lib/list.cc\ ../lib/sysdep.cc LIB_O = bitmap.o debug.o libtest.o sysdep.o MACHINE_H = ../machine/callback.h\ ../machine/interrupt.h\ ../machine/stats.h\ ../machine/timer.h\ ../machine/console.h\ ../machine/machine.h\ ../machine/mipssim.h\ ../machine/translate.h\ ../machine/network.h\ ../machine/disk.h MACHINE_C = ../machine/interrupt.cc\ ../machine/stats.cc\ ../machine/timer.cc\ ../machine/console.cc\ ../machine/machine.cc\ ../machine/mipssim.cc\ ../machine/translate.cc\ ../machine/network.cc\ ../machine/disk.cc MACHINE_O = interrupt.o stats.o timer.o console.o machine.o mipssim.o\ translate.o network.o disk.o THREAD_H = ../threads/alarm.h\ ../threads/kernel.h\ ../threads/main.h\ ../threads/scheduler.h\ ../threads/switch.h\ ../threads/synch.h\ ../threads/synchlist.h\ ../threads/thread.h THREAD_C = ../threads/alarm.cc\ ../threads/kernel.cc\ ../threads/main.cc\ ../threads/scheduler.cc\ ../threads/synch.cc\ ../threads/synchlist.cc\ ../threads/thread.cc THREAD_O = alarm.o kernel.o main.o scheduler.o synch.o thread.o USERPROG_H = ../userprog/addrspace.h\ ../userprog/syscall.h\ ../userprog/synchconsole.h\ ../userprog/noff.h USERPROG_C = ../userprog/addrspace.cc\ ../userprog/exception.cc\ ../userprog/synchconsole.cc USERPROG_O = addrspace.o exception.o synchconsole.o FILESYS_H =../filesys/directory.h \ ../filesys/filehdr.h\ ../filesys/filesys.h \ ../filesys/openfile.h\ ../filesys/pbitmap.h\ ../filesys/synchdisk.h FILESYS_C =../filesys/directory.cc\ ../filesys/filehdr.cc\ ../filesys/filesys.cc\ ../filesys/pbitmap.cc\ ../filesys/openfile.cc\ ../filesys/synchdisk.cc\ FILESYS_O =directory.o filehdr.o filesys.o pbitmap.o openfile.o synchdisk.o NETWORK_H = ../network/post.h NETWORK_C = ../network/post.cc NETWORK_O = post.o ################################################################## # You probably don't want to change anything below this point in # the file unless you are comfortable with GNU make and know what # you are doing... ################################################################## THREAD_S = ../threads/switch.s HFILES = $(LIB_H) $(MACHINE_H) $(THREAD_H) $(USERPROG_H) $(FILESYS_H) $(NETWORK_H) CFILES = $(LIB_C) $(MACHINE_C) $(THREAD_C) $(USERPROG_C) $(FILESYS_C) $(NETWORK_C) C_OFILES = $(LIB_O) $(MACHINE_O) $(THREAD_O) $(USERPROG_O) $(FILESYS_O) $(NETWORK_O) S_OFILES = switch.o OFILES = $(C_OFILES) $(S_OFILES) $(PROGRAM): $(OFILES) $(LD) $(OFILES) $(LDFLAGS) -o $(PROGRAM) $(C_OFILES): %.o: $(CC) $(CFLAGS) -c $< switch.o: ../threads/switch.s $(CPP) $(CPP_AS_FLAGS) -P $(INCPATH) $(HOSTCFLAGS) ../threads/switch.s > swtch.s $(AS) -o switch.o swtch.s depend: $(CFILES) $(HFILES) $(CC) $(INCPATH) $(DEFINES) $(HOSTCFLAGS) -DCHANGED -M $(CFILES) > makedep @echo '/^# DO NOT DELETE THIS LINE/+2,$$d' >eddep @echo '$$r makedep' >>eddep @echo 'w' >>eddep @echo 'q' >>eddep ed - Makefile.dep < eddep rm eddep makedep @echo '# DEPENDENCIES MUST END AT END OF FILE' >> Makefile.dep @echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >> Makefile.dep @echo '# see make depend above' >> Makefile.dep clean: $(RM) -f $(OFILES) $(RM) -f swtch.s distclean: clean $(RM) -f $(PROGRAM) $(RM) -f DISK_? $(RM) -f core $(RM) -f SOCKET_? include Makefile.dep

project4/nachos/code/threads/main.cc

project4/nachos/code/threads/main.cc

// main.cc 
//  Driver code to initialize, selftest, and run the 
//  operating system kernel.  
//
// Usage: nachos -d <debugflags> -rs <random seed #>
//              -s -x <nachos file> -ci <consoleIn> -co <consoleOut>
//              -f -cp <unix file> <nachos file>
//              -p <nachos file> -r <nachos file> -l -D
//              -n <network reliability> -m <machine id>
//              -z -K -C -N
//
//    -d causes certain debugging messages to be printed (see debug.h)
//    -rs causes Yield to occur at random (but repeatable) spots
//    -z prints the copyright message
//    -s causes user programs to be executed in single-step mode
//    -x runs a user program
//    -ci specify file for console input (stdin is the default)
//    -co specify file for console output (stdout is the default)
//    -n sets the network reliability
//    -m sets this machine's host id (needed for the network)
//    -K run a simple self test of kernel threads and synchronization
//    -C run an interactive console test
//    -N run a two-machine network test (see Kernel::NetworkTest)
//
//    Filesystem-related flags:
//    -f forces the Nachos disk to be formatted
//    -cp copies a file from UNIX to Nachos
//    -p prints a Nachos file to stdout
//    -r removes a Nachos file from the file system
//    -l lists the contents of the Nachos directory
//    -D prints the contents of the entire file system 
//
//  Note: the file system flags are not used if the stub filesystem
//        is being used
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#define  MAIN
#include   "copyright.h"
#undef  MAIN

#include   "main.h"
#include   "filesys.h"
#include   "openfile.h"
#include   "sysdep.h"

// global variables
Kernel   * kernel ;
Debug   * debug ;

extern   void   ThreadTest ( void );

//----------------------------------------------------------------------
// Cleanup
//  Delete kernel data structures; called when user hits "ctl-C".
//----------------------------------------------------------------------

static   void  
Cleanup ( int  x )  
{      
    cerr  <<   "\nCleaning up after signal "   <<  x  <<   "\n" ;
     delete  kernel ;  
}

//-------------------------------------------------------------------
// Constant used by "Copy" and "Print"
//   It is the number of bytes read from the Unix file (for Copy)
//   or the Nachos file (for Print) by each read operation
//-------------------------------------------------------------------
static   const   int   TransferSize   =   128 ;


#ifndef  FILESYS_STUB
//----------------------------------------------------------------------
// Copy
//      Copy the contents of the UNIX file "from" to the Nachos file "to"
//----------------------------------------------------------------------

static   void
Copy ( char   * from ,   char   * to )
{
     int  fd ;
     OpenFile *  openFile ;
     int  amountRead ,  fileLength ;
     char   * buffer ;

// Open UNIX file
     if   (( fd  =   OpenForReadWrite ( from , FALSE ))   <   0 )   {        
        printf ( "Copy: couldn't open input file %s\n" ,  from );
         return ;
     }

// Figure out length of UNIX file
     Lseek ( fd ,   0 ,   2 );             
    fileLength  =   Tell ( fd );
     Lseek ( fd ,   0 ,   0 );

// Create a Nachos file of the same length
    DEBUG ( 'f' ,   "Copying file "   <<  from  <<   " of size "   <<  fileLength  <<    " to file "   <<  to );
     if   ( ! kernel -> fileSystem -> Create ( to ,  fileLength ))   {     // Create Nachos file
        printf ( "Copy: couldn't create output file %s\n" ,  to );
         Close ( fd );
         return ;
     }
    
    openFile  =  kernel -> fileSystem -> Open ( to );
    ASSERT ( openFile  !=  NULL );
    
// Copy the data in TransferSize chunks
    buffer  =   new   char [ TransferSize ];
     while   (( amountRead = ReadPartial ( fd ,  buffer ,   sizeof ( char ) * TransferSize ))   >   0 )
        openFile -> Write ( buffer ,  amountRead );     
     delete   []  buffer ;

// Close the UNIX and the Nachos files
     delete  openFile ;
     Close ( fd );
}

#endif   // FILESYS_STUB

//----------------------------------------------------------------------
// Print
//      Print the contents of the Nachos file "name".
//----------------------------------------------------------------------

void
Print ( char   * name )
{
     OpenFile   * openFile ;     
     int  i ,  amountRead ;
     char   * buffer ;

     if   (( openFile  =  kernel -> fileSystem -> Open ( name ))   ==  NULL )   {
        printf ( "Print: unable to open file %s\n" ,  name );
         return ;
     }
    
    buffer  =   new   char [ TransferSize ];
     while   (( amountRead  =  openFile -> Read ( buffer ,   TransferSize ))   >   0 )
         for   ( =   0 ;  i  <  amountRead ;  i ++ )
            printf ( "%c" ,  buffer [ i ]);
     delete   []  buffer ;

     delete  openFile ;              // close the Nachos file
     return ;
}

//----------------------------------------------------------------------
// RunUserProg
//      Run the user program in the given file.
//----------------------------------------------------------------------

void
RunUserProg ( void   * filename )   {
     AddrSpace   * space  =   new   AddrSpace ;
    ASSERT ( space  !=   ( AddrSpace   * ) NULL );
     if   ( space -> Load (( char * ) filename ))   {    // load the program into the space
        space -> Execute ();           // run the program
     }
    ASSERTNOTREACHED ();
}

//----------------------------------------------------------------------
// main
//  Bootstrap the operating system kernel.  
//  
//  Initialize kernel data structures
//  Call some test routines
//  Call "Run" to start an initial user program running
//
//  "argc" is the number of command line arguments (including the name
//      of the command) -- ex: "nachos -d +" -> argc = 3 
//  "argv" is an array of strings, one for each command line argument
//      ex: "nachos -d +" -> argv = {"nachos", "-d", "+"}
//----------------------------------------------------------------------

int
main ( int  argc ,   char   ** argv )
{
     int  i ;
     char   * debugArg  =   "" ;
     char   * userProgName  =  NULL ;          // default is not to execute a user prog
     bool  threadTestFlag  =   false ;
     bool  consoleTestFlag  =   false ;
     bool  networkTestFlag  =   false ;
#ifndef  FILESYS_STUB
     char   * copyUnixFileName  =  NULL ;      // UNIX file to be copied into Nachos
     char   * copyNachosFileName  =  NULL ;    // name of copied file in Nachos
     char   * printFileName  =  NULL ;  
     char   * removeFileName  =  NULL ;
     bool  dirListFlag  =   false ;
     bool  dumpFlag  =   false ;
#endif   //FILESYS_STUB

     // some command line arguments are handled here.
     // those that set kernel parameters are handled in
     // the Kernel constructor
     for   ( =   1 ;  i  <  argc ;  i ++ )   {
         if   ( strcmp ( argv [ i ],   "-d" )   ==   0 )   {
        ASSERT ( +   1   <  argc );     // next argument is debug string
            debugArg  =  argv [ +   1 ];
        i ++ ;
     }
     else   if   ( strcmp ( argv [ i ],   "-z" )   ==   0 )   {
            cout  <<  copyright  <<   "\n" ;
     }
     else   if   ( strcmp ( argv [ i ],   "-x" )   ==   0 )   {
        ASSERT ( +   1   <  argc );
        userProgName  =  argv [ +   1 ];
        i ++ ;
     }
     else   if   ( strcmp ( argv [ i ],   "-K" )   ==   0 )   {
        threadTestFlag  =  TRUE ;
     }
     else   if   ( strcmp ( argv [ i ],   "-C" )   ==   0 )   {
        consoleTestFlag  =  TRUE ;
     }
     else   if   ( strcmp ( argv [ i ],   "-N" )   ==   0 )   {
        networkTestFlag  =  TRUE ;
     }
#ifndef  FILESYS_STUB
     else   if   ( strcmp ( argv [ i ],   "-cp" )   ==   0 )   {
        ASSERT ( +   2   <  argc );
        copyUnixFileName  =  argv [ +   1 ];
        copyNachosFileName  =  argv [ +   2 ];
        i  +=   2 ;
     }
     //else if (strcmp(argv[i],"-quantum")==0){


//}
     else   if   ( strcmp ( argv [ i ],   "-p" )   ==   0 )   {
        ASSERT ( +   1   <  argc );
        printFileName  =  argv [ +   1 ];
        i ++ ;
     }
     else   if   ( strcmp ( argv [ i ],   "-r" )   ==   0 )   {
        ASSERT ( +   1   <  argc );
        removeFileName  =  argv [ +   1 ];
        i ++ ;
     }
     else   if   ( strcmp ( argv [ i ],   "-l" )   ==   0 )   {
        dirListFlag  =   true ;
     }
     else   if   ( strcmp ( argv [ i ],   "-D" )   ==   0 )   {
        dumpFlag  =   true ;
     }
#endif   //FILESYS_STUB
     else   if   ( strcmp ( argv [ i ],   "-u" )   ==   0 )   {
            cout  <<   "Partial usage: nachos [-z -d debugFlags]\n" ;
            cout  <<   "Partial usage: nachos [-x programName]\n" ;
        cout  <<   "Partial usage: nachos [-K] [-C] [-N]\n" ;
#ifndef  FILESYS_STUB
            cout  <<   "Partial usage: nachos [-cp UnixFile NachosFile]\n" ;
            cout  <<   "Partial usage: nachos [-p fileName] [-r fileName]\n" ;
            cout  <<   "Partial usage: nachos [-l] [-D]\n" ;
#endif   //FILESYS_STUB
     }

     }
    debug  =   new   Debug ( debugArg );
    
    DEBUG ( dbgThread ,   "Entering main" );

    kernel  =   new   Kernel ( argc ,  argv );

    kernel -> Initialize ();

     CallOnUserAbort ( Cleanup );         // if user hits ctl-C

     // at this point, the kernel is ready to do something
     // run some tests, if requested
     if   ( threadTestFlag )   {
       //kernel->ThreadSelfTest();  // test threads and synchronization
       ThreadTest ();
     }
     if   ( consoleTestFlag )   {
      kernel -> ConsoleTest ();     // interactive test of the synchronized console
     }
     if   ( networkTestFlag )   {
      kernel -> NetworkTest ();     // two-machine test of the network
     }

#ifndef  FILESYS_STUB
     if   ( removeFileName  !=  NULL )   {
      kernel -> fileSystem -> Remove ( removeFileName );
     }
     if   ( copyUnixFileName  !=  NULL  &&  copyNachosFileName  !=  NULL )   {
       Copy ( copyUnixFileName , copyNachosFileName );
     }
     if   ( dumpFlag )   {
      kernel -> fileSystem -> Print ();
     }
     if   ( dirListFlag )   {
      kernel -> fileSystem -> List ();
     }
     if   ( printFileName  !=  NULL )   {
       Print ( printFileName );
     }
#endif   // FILESYS_STUB

     // finally, run an initial user program if requested to do so
     if   ( userProgName  !=  NULL )   {
       RunUserProg ( userProgName );
     }

     // NOTE: if the procedure "main" returns, then the program "nachos"
     // will exit (as any other normal program would).  But there may be
     // other threads on the ready list (started in SelfTest).  
     // We switch to those threads by saying that the "main" thread 
     // is finished, preventing it from returning.
    kernel -> currentThread -> Finish ();   
    
    ASSERTNOTREACHED ();
}

project4/nachos/code/threads/main.h

// main.h // This file defines the Nachos global variables // // Copyright (c) 1992-1996 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef MAIN_H #define MAIN_H #include "copyright.h" #include "debug.h" #include "kernel.h" extern Kernel *kernel; extern Debug *debug; #endif // MAIN_H

project4/nachos/code/threads/scheduler.cc

project4/nachos/code/threads/scheduler.cc

// scheduler.cc 
//  Routines to choose the next thread to run, and to dispatch to
//  that thread.
//
//  These routines assume that interrupts are already disabled.
//  If interrupts are disabled, we can assume mutual exclusion
//  (since we are on a uniprocessor).
//
//  NOTE: We can't use Locks to provide mutual exclusion here, since
//  if we needed to wait for a lock, and the lock was busy, we would 
//  end up calling FindNextToRun(), and that would put us in an 
//  infinite loop.
//
//  Very simple implementation -- no priorities, straight FIFO.
//  Might need to be improved in later assignments.
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include   "copyright.h"
#include   "debug.h"
#include   "scheduler.h"
#include   "main.h"

//----------------------------------------------------------------------
// Scheduler::Scheduler
//  Initialize the list of ready but not running threads.
//  Initially, no ready threads.
//----------------------------------------------------------------------

Scheduler :: Scheduler ()
{  
    readyList  =   new   List < Thread   *> ;  
    toBeDestroyed  =  NULL ;
}  

//----------------------------------------------------------------------
// Scheduler::~Scheduler
//  De-allocate the list of ready threads.
//----------------------------------------------------------------------

Scheduler ::~ Scheduler ()
{  
     delete  readyList ;  
}  

//----------------------------------------------------------------------
// Scheduler::ReadyToRun
//  Mark a thread as ready, but not running.
//  Put it on the ready list, for later scheduling onto the CPU.
//
//  "thread" is the thread to be put on the ready list.
//----------------------------------------------------------------------

void
Scheduler :: ReadyToRun   ( Thread   * thread )
{
    ASSERT ( kernel -> interrupt -> getLevel ()   ==   IntOff );
    DEBUG ( dbgThread ,   "Putting thread on ready list: "   <<   thread -> getName ());

     thread -> setStatus ( READY );
    readyList -> Append ( thread );
}

//----------------------------------------------------------------------
// Scheduler::FindNextToRun
//  Return the next thread to be scheduled onto the CPU.
//  If there are no ready threads, return NULL.
// Side effect:
//  Thread is removed from the ready list.
//----------------------------------------------------------------------

Thread   *
Scheduler :: FindNextToRun   ()
{
    ASSERT ( kernel -> interrupt -> getLevel ()   ==   IntOff );

     if   ( readyList -> IsEmpty ())   {
     return  NULL ;
     }   else   {
         return  readyList -> RemoveFront ();
     }
}

//----------------------------------------------------------------------
// Scheduler::Run
//  Dispatch the CPU to nextThread.  Save the state of the old thread,
//  and load the state of the new thread, by calling the machine
//  dependent context switch routine, SWITCH.
//
//      Note: we assume the state of the previously running thread has
//  already been changed from running to blocked or ready (depending).
// Side effect:
//  The global variable kernel->currentThread becomes nextThread.
//
//  "nextThread" is the thread to be put into the CPU.
//  "finishing" is set if the current thread is to be deleted
//      once we're no longer running on its stack
//      (when the next thread starts running)
//----------------------------------------------------------------------

void
Scheduler :: Run   ( Thread   * nextThread ,   bool  finishing )
{
     Thread   * oldThread  =  kernel -> currentThread ;
    
    ASSERT ( kernel -> interrupt -> getLevel ()   ==   IntOff );

     if   ( finishing )   {      // mark that we need to delete current thread
         ASSERT ( toBeDestroyed  ==  NULL );
     toBeDestroyed  =  oldThread ;
     }
    
     if   ( oldThread -> space  !=  NULL )   {   // if this thread is a user program,
        oldThread -> SaveUserState ();       // save the user's CPU registers
    oldThread -> space -> SaveState ();
     }
    
    oldThread -> CheckOverflow ();           // check if the old thread
                         // had an undetected stack overflow

    kernel -> currentThread  =  nextThread ;    // switch to the next thread
    nextThread -> setStatus ( RUNNING );        // nextThread is now running
    
    DEBUG ( dbgThread ,   "Switching from: "   <<  oldThread -> getName ()   <<   " to: "   <<  nextThread -> getName ());
    
     // This is a machine-dependent assembly language routine defined 
     // in switch.s.  You may have to think
     // a bit to figure out what happens after this, both from the point
     // of view of the thread and from the perspective of the "outside world".

    SWITCH ( oldThread ,  nextThread );

     // we're back, running oldThread
      
     // interrupts are off when we return from switch!
    ASSERT ( kernel -> interrupt -> getLevel ()   ==   IntOff );

    DEBUG ( dbgThread ,   "Now in thread: "   <<  oldThread -> getName ());

     CheckToBeDestroyed ();         // check if thread we were running
                     // before this one has finished
                     // and needs to be cleaned up
    
     if   ( oldThread -> space  !=  NULL )   {       // if there is an address space
        oldThread -> RestoreUserState ();       // to restore, do it.
    oldThread -> space -> RestoreState ();
     }
}

//----------------------------------------------------------------------
// Scheduler::CheckToBeDestroyed
//  If the old thread gave up the processor because it was finishing,
//  we need to delete its carcass.  Note we cannot delete the thread
//  before now (for example, in Thread::Finish()), because up to this
//  point, we were still running on the old thread's stack!
//----------------------------------------------------------------------

void
Scheduler :: CheckToBeDestroyed ()
{
     if   ( toBeDestroyed  !=  NULL )   {
         delete  toBeDestroyed ;
    toBeDestroyed  =  NULL ;
     }
}
 
//----------------------------------------------------------------------
// Scheduler::Print
//  Print the scheduler state -- in other words, the contents of
//  the ready list.  For debugging.
//----------------------------------------------------------------------
void
Scheduler :: Print ()
{
    cout  <<   "Ready list contents:\n" ;
    readyList -> Apply ( ThreadPrint );
}

project4/nachos/code/threads/alarm.h

// alarm.h // Data structures for a software alarm clock. // // We make use of a hardware timer device, that generates // an interrupt every X time ticks (on real systems, X is // usually between 0.25 - 10 milliseconds). // // From this, we provide the ability for a thread to be // woken up after a delay; we also provide time-slicing. // // NOTE: this abstraction is not completely implemented. // // Copyright (c) 1992-1996 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef ALARM_H #define ALARM_H #include "copyright.h" #include "utility.h" #include "callback.h" #include "timer.h" // The following class defines a software alarm clock. class Alarm : public CallBackObj { public: Alarm(bool doRandomYield); // Initialize the timer, and callback // to "toCall" every time slice. ~Alarm() { delete timer; } void WaitUntil(int x); // suspend execution until time > now + x // this method is not yet implemented private: Timer *timer; // the hardware timer device void CallBack(); // called when the hardware // timer generates an interrupt }; #endif // ALARM_H

project4/nachos/code/threads/synch.h

// synch.h // Data structures for synchronizing threads. // // Three kinds of synchronization are defined here: semaphores, // locks, and condition variables. The implementation for // semaphores is given; for the latter two, only the procedure // interface is given -- they are to be implemented as part of // the first assignment. // // Note that all the synchronization objects take a "name" as // part of the initialization. This is solely for debugging purposes. // // Copyright (c) 1992-1996 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // synch.h -- synchronization primitives. #ifndef SYNCH_H #define SYNCH_H #include "copyright.h" #include "thread.h" #include "list.h" #include "main.h" // The following class defines a "semaphore" whose value is a non-negative // integer. The semaphore has only two operations P() and V(): // // P() -- waits until value > 0, then decrement // // V() -- increment, waking up a thread waiting in P() if necessary // // Note that the interface does *not* allow a thread to read the value of // the semaphore directly -- even if you did read the value, the // only thing you would know is what the value used to be. You don't // know what the value is now, because by the time you get the value // into a register, a context switch might have occurred, // and some other thread might have called P or V, so the true value might // now be different. class Semaphore { public: Semaphore(char* debugName, int initialValue); // set initial value ~Semaphore(); // de-allocate semaphore char* getName() { return name;} // debugging assist void P(); // these are the only operations on a semaphore void V(); // they are both *atomic* void SelfTest(); // test routine for semaphore implementation private: char* name; // useful for debugging int value; // semaphore value, always >= 0 List<Thread *> *queue; // threads waiting in P() for the value to be > 0 }; // The following class defines a "lock". A lock can be BUSY or FREE. // There are only two operations allowed on a lock: // // Acquire -- wait until the lock is FREE, then set it to BUSY // // Release -- set lock to be FREE, waking up a thread waiting // in Acquire if necessary // // In addition, by convention, only the thread that acquired the lock // may release it. As with semaphores, you can't read the lock value // (because the value might change immediately after you read it). class Lock { public: Lock(char* debugName); // initialize lock to be FREE ~Lock(); // deallocate lock char* getName() { return name; } // debugging assist void Acquire(); // these are the only operations on a lock void Release(); // they are both *atomic* bool IsHeldByCurrentThread() { return lockHolder == kernel->currentThread; } // return true if the current thread // holds this lock. // Note: SelfTest routine provided by SynchList private: char *name; // debugging assist Thread *lockHolder; // thread currently holding lock Semaphore *semaphore; // we use a semaphore to implement lock }; // The following class defines a "condition variable". A condition // variable does not have a value, but threads may be queued, waiting // on the variable. These are only operations on a condition variable: // // Wait() -- release the lock, relinquish the CPU until signaled, // then re-acquire the lock // // Signal() -- wake up a thread, if there are any waiting on // the condition // // Broadcast() -- wake up all threads waiting on the condition // // All operations on a condition variable must be made while // the current thread has acquired a lock. Indeed, all accesses // to a given condition variable must be protected by the same lock. // In other words, mutual exclusion must be enforced among threads calling // the condition variable operations. // // In Nachos, condition variables are assumed to obey *Mesa*-style // semantics. When a Signal or Broadcast wakes up another thread, // it simply puts the thread on the ready list, and it is the responsibility // of the woken thread to re-acquire the lock (this re-acquire is // taken care of within Wait()). By contrast, some define condition // variables according to *Hoare*-style semantics -- where the signalling // thread gives up control over the lock and the CPU to the woken thread, // which runs immediately and gives back control over the lock to the // signaller when the woken thread leaves the critical section. // // The consequence of using Mesa-style semantics is that some other thread // can acquire the lock, and change data structures, before the woken // thread gets a chance to run. The advantage to Mesa-style semantics // is that it is a lot easier to implement than Hoare-style. class Condition { public: Condition(char* debugName); // initialize condition to // "no one waiting" ~Condition(); // deallocate the condition char* getName() { return (name); } void Wait(Lock *conditionLock); // these are the 3 operations on // condition variables; releasing the // lock and going to sleep are // *atomic* in Wait() void Signal(Lock *conditionLock); // conditionLock must be held by void Broadcast(Lock *conditionLock);// the currentThread for all of // these operations // SelfTest routine provided by SyncLists private: char* name; List<Semaphore *> *waitQueue; // list of waiting threads }; #endif // SYNCH_H

project4/nachos/code/threads/threadtest.cc

#include "kernel.h" #include "main.h" #include "thread.h" void SimpleThread(int which) { int num; for (num = 0; num < 5; num++) { printf("*** thread %d looped %d times\n", which, num); kernel->currentThread->Yield(); } } void ThreadTest() { Thread *t = new Thread("forked thread"); t->Fork((VoidFunctionPtr) SimpleThread, (void *) 1); SimpleThread(0); }

project4/nachos/code/threads/synchlist.cc

project4/nachos/code/threads/synchlist.cc

// synchlist.cc
//  Routines for synchronized access to a list.
//
//  Implemented in "monitor"-style -- surround each procedure with a
//  lock acquire and release pair, using condition signal and wait for
//  synchronization.
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include   "copyright.h"
#include   "synchlist.h"

//----------------------------------------------------------------------
// SynchList<T>::SynchList
//  Allocate and initialize the data structures needed for a 
//  synchronized list, empty to start with.
//  Elements can now be added to the list.
//----------------------------------------------------------------------

template   < class  T >
SynchList < T >:: SynchList ()
{
    list  =   new   List < T > ;
    lock  =   new   Lock ( "list lock" );  
    listEmpty  =   new   Condition ( "list empty cond" );
}

//----------------------------------------------------------------------
// SynchList<T>::~SynchList
//  De-allocate the data structures created for synchronizing a list. 
//----------------------------------------------------------------------

template   < class  T >
SynchList < T >::~ SynchList ()
{  
     delete  listEmpty ;
     delete  lock ;
     delete  list ;
}

//----------------------------------------------------------------------
// SynchList<T>::Append
//      Append an "item" to the end of the list.  Wake up anyone
//  waiting for an element to be appended.
//
//  "item" is the thing to put on the list. 
//----------------------------------------------------------------------

template   < class  T >
void
SynchList < T >:: Append ( T item )
{
    lock -> Acquire ();          // enforce mutual exclusive access to the list 
    list -> Append ( item );
    listEmpty -> Signal ( lock );      // wake up a waiter, if any
    lock -> Release ();
}

//----------------------------------------------------------------------
// SynchList<T>::RemoveFront
//      Remove an "item" from the beginning of the list.  Wait if
//  the list is empty.
// Returns:
//  The removed item. 
//----------------------------------------------------------------------

template   < class  T >
T
SynchList < T >:: RemoveFront ()
{
    T item ;

    lock -> Acquire ();              // enforce mutual exclusion
     while   ( list -> IsEmpty ())
    listEmpty -> Wait ( lock );        // wait until list isn't empty
    item  =  list -> RemoveFront ();
    lock -> Release ();
     return  item ;
}

//----------------------------------------------------------------------
// SynchList<T>::Apply
//      Apply function to every item on a list.
//
//      "func" -- the function to apply
//----------------------------------------------------------------------

template   < class  T >
void
SynchList < T >:: Apply ( void   ( * func )( T ))
{
    lock -> Acquire ();              // enforce mutual exclusion
    list -> Apply ( func );
    lock -> Release ();
}

//----------------------------------------------------------------------
// SynchList<T>::SelfTest, SelfTestHelper
//  Test whether the SynchList implementation is working,
//  by having two threads ping-pong a value between them
//  using two synchronized lists.
//----------------------------------------------------------------------

template   < class  T >
void
SynchList < T >:: SelfTestHelper   ( void *  data )  
{
     SynchList < T >*  _this  =   ( SynchList < T >* ) data ;
     for   ( int  i  =   0 ;  i  <   10 ;  i ++ )   {
        _this -> Append ( _this -> selfTestPing -> RemoveFront ());
     }
}

template   < class  T >
void
SynchList < T >:: SelfTest ( T val )
{
     Thread   * helper  =   new   Thread ( "ping" );
    
    ASSERT ( list -> IsEmpty ());
    selfTestPing  =   new   SynchList < T > ;
    helper -> Fork ( SynchList < T >:: SelfTestHelper ,   this );
     for   ( int  i  =   0 ;  i  <   10 ;  i ++ )   {
        selfTestPing -> Append ( val );
    ASSERT ( val  ==   this -> RemoveFront ());
     }
     delete  selfTestPing ;
}

project4/nachos/code/threads/synchlist.h

// synchlist.h // Data structures for synchronized access to a list. // // Identical interface to List, except accesses are synchronized. // // Copyright (c) 1992-1996 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef SYNCHLIST_H #define SYNCHLIST_H #include "copyright.h" #include "list.h" #include "synch.h" // The following class defines a "synchronized list" -- a list for which // these constraints hold: // 1. Threads trying to remove an item from a list will // wait until the list has an element on it. // 2. One thread at a time can access list data structures template <class T> class SynchList { public: SynchList(); // initialize a synchronized list ~SynchList(); // de-allocate a synchronized list void Append(T item); // append item to the end of the list, // and wake up any thread waiting in remove T RemoveFront(); // remove the first item from the front of // the list, waiting if the list is empty void Apply(void (*f)(T)); // apply function to all elements in list void SelfTest(T value); // test the SynchList implementation private: List<T> *list; // the list of things Lock *lock; // enforce mutual exclusive access to the list Condition *listEmpty; // wait in Remove if the list is empty // these are only to assist SelfTest() SynchList<T> *selfTestPing; static void SelfTestHelper(void* data); }; #include "synchlist.cc" #endif // SYNCHLIST_H

project4/nachos/code/threads/scheduler.h

// scheduler.h // Data structures for the thread dispatcher and scheduler. // Primarily, the list of threads that are ready to run. // // Copyright (c) 1992-1996 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef SCHEDULER_H #define SCHEDULER_H #include "copyright.h" #include "list.h" #include "thread.h" // The following class defines the scheduler/dispatcher abstraction -- // the data structures and operations needed to keep track of which // thread is running, and which threads are ready but not running. class Scheduler { public: Scheduler(); // Initialize list of ready threads ~Scheduler(); // De-allocate ready list void ReadyToRun(Thread* thread); // Thread can be dispatched. Thread* FindNextToRun(); // Dequeue first thread on the ready // list, if any, and return thread. void Run(Thread* nextThread, bool finishing); // Cause nextThread to start running void CheckToBeDestroyed();// Check if thread that had been // running needs to be deleted void Print(); // Print contents of ready list // SelfTest for scheduler is implemented in class Thread private: List<Thread *> *readyList; // queue of threads that are ready to run, // but not running Thread *toBeDestroyed; // finishing thread to be destroyed // by the next thread that runs }; #endif // SCHEDULER_H

project4/nachos/code/threads/.kernel.cc.swp

project4/nachos/code/threads/alarm.cc

project4/nachos/code/threads/alarm.cc

// alarm.cc
//  Routines to use a hardware timer device to provide a
//  software alarm clock.  For now, we just provide time-slicing.
//
//  Not completely implemented.
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include   "copyright.h"
#include   "alarm.h"
#include   "main.h"

//----------------------------------------------------------------------
// Alarm::Alarm
//      Initialize a software alarm clock.  Start up a timer device
//
//      "doRandom" -- if true, arrange for the hardware interrupts to 
//      occur at random, instead of fixed, intervals.
//----------------------------------------------------------------------

Alarm :: Alarm ( bool  doRandom )
{
    timer  =   new   Timer ( doRandom ,   this );
}

//----------------------------------------------------------------------
// Alarm::CallBack
//  Software interrupt handler for the timer device. The timer device is
//  set up to interrupt the CPU periodically (once every TimerTicks).
//  This routine is called each time there is a timer interrupt,
//  with interrupts disabled.
//
//  Note that instead of calling Yield() directly (which would
//  suspend the interrupt handler, not the interrupted thread
//  which is what we wanted to context switch), we set a flag
//  so that once the interrupt handler is done, it will appear as 
//  if the interrupted thread called Yield at the point it is 
//  was interrupted.
//
//  For now, just provide time-slicing.  Only need to time slice 
//      if we're currently running something (in other words, not idle).
//----------------------------------------------------------------------

void  
Alarm :: CallBack ()  
{
     Interrupt   * interrupt  =  kernel -> interrupt ;
     MachineStatus  status  =  interrupt -> getStatus ();
    
     if   ( status  !=   IdleMode )   {
    interrupt -> YieldOnReturn ();
     }
}

project4/nachos/code/threads/thread.h

// thread.h // Data structures for managing threads. A thread represents // sequential execution of code within a program. // So the state of a thread includes the program counter, // the processor registers, and the execution stack. // // Note that because we allocate a fixed size stack for each // thread, it is possible to overflow the stack -- for instance, // by recursing to too deep a level. The most common reason // for this occuring is allocating large data structures // on the stack. For instance, this will cause problems: // // void foo() { int buf[1000]; ...} // // Instead, you should allocate all data structures dynamically: // // void foo() { int *buf = new int[1000]; ...} // // // Bad things happen if you overflow the stack, and in the worst // case, the problem may not be caught explicitly. Instead, // the only symptom may be bizarre segmentation faults. (Of course, // other problems can cause seg faults, so that isn't a sure sign // that your thread stacks are too small.) // // One thing to try if you find yourself with seg faults is to // increase the size of thread stack -- ThreadStackSize. // // In this interface, forking a thread takes two steps. // We must first allocate a data structure for it: "t = new Thread". // Only then can we do the fork: "t->fork(f, arg)". // // Copyright (c) 1992-1996 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef THREAD_H #define THREAD_H #include "copyright.h" #include "utility.h" #include "sysdep.h" #include "machine.h" #include "addrspace.h" // CPU register state to be saved on context switch. // The x86 needs to save only a few registers, // SPARC and MIPS needs to save 10 registers, // the Snake needs 18, // and the RS6000 needs to save 75 (!) // For simplicity, I just take the maximum over all architectures. #define MachineStateSize 75 // Size of the thread's private execution stack. // WATCH OUT IF THIS ISN'T BIG ENOUGH!!!!! const int StackSize = (8 * 1024); // in words // Thread state enum ThreadStatus { JUST_CREATED, RUNNING, READY, BLOCKED }; // The following class defines a "thread control block" -- which // represents a single thread of execution. // // Every thread has: // an execution stack for activation records ("stackTop" and "stack") // space to save CPU registers while not running ("machineState") // a "status" (running/ready/blocked) // // Some threads also belong to a user address space; threads // that only run in the kernel have a NULL address space. class Thread { private: // NOTE: DO NOT CHANGE the order of these first two members. // THEY MUST be in this position for SWITCH to work. int *stackTop; // the current stack pointer void *machineState[MachineStateSize]; // all registers except for stackTop public: Thread(char* debugName); // initialize a Thread ~Thread(); // deallocate a Thread // NOTE -- thread being deleted // must not be running when delete // is called // basic thread operations void Fork(VoidFunctionPtr func, void *arg); // Make thread run (*func)(arg) void Yield(); // Relinquish the CPU if any // other thread is runnable void Sleep(bool finishing); // Put the thread to sleep and // relinquish the processor void Begin(); // Startup code for the thread void Finish(); // The thread is done executing void CheckOverflow(); // Check if thread stack has overflowed void setStatus(ThreadStatus st) { status = st; } char* getName() { return (name); } void Print() { cout << name; } void SelfTest(); // test whether thread impl is working private: // some of the private data for this class is listed above int *stack; // Bottom of the stack // NULL if this is the main thread // (If NULL, don't deallocate stack) ThreadStatus status; // ready, running or blocked char* name; void StackAllocate(VoidFunctionPtr func, void *arg); // Allocate a stack for thread. // Used internally by Fork() // A thread running a user program actually has *two* sets of CPU registers -- // one for its state while executing user code, one for its state // while executing kernel code. int userRegisters[NumTotalRegs]; // user-level CPU register state public: void SaveUserState(); // save user-level register state void RestoreUserState(); // restore user-level register state AddrSpace *space; // User code this thread is running. }; // external function, dummy routine whose sole job is to call Thread::Print extern void ThreadPrint(Thread *thread); // Magical machine-dependent routines, defined in switch.s extern "C" { // First frame on thread execution stack; // call ThreadBegin // call "func" // (when func returns, if ever) call ThreadFinish() void ThreadRoot(); // Stop running oldThread and start running newThread void SWITCH(Thread *oldThread, Thread *newThread); } #endif // THREAD_H

project4/nachos/code/threads/kernel.h

// kernel.h // Global variables for the Nachos kernel. // // Copyright (c) 1992-1996 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef KERNEL_H #define KERNEL_H #include "copyright.h" #include "debug.h" #include "utility.h" #include "thread.h" #include "scheduler.h" #include "interrupt.h" #include "stats.h" #include "alarm.h" #include "filesys.h" #include "machine.h" class PostOfficeInput; class PostOfficeOutput; class SynchConsoleInput; class SynchConsoleOutput; class SynchDisk; class Kernel { public: Kernel(int argc, char **argv); // Interpret command line arguments ~Kernel(); // deallocate the kernel void Initialize(); // initialize the kernel -- separated // from constructor because // refers to "kernel" as a global void ThreadSelfTest(); // self test of threads and synchronization void ConsoleTest(); // interactive console self test void NetworkTest(); // interactive 2-machine network test // These are public for notational convenience; really, // they're global variables used everywhere. Thread *currentThread; // the thread holding the CPU Scheduler *scheduler; // the ready list Interrupt *interrupt; // interrupt status Statistics *stats; // performance metrics Alarm *alarm; // the software alarm clock Machine *machine; // the simulated CPU SynchConsoleInput *synchConsoleIn; SynchConsoleOutput *synchConsoleOut; SynchDisk *synchDisk; FileSystem *fileSystem; PostOfficeInput *postOfficeIn; PostOfficeOutput *postOfficeOut; int hostName; // machine identifier private: bool randomSlice; // enable pseudo-random time slicing bool debugUserProg; // single step user program double reliability; // likelihood messages are dropped char *consoleIn; // file to read console input from char *consoleOut; // file to send console output to #ifndef FILESYS_STUB bool formatFlag; // format the disk if this is true #endif }; #endif // KERNEL_H

project4/nachos/code/threads/switch.S

/* switch.s * Machine dependent context switch routines. DO NOT MODIFY THESE! * * Context switching is inherently machine dependent, since * the registers to be saved, how to set up an initial * call frame, etc, are all specific to a processor architecture. * * This file currently supports the following architectures: * DEC MIPS (DECMIPS) * DEC Alpha (ALPHA) * SUN SPARC (SPARC) * HP PA-RISC (PARISC) * Intel 386 (x86) * IBM RS6000 (PowerPC) -- I hope it will also work for Mac PowerPC * * We define two routines for each architecture: * * ThreadRoot(InitialPC, InitialArg, WhenDonePC, StartupPC) * InitialPC - The program counter of the procedure to run * in this thread. * InitialArg - The single argument to the thread. * WhenDonePC - The routine to call when the thread returns. * StartupPC - Routine to call when the thread is started. * * ThreadRoot is called from the SWITCH() routine to start * a thread for the first time. * * SWITCH(oldThread, newThread) * oldThread - The current thread that was running, where the * CPU register state is to be saved. * newThread - The new thread to be run, where the CPU register * state is to be loaded from. */ /* Copyright (c) 1992-1996 The Regents of the University of California. All rights reserved. See copyright.h for copyright notice and limitation of liability and disclaimer of warranty provisions. */ #include "copyright.h" #include "switch.h" #ifdef DECMIPS /* Symbolic register names */ #define z $0 /* zero register */ #define a0 $4 /* argument registers */ #define a1 $5 #define s0 $16 /* callee saved */ #define s1 $17 #define s2 $18 #define s3 $19 #define s4 $20 #define s5 $21 #define s6 $22 #define s7 $23 #define sp $29 /* stack pointer */ #define fp $30 /* frame pointer */ #define ra $31 /* return address */ .text .align 2 .globl ThreadRoot .ent ThreadRoot,0 ThreadRoot: or fp,z,z # Clearing the frame pointer here # makes gdb backtraces of thread stacks # end here (I hope!) jal StartupPC # call startup procedure move a0, InitialArg jal InitialPC # call main procedure jal WhenDonePC # when done, call clean up procedure # NEVER REACHED .end ThreadRoot # a0 -- pointer to old Thread # a1 -- pointer to new Thread .globl SWITCH .ent SWITCH,0 SWITCH: sw sp, SP(a0) # save new stack pointer sw s0, S0(a0) # save all the callee-save registers sw s1, S1(a0) sw s2, S2(a0) sw s3, S3(a0) sw s4, S4(a0) sw s5, S5(a0) sw s6, S6(a0) sw s7, S7(a0) sw fp, FP(a0) # save frame pointer sw ra, PC(a0) # save return address lw sp, SP(a1) # load the new stack pointer lw s0, S0(a1) # load the callee-save registers lw s1, S1(a1) lw s2, S2(a1) lw s3, S3(a1) lw s4, S4(a1) lw s5, S5(a1) lw s6, S6(a1) lw s7, S7(a1) lw fp, FP(a1) lw ra, PC(a1) # load the return address j ra .end SWITCH #endif // DECMIPS #ifdef SPARC /* NOTE! These files appear not to exist on Solaris -- * you need to find where (the SPARC-specific) MINFRAME, ST_FLUSH_WINDOWS, ... * are defined. (I don't have a Solaris machine, so I have no way to tell.) */ #ifdef SOLARIS #include <sys/trap.h> #include <sys/asm_linkage.h> #else #include <sun4/trap.h> #include <sun4/asm_linkage.h> #endif .seg "text" /* SPECIAL to the SPARC: * The first two instruction of ThreadRoot are skipped because * the address of ThreadRoot is made the return address of SWITCH() * by the routine Thread::StackAllocate. SWITCH() jumps here on the * "ret" instruction which is really at "jmp %o7+8". The 8 skips the * two nops at the beginning of the routine. */ #ifdef SOLARIS .globl ThreadRoot ThreadRoot: #else .globl _ThreadRoot _ThreadRoot: #endif nop ; nop /* These 2 nops are skipped because we are called * with a jmp+8 instruction. */ clr %fp /* Clearing the frame pointer makes gdb backtraces * of thread stacks end here. */ /* Currently the arguments are in out registers we * save them into local registers so they won't be * trashed during the calls we make. */ mov InitialPC, %l0 mov InitialArg, %l1 mov WhenDonePC, %l2 /* Execute the code: * call StartupPC(); * call InitialPC(InitialArg); * call WhenDonePC(); */ call StartupPC,0 nop call %l0, 1 mov %l1, %o0 /* Using delay slot to setup argument to InitialPC */ call %l2, 0 nop /* WhenDonePC call should never return. If it does * we execute a trap into the debugger. */ ta ST_BREAKPOINT #ifdef SOLARIS .globl SWITCH SWITCH: #else .globl _SWITCH _SWITCH: #endif save %sp, -SA(MINFRAME), %sp st %fp, [%i0] st %i0, [%i0+I0] st %i1, [%i0+I1] st %i2, [%i0+I2] st %i3, [%i0+I3] st %i4, [%i0+I4] st %i5, [%i0+I5] st %i7, [%i0+I7] ta ST_FLUSH_WINDOWS nop mov %i1, %l0 ld [%l0+I0], %i0 ld [%l0+I1], %i1 ld [%l0+I2], %i2 ld [%l0+I3], %i3 ld [%l0+I4], %i4 ld [%l0+I5], %i5 ld [%l0+I7], %i7 ld [%l0], %i6 ret restore #endif // SPARC #ifdef PARISC ;rp = r2, sp = r30 ;arg0 = r26, arg1 = r25, arg2 = r24, arg3 = r23 .SPACE $TEXT$ .SUBSPA $CODE$ ThreadRoot .PROC .CALLINFO CALLER,FRAME=0 .ENTER .CALL ble 0(%r6) ;call StartupPC stw %r31, -24(%sp) ;put return address in proper stack ;location for StartupPC export stub. or %r4, 0, %arg0 ;load InitialArg .CALL ;in=26 ble 0(%r3) ;call InitialPC stw %r31, -24(%sp) ;put return address in proper stack ;location for InitialPC export stub. .CALL ble 0(%r5) ;call WhenDonePC stw %r31, -24(%sp) ;put return address in proper stack ;location for StartupPC export stub. .LEAVE .PROCEND SWITCH .PROC .CALLINFO CALLER,FRAME=0 .ENTRY ; save process state of oldThread stw %sp, SP(%arg0) ;save stack pointer stw %r3, S0(%arg0) ;save callee-save registers stw %r4, S1(%arg0) stw %r5, S2(%arg0) stw %r6, S3(%arg0) stw %r7, S4(%arg0) stw %r8, S5(%arg0) stw %r9, S6(%arg0) stw %r10, S7(%arg0) stw %r11, S8(%arg0) stw %r12, S9(%arg0) stw %r13, S10(%arg0) stw %r14, S11(%arg0) stw %r15, S12(%arg0) stw %r16, S13(%arg0) stw %r17, S14(%arg0) stw %r18, S15(%arg0) stw %rp, PC(%arg0) ;save program counter ; restore process state of nextThread ldw SP(%arg1), %sp ;restore stack pointer ldw S0(%arg1), %r3 ;restore callee-save registers ldw S1(%arg1), %r4 ldw S2(%arg1), %r5 ldw S3(%arg1), %r6 ldw S4(%arg1), %r7 ldw S5(%arg1), %r8 ldw S6(%arg1), %r9 ldw S7(%arg1), %r10 ldw S8(%arg1), %r11 ldw S9(%arg1), %r12 ldw S10(%arg1), %r13 ldw S11(%arg1), %r14 ldw S12(%arg1), %r15 ldw S13(%arg1), %r16 ldw S14(%arg1), %r17 ldw PC(%arg1), %rp ;save program counter bv 0(%rp) .EXIT ldw S15(%arg1), %r18 .PROCEND .EXPORT SWITCH,ENTRY,PRIV_LEV=3,RTNVAL=GR .EXPORT ThreadRoot,ENTRY,PRIV_LEV=3,RTNVAL=GR #endif // PARISC #ifdef x86 .text .align 2 .globl ThreadRoot .globl _ThreadRoot /* void ThreadRoot( void ) ** ** expects the following registers to be initialized: ** eax points to startup function (interrupt enable) ** edx contains inital argument to thread function ** esi points to thread function ** edi point to Thread::Finish() */ _ThreadRoot: ThreadRoot: pushl %ebp movl %esp,%ebp pushl InitialArg call *StartupPC call *InitialPC call *WhenDonePC # NOT REACHED movl %ebp,%esp popl %ebp ret /* void SWITCH( thread *t1, thread *t2 ) ** ** on entry, stack looks like this: ** 8(esp) -> thread *t2 ** 4(esp) -> thread *t1 ** (esp) -> return address ** ** we push the current eax on the stack so that we can use it as ** a pointer to t1, this decrements esp by 4, so when we use it ** to reference stuff on the stack, we add 4 to the offset. */ .comm _eax_save,4 .globl SWITCH .globl _SWITCH _SWITCH: SWITCH: movl %eax,_eax_save # save the value of eax movl 4(%esp),%eax # move pointer to t1 into eax movl %ebx,_EBX(%eax) # save registers movl %ecx,_ECX(%eax) movl %edx,_EDX(%eax) movl %esi,_ESI(%eax) movl %edi,_EDI(%eax) movl %ebp,_EBP(%eax) movl %esp,_ESP(%eax) # save stack pointer movl _eax_save,%ebx # get the saved value of eax movl %ebx,_EAX(%eax) # store it movl 0(%esp),%ebx # get return address from stack into ebx movl %ebx,_PC(%eax) # save it into the pc storage movl 8(%esp),%eax # move pointer to t2 into eax movl _EAX(%eax),%ebx # get new value for eax into ebx movl %ebx,_eax_save # save it movl _EBX(%eax),%ebx # retore old registers movl _ECX(%eax),%ecx movl _EDX(%eax),%edx movl _ESI(%eax),%esi movl _EDI(%eax),%edi movl _EBP(%eax),%ebp movl _ESP(%eax),%esp # restore stack pointer movl _PC(%eax),%eax # restore return address into eax movl %eax,4(%esp) # copy over the ret address on the stack movl _eax_save,%eax ret #endif // x86 #if defined(ApplePowerPC) /* The AIX PowerPC code is incompatible with the assembler on MacOS X * and Linux. So the SWITCH code was adapted for IBM 750 compatible * processors, and ThreadRoot is modeled after the more reasonable * looking ThreadRoot's in this file. * * Joshua LeVasseur <[email protected]> */ .align 2 .globl _SWITCH _SWITCH: stw r1, 0(r3) /* Store stack pointer. */ stmw r13, 20(r3) /* Store general purpose registers 13 - 31. */ stfd f14, 96(r3) /* Store floating point registers 14 -31. */ stfd f15, 104(r3) stfd f16, 112(r3) stfd f17, 120(r3) stfd f18, 128(r3) stfd f19, 136(r3) stfd f20, 144(r3) stfd f21, 152(r3) stfd f22, 160(r3) stfd f23, 168(r3) stfd f24, 176(r3) stfd f25, 184(r3) stfd f26, 192(r3) stfd f27, 200(r3) stfd f28, 208(r3) stfd f29, 216(r3) stfd f30, 224(r3) stfd f31, 232(r3) mflr r0 stw r0, 244(r3) /* Spill the link register. */ mfcr r12 stw r12, 240(r3) /* Spill the condition register. */ lwz r1, 0(r4) /* Load the incoming stack pointer. */ lwz r0, 244(r4) /* Load the incoming link register. */ mtlr r0 /* Restore the link register. */ lwz r12, 240(r4) /* Load the condition register value. */ mtcrf 0xff, r12 /* Restore the condition register. */ lmw r13, 20(r4) /* Restore registers r13 - r31. */ lfd f14, 96(r4) /* Restore floating point register f14 - f31. */ lfd f15, 104(r4) lfd f16, 112(r4) lfd f17, 120(r4) lfd f18, 128(r4) lfd f19, 136(r4) lfd f20, 144(r4) lfd f21, 152(r4) lfd f22, 160(r4) lfd f23, 168(r4) lfd f24, 176(r4) lfd f25, 184(r4) lfd f26, 192(r4) lfd f27, 200(r4) lfd f28, 208(r4) lfd f29, 216(r4) lfd f30, 224(r4) lfd f31, 232(r4) /* When a thread first starts, the following blr instruction jumps * to ThreadRoot. ThreadRoot expects the incoming thread block * in r4. */ blr /* Branch to the address held in link register. */ .align 2 .globl _ThreadRoot _ThreadRoot: lwz r20, 16(r4) /* StartupPCState - ThreadBegin */ lwz r21, 8(r4) /* InitialArgState - arg */ lwz r22, 4(r4) /* InitialPCState - func */ lwz r23, 12(r4) /* WhenDonePCState - ThreadFinish */ /* Call ThreadBegin function. */ mtctr r20 /* The function pointer. */ bctrl /* Call the target function. */ mr r3, r21 /* Function arg. */ mtctr r22 /* Function pointer. */ bctrl /* Call the ThreadFinish function. */ mtctr r23 bctrl /* We shouldn't execute here. */ 1: b 1b #endif #if defined(PowerPC) && !defined(ApplePowerPC) .globl branch[ds] .csect branch[ds] .long .branch[PR] .long TOC[tc0] .long 0 .toc T.branch: .tc .branch[tc], branch[ds] .globl .branch[PR] .csect .branch[PR] l 0, 0x0(11) # load function address into r0 mtctr 0 # move r0 into counter register l 2, 0x4(11) # move new TOC address into r2 l 11, 0x8(11) # reset function address bctr # branch to the counter register .globl ThreadRoot[ds] .csect ThreadRoot[ds] .long .ThreadRoot[PR] .long TOC[tc0] .long 0 .toc T.ThreadRoot: .tc .ThreadRoot[tc], ThreadRoot[ds] .globl .ThreadRoot[PR] .csect .ThreadRoot[PR] .set argarea, 32 .set linkarea, 24 .set locstckarea, 0 .set nfprs, 18 .set ngprs, 19 .set szdsa, 8*nfprs+4*ngprs+linkarea+argarea+locstckarea mflr 0 mfcr 12 bl ._savef14 cror 0xf, 0xf, 0xf stm 13, -8*nfprs-4*ngprs(1) st 0, 8(1) st 12, 4(1) st 4, 24(1) st 5, 28(1) st 6, 32(1) stu 1, -szdsa(1) muli 11,3,1 # copy contents of register r24 to r11 bl .branch[PR] # call function branch cror 0xf, 0xf, 0xf # no operation ai 1,1,szdsa lm 13, -8*nfprs-4*ngprs(1) bl ._restf14 cror 0xf, 0xf, 0xf l 0, 8(1) l 12, 4(1) mtlr 0 mtcrf 0x38, 12 l 4, 24(1) l 5, 28(1) l 6, 32(1) mflr 0 mfcr 12 bl ._savef14 cror 0xf, 0xf, 0xf stm 13, -8*nfprs-4*ngprs(1) st 0, 8(1) st 12, 4(1) st 6, 24(1) stu 1, -szdsa(1) muli 3, 4,1 # load user function parameter r22 to r3 muli 11,5,1 # copy contents of register r21 to r11 bl .branch[PR] # call function branch cror 0xf, 0xf, 0xf # no operation ai 1,1,szdsa lm 13, -8*nfprs-4*ngprs(1) bl ._restf14 cror 0xf, 0xf, 0xf l 0, 8(1) l 12, 4(1) mtlr 0 mtcrf 0x38, 12 l 6, 24(1) muli 11,6,1 # copy contents of register r23 to r11 bl .branch[PR] # call function branch cror 0xf, 0xf, 0xf # no operation brl # the programme should not return here. .extern ._savef14 .extern ._restf14 .globl SWITCH[ds] .csect SWITCH[ds] .long .SWITCH[PR] .long TOC[tc0] .long 0 .toc T.SWITCH: .tc .SWITCH[tc], SWITCH[ds] .globl .SWITCH[PR] .csect .SWITCH[PR] st 1, 0(3) # store stack pointer stm 13, 20(3) # store general purpose registers (13 -31) stfd 14, 96(3) # store floating point registers (14 -31) stfd 15, 104(3) # there is no single instruction to do for stfd 16, 112(3) # floating point registers. so do one by one stfd 17, 120(3) stfd 18, 128(3) stfd 19, 136(3) stfd 20, 144(3) stfd 21, 152(3) stfd 22, 160(3) stfd 23, 168(3) stfd 24, 176(3) stfd 25, 184(3) stfd 26, 192(3) stfd 27, 200(3) stfd 28, 208(3) stfd 29, 216(3) stfd 30, 224(3) stfd 31, 232(3) mflr 0 # move link register value to register 0 st 0, 244(3) # store link register value mfcr 12 # move condition register to register 12 st 12, 240(3) # store condition register value l 1, 0(4) # load stack pointer l 0, 244(4) # load link register value mtlr 0 l 12, 240(4) # load condition register value mtcrf 0x38, 12 lm 13, 20(4) # load into general purpose registers (13 -31) lfd 14, 96(4) # load into floating point registers (14 -31) lfd 15, 104(4) # there is no single instruction for lfd 16, 112(4) # loading into more than one floating point lfd 17, 120(4) # registers. so do one by one. lfd 18, 128(4) lfd 19, 136(4) lfd 20, 144(4) lfd 21, 152(4) lfd 22, 160(4) lfd 23, 168(4) lfd 24, 176(4) lfd 25, 184(4) lfd 26, 192(4) lfd 27, 200(4) lfd 28, 208(4) lfd 29, 216(4) lfd 30, 224(4) lfd 31, 232(4) l 3, 16(4) l 5, 4(4) l 6, 12(4) l 4, 8(4) brl # branch to the address held in link register. #endif // PowerPC #ifdef ALPHA /* * Porting to Alpha was done by Shuichi Oikawa ([email protected]). */ /* * Symbolic register names and register saving rules * * Legend: * T Saved by caller (Temporaries) * S Saved by callee (call-Safe registers) */ #define v0 $0 /* (T) return value */ #define t0 $1 /* (T) temporary registers */ #define s0 $9 /* (S) call-safe registers */ #define s1 $10 #define s2 $11 #define s3 $12 #define s4 $13 #define s5 $14 #define s6 $15 #define a0 $16 /* (T) argument registers */ #define a1 $17 #define ai $25 /* (T) argument information */ #define ra $26 /* (T) return address */ #define pv $27 /* (T) procedure value */ #define gp $29 /* (T) (local) data pointer */ #define sp $30 /* (S) stack pointer */ #define zero $31 /* wired zero */ .set noreorder # unless overridden .align 3 .text .globl ThreadRoot .ent ThreadRoot,0 ThreadRoot: .frame sp,0,ra ldgp gp,0(pv) mov zero,s6 # Clearing the frame pointer here # makes gdb backtraces of thread stacks # end here (I hope!) mov StartupPC,pv jsr ra,(pv) # call startup procedure ldgp gp,0(ra) mov InitialArg,a0 mov InitialPC,pv jsr ra,(pv) # call main procedure ldgp gp,0(ra) mov WhenDonePC,pv jsr ra,(pv) # when done, call clean up procedure ldgp gp,0(ra) .end ThreadRoot # NEVER REACHED /* a0 -- pointer to old Thread * * a1 -- pointer to new Thread */ .globl SWITCH .ent SWITCH,0 SWITCH: .frame sp,0,ra ldgp gp,0(pv) stq ra, PC(a0) # save return address stq gp, GP(a0) stq sp, SP(a0) # save new stack pointer stq s0, S0(a0) # save all the callee-save registers stq s1, S1(a0) stq s2, S2(a0) stq s3, S3(a0) stq s4, S4(a0) stq s5, S5(a0) stq s6, S6(a0) # save frame pointer ldq ra, PC(a1) # load the return address ldq gp, GP(a1) ldq sp, SP(a1) # load the new stack pointer ldq s0, S0(a1) # load the callee-save registers ldq s1, S1(a1) ldq s2, S2(a1) ldq s3, S3(a1) ldq s4, S4(a1) ldq s5, S5(a1) ldq s6, S6(a1) mov ra,pv ret zero,(ra) .end SWITCH #endif // ALPHA

project4/nachos/code/threads/synch.cc

project4/nachos/code/threads/synch.cc

// synch.cc 
//  Routines for synchronizing threads.  Three kinds of
//  synchronization routines are defined here: semaphores, locks 
//      and condition variables.
//
// Any implementation of a synchronization routine needs some
// primitive atomic operation.  We assume Nachos is running on
// a uniprocessor, and thus atomicity can be provided by
// turning off interrupts.  While interrupts are disabled, no
// context switch can occur, and thus the current thread is guaranteed
// to hold the CPU throughout, until interrupts are reenabled.
//
// Because some of these routines might be called with interrupts
// already disabled (Semaphore::V for one), instead of turning
// on interrupts at the end of the atomic operation, we always simply
// re-set the interrupt state back to its original value (whether
// that be disabled or enabled).
//
// Once we'e implemented one set of higher level atomic operations,
// we can implement others using that implementation.  We illustrate
// this by implementing locks and condition variables on top of 
// semaphores, instead of directly enabling and disabling interrupts.
//
// Locks are implemented using a semaphore to keep track of
// whether the lock is held or not -- a semaphore value of 0 means
// the lock is busy; a semaphore value of 1 means the lock is free.
//
// The implementation of condition variables using semaphores is
// a bit trickier, as explained below under Condition::Wait.
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include   "copyright.h"
#include   "synch.h"
#include   "main.h"

//----------------------------------------------------------------------
// Semaphore::Semaphore
//  Initialize a semaphore, so that it can be used for synchronization.
//
//  "debugName" is an arbitrary name, useful for debugging.
//  "initialValue" is the initial value of the semaphore.
//----------------------------------------------------------------------

Semaphore :: Semaphore ( char *  debugName ,   int  initialValue )
{
    name  =  debugName ;
     value   =  initialValue ;
    queue  =   new   List < Thread   *> ;
}

//----------------------------------------------------------------------
// Semaphore::Semaphore
//  De-allocate semaphore, when no longer needed.  Assume no one
//  is still waiting on the semaphore!
//----------------------------------------------------------------------

Semaphore ::~ Semaphore ()
{
     delete  queue ;
}

//----------------------------------------------------------------------
// Semaphore::P
//  Wait until semaphore value > 0, then decrement.  Checking the
//  value and decrementing must be done atomically, so we
//  need to disable interrupts before checking the value.
//
//  Note that Thread::Sleep assumes that interrupts are disabled
//  when it is called.
//----------------------------------------------------------------------

void
Semaphore :: P ()
{
     Interrupt   * interrupt  =  kernel -> interrupt ;
     Thread   * currentThread  =  kernel -> currentThread ;
    
     // disable interrupts
     IntStatus  oldLevel  =  interrupt -> SetLevel ( IntOff );    
    
     while   ( value   ==   0 )   {          // semaphore not available
    queue -> Append ( currentThread );     // so go to sleep
    currentThread -> Sleep ( FALSE );
     }  
     value -- ;              // semaphore available, consume its value
   
     // re-enable interrupts
     ( void )  interrupt -> SetLevel ( oldLevel );    
}

//----------------------------------------------------------------------
// Semaphore::V
//  Increment semaphore value, waking up a waiter if necessary.
//  As with P(), this operation must be atomic, so we need to disable
//  interrupts.  Scheduler::ReadyToRun() assumes that interrupts
//  are disabled when it is called.
//----------------------------------------------------------------------

void
Semaphore :: V ()
{
     Interrupt   * interrupt  =  kernel -> interrupt ;
    
     // disable interrupts
     IntStatus  oldLevel  =  interrupt -> SetLevel ( IntOff );    
    
     if   ( ! queue -> IsEmpty ())   {    // make thread ready.
    kernel -> scheduler -> ReadyToRun ( queue -> RemoveFront ());
     }
     value ++ ;
    
     // re-enable interrupts
     ( void )  interrupt -> SetLevel ( oldLevel );
}

//----------------------------------------------------------------------
// Semaphore::SelfTest, SelfTestHelper
//  Test the semaphore implementation, by using a semaphore
//  to control two threads ping-ponging back and forth.
//----------------------------------------------------------------------

static   Semaphore   * ping ;
static   void
SelfTestHelper   ( Semaphore   * pong )  
{
     for   ( int  i  =   0 ;  i  <   10 ;  i ++ )   {
        ping -> P ();
    pong -> V ();
     }
}

void
Semaphore :: SelfTest ()
{
     Thread   * helper  =   new   Thread ( "ping" );

    ASSERT ( value   ==   0 );       // otherwise test won't work!
    ping  =   new   Semaphore ( "ping" ,   0 );
    helper -> Fork (( VoidFunctionPtr )   SelfTestHelper ,   this );
     for   ( int  i  =   0 ;  i  <   10 ;  i ++ )   {
        ping -> V ();
     this -> P ();
     }
     delete  ping ;
}

//----------------------------------------------------------------------
// Lock::Lock
//  Initialize a lock, so that it can be used for synchronization.
//  Initially, unlocked.
//
//  "debugName" is an arbitrary name, useful for debugging.
//----------------------------------------------------------------------

Lock :: Lock ( char *  debugName )
{
    name  =  debugName ;
    semaphore  =   new   Semaphore ( "lock" ,   1 );    // initially, unlocked
    lockHolder  =  NULL ;
}

//----------------------------------------------------------------------
// Lock::~Lock
//  Deallocate a lock
//----------------------------------------------------------------------
Lock ::~ Lock ()
{
     delete  semaphore ;
}

//----------------------------------------------------------------------
// Lock::Acquire
//  Atomically wait until the lock is free, then set it to busy.
//  Equivalent to Semaphore::P(), with the semaphore value of 0
//  equal to busy, and semaphore value of 1 equal to free.
//----------------------------------------------------------------------

void   Lock :: Acquire ()
{
    semaphore -> P ();
    lockHolder  =  kernel -> currentThread ;
}

//----------------------------------------------------------------------
// Lock::Release
//  Atomically set lock to be free, waking up a thread waiting
//  for the lock, if any.
//  Equivalent to Semaphore::V(), with the semaphore value of 0
//  equal to busy, and semaphore value of 1 equal to free.
//
//  By convention, only the thread that acquired the lock
//  may release it.
//---------------------------------------------------------------------

void   Lock :: Release ()
{
    ASSERT ( IsHeldByCurrentThread ());
    lockHolder  =  NULL ;
    semaphore -> V ();
}

//----------------------------------------------------------------------
// Condition::Condition
//  Initialize a condition variable, so that it can be 
//  used for synchronization.  Initially, no one is waiting
//  on the condition.
//
//  "debugName" is an arbitrary name, useful for debugging.
//----------------------------------------------------------------------
Condition :: Condition ( char *  debugName )
{
    name  =  debugName ;
    waitQueue  =   new   List < Semaphore   *> ;
}

//----------------------------------------------------------------------
// Condition::Condition
//  Deallocate the data structures implementing a condition variable.
//----------------------------------------------------------------------

Condition ::~ Condition ()
{
     delete  waitQueue ;
}

//----------------------------------------------------------------------
// Condition::Wait
//  Atomically release monitor lock and go to sleep.
//  Our implementation uses semaphores to implement this, by
//  allocating a semaphore for each waiting thread.  The signaller
//  will V() this semaphore, so there is no chance the waiter
//  will miss the signal, even though the lock is released before
//  calling P().
//
//  Note: we assume Mesa-style semantics, which means that the
//  waiter must re-acquire the monitor lock when waking up.
//
//  "conditionLock" -- lock protecting the use of this condition
//----------------------------------------------------------------------

void   Condition :: Wait ( Lock *  conditionLock )  
{
      Semaphore   * waiter ;
    
     ASSERT ( conditionLock -> IsHeldByCurrentThread ());

     waiter  =   new   Semaphore ( "condition" ,   0 );
     waitQueue -> Append ( waiter );
     conditionLock -> Release ();
     waiter -> P ();
     conditionLock -> Acquire ();
      delete  waiter ;
}

//----------------------------------------------------------------------
// Condition::Signal
//  Wake up a thread waiting on this condition, if any.
//
//  Note: we assume Mesa-style semantics, which means that the
//  signaller doesn't give up control immediately to the thread
//  being woken up (unlike Hoare-style).
//
//  Also note: we assume the caller holds the monitor lock
//  (unlike what is described in Birrell's paper).  This allows
//  us to access waitQueue without disabling interrupts.
//
//  "conditionLock" -- lock protecting the use of this condition
//----------------------------------------------------------------------

void   Condition :: Signal ( Lock *  conditionLock )
{
     Semaphore   * waiter ;
    
    ASSERT ( conditionLock -> IsHeldByCurrentThread ());
    
     if   ( ! waitQueue -> IsEmpty ())   {
        waiter  =  waitQueue -> RemoveFront ();
    waiter -> V ();
     }
}

//----------------------------------------------------------------------
// Condition::Broadcast
//  Wake up all threads waiting on this condition, if any.
//
//  "conditionLock" -- lock protecting the use of this condition
//----------------------------------------------------------------------

void   Condition :: Broadcast ( Lock *  conditionLock )  
{
     while   ( ! waitQueue -> IsEmpty ())   {
         Signal ( conditionLock );
     }
}

project4/nachos/code/threads/switch.h

/* switch.h * Definitions needed for implementing context switching. * * Context switching is inherently machine dependent, since * the registers to be saved, how to set up an initial * call frame, etc, are all specific to a processor architecture. * * This file currently supports the DEC MIPS, DEC Alpha, SUN SPARC, * HP PARISC, IBM PowerPC, and Intel x86 architectures. */ /* Copyright (c) 1992-1996 The Regents of the University of California. All rights reserved. See copyright.h for copyright notice and limitation of liability and disclaimer of warranty provisions. */ #ifndef SWITCH_H #define SWITCH_H #include "copyright.h" #ifdef DECMIPS /* Registers that must be saved during a context switch. * These are the offsets from the beginning of the Thread object, * in bytes, used in switch.s */ #define SP 0 #define S0 4 #define S1 8 #define S2 12 #define S3 16 #define S4 20 #define S5 24 #define S6 28 #define S7 32 #define FP 36 #define PC 40 /* To fork a thread, we set up its saved register state, so that * when we switch to the thread, it will start running in ThreadRoot. * * The following are the initial registers we need to set up to * pass values into ThreadRoot (for instance, containing the procedure * for the thread to run). The first set is the registers as used * by ThreadRoot; the second set is the locations for these initial * values in the Thread object -- used in Thread::AllocateStack(). */ #define InitialPC s0 #define InitialArg s1 #define WhenDonePC s2 #define StartupPC s3 #define PCState (PC/4-1) #define FPState (FP/4-1) #define InitialPCState (S0/4-1) #define InitialArgState (S1/4-1) #define WhenDonePCState (S2/4-1) #define StartupPCState (S3/4-1) #endif // DECMIPS #ifdef SPARC /* Registers that must be saved during a context switch. See comment above. */ #define I0 4 #define I1 8 #define I2 12 #define I3 16 #define I4 20 #define I5 24 #define I6 28 #define I7 32 /* Aliases used for clearing code. */ #define FP I6 #define PC I7 /* Registers for ThreadRoot. See comment above. */ #define InitialPC %o0 #define InitialArg %o1 #define WhenDonePC %o2 #define StartupPC %o3 #define PCState (PC/4-1) #define InitialPCState (I0/4-1) #define InitialArgState (I1/4-1) #define WhenDonePCState (I2/4-1) #define StartupPCState (I3/4-1) #endif // SPARC #ifdef PARISC /* Registers that must be saved during a context switch. See comment above. */ #define SP 0 #define S0 4 #define S1 8 #define S2 12 #define S3 16 #define S4 20 #define S5 24 #define S6 28 #define S7 32 #define S8 36 #define S9 40 #define S10 44 #define S11 48 #define S12 52 #define S13 56 #define S14 60 #define S15 64 #define PC 68 /* Registers for ThreadRoot. See comment above. */ #define InitialPC %r3 /* S0 */ #define InitialArg %r4 #define WhenDonePC %r5 #define StartupPC %r6 #define PCState (PC/4-1) #define InitialPCState (S0/4-1) #define InitialArgState (S1/4-1) #define WhenDonePCState (S2/4-1) #define StartupPCState (S3/4-1) #endif // PARISC #ifdef x86 /* the offsets of the registers from the beginning of the thread object */ #define _ESP 0 #define _EAX 4 #define _EBX 8 #define _ECX 12 #define _EDX 16 #define _EBP 20 #define _ESI 24 #define _EDI 28 #define _PC 32 /* These definitions are used in Thread::AllocateStack(). */ #define PCState (_PC/4-1) #define FPState (_EBP/4-1) #define InitialPCState (_ESI/4-1) #define InitialArgState (_EDX/4-1) #define WhenDonePCState (_EDI/4-1) #define StartupPCState (_ECX/4-1) #define InitialPC %esi #define InitialArg %edx #define WhenDonePC %edi #define StartupPC %ecx #endif // x86 #ifdef PowerPC #define SP 0 // stack pointer #define P1 4 // parameters #define P2 8 #define P3 12 #define P4 16 #define GP13 20 // general purpose registers 13-31 #define GP14 24 #define GP15 28 #define GP16 32 #define GP17 36 #define GP18 40 #define GP19 44 #define GP20 48 #define GP21 52 #define GP22 56 #define GP23 60 #define GP24 64 #define GP25 68 #define GP26 72 #define GP27 76 #define GP28 80 #define GP29 84 #define GP30 88 #define GP31 92 #define FP13 96 // floating point registers 14-31 #define FP15 104 #define FP16 112 #define FP17 120 #define FP18 128 #define FP19 136 #define FP20 144 #define FP21 152 #define FP22 160 #define FP23 168 #define FP24 176 #define FP25 184 #define FP26 192 #define FP27 200 #define FP28 208 #define FP29 216 #define FP30 224 #define FP31 232 #define CR 240 // control register #define LR 244 // link register #define TOC 248 // Table Of Contents // for ThreadRoot assembly function #define InitialPCState 0 // (P1/4 - 1) // user function address #define InitialArgState 1 // (P2/4 - 1) // user function argument #define WhenDonePCState 2 // (P3/4 - 1) // clean up function addr #define StartupPCState 3 // (P4/4 - 1) // start up function addr #define PCState 60 // (LR/4 - 1) // ThreadRoot addr (first time). // Later PC addr when SWITCH // occured #define InitialLR 21 #define InitialArg 22 #define WhenDoneLR 23 #define StartupLR 24 #endif // PowerPC #ifdef ALPHA /* * Porting to Alpha was done by Shuichi Oikawa ([email protected]). */ /* Registers that must be saved during a context switch. * These are the offsets from the beginning of the Thread object, * in bytes, used in switch.s */ #define SP (0*8) #define S0 (1*8) #define S1 (2*8) #define S2 (3*8) #define S3 (4*8) #define S4 (5*8) #define S5 (6*8) #define S6 (7*8) /* used as FP (Frame Pointer) */ #define GP (8*8) #define PC (9*8) /* To fork a thread, we set up its saved register state, so that * when we switch to the thread, it will start running in ThreadRoot. * * The following are the initial registers we need to set up to * pass values into ThreadRoot (for instance, containing the procedure * for the thread to run). The first set is the registers as used * by ThreadRoot; the second set is the locations for these initial * values in the Thread object -- used in Thread::StackAllocate(). */ #define InitialPC s0 #define InitialArg s1 #define WhenDonePC s2 #define StartupPC s3 #define PCState (PC/8-1) #define FPState (S6/8-1) #define InitialPCState (S0/8-1) #define InitialArgState (S1/8-1) #define WhenDonePCState (S2/8-1) #define StartupPCState (S3/8-1) #endif // HOST_ALPHA #endif // SWITCH_H

project4/nachos/code/threads/thread.cc

project4/nachos/code/threads/thread.cc

// thread.cc 
//  Routines to manage threads.  These are the main operations:
//
//  Fork -- create a thread to run a procedure concurrently
//      with the caller (this is done in two steps -- first
//      allocate the Thread object, then call Fork on it)
//  Begin -- called when the forked procedure starts up, to turn
//      interrupts on and clean up after last thread
//  Finish -- called when the forked procedure finishes, to clean up
//  Yield -- relinquish control over the CPU to another ready thread
//  Sleep -- relinquish control over the CPU, but thread is now blocked.
//      In other words, it will not run again, until explicitly 
//      put back on the ready queue.
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include   "copyright.h"
#include   "thread.h"
#include   "switch.h"
#include   "synch.h"
#include   "sysdep.h"

// this is put at the top of the execution stack, for detecting stack overflows
const   int  STACK_FENCEPOST  =   0xdedbeef ;

//----------------------------------------------------------------------
// Thread::Thread
//  Initialize a thread control block, so that we can then call
//  Thread::Fork.
//
//  "threadName" is an arbitrary string, useful for debugging.
//----------------------------------------------------------------------

Thread :: Thread ( char *  threadName )
{
    name  =  threadName ;
    stackTop  =  NULL ;
    stack  =  NULL ;
    status  =  JUST_CREATED ;
     for   ( int  i  =   0 ;  i  <   MachineStateSize ;  i ++ )   {
    machineState [ i ]   =  NULL ;       // not strictly necessary, since
                     // new thread ignores contents 
                     // of machine registers
     }
    space  =  NULL ;
}

//----------------------------------------------------------------------
// Thread::~Thread
//  De-allocate a thread.
//
//  NOTE: the current thread *cannot* delete itself directly,
//  since it is still running on the stack that we need to delete.
//
//      NOTE: if this is the main thread, we can't delete the stack
//      because we didn't allocate it -- we got it automatically
//      as part of starting up Nachos.
//----------------------------------------------------------------------

Thread ::~ Thread ()
{
    DEBUG ( dbgThread ,   "Deleting thread: "   <<  name );

    ASSERT ( this   !=  kernel -> currentThread );
     if   ( stack  !=  NULL )
     DeallocBoundedArray (( char   * )  stack ,   StackSize   *   sizeof ( int ));
}

//----------------------------------------------------------------------
// Thread::Fork
//  Invoke (*func)(arg), allowing caller and callee to execute 
//  concurrently.
//
//  NOTE: although our definition allows only a single argument
//  to be passed to the procedure, it is possible to pass multiple
//  arguments by making them fields of a structure, and passing a pointer
//  to the structure as "arg".
//
//  Implemented as the following steps:
//      1. Allocate a stack
//      2. Initialize the stack so that a call to SWITCH will
//      cause it to run the procedure
//      3. Put the thread on the ready queue
//  
//  "func" is the procedure to run concurrently.
//  "arg" is a single argument to be passed to the procedure.
//----------------------------------------------------------------------

void  
Thread :: Fork ( VoidFunctionPtr  func ,   void   * arg )
{
     Interrupt   * interrupt  =  kernel -> interrupt ;
     Scheduler   * scheduler  =  kernel -> scheduler ;
     IntStatus  oldLevel ;
    
    DEBUG ( dbgThread ,   "Forking thread: "   <<  name  <<   " f(a): "   <<   ( int )  func  <<   " "   <<  arg );
    
     StackAllocate ( func ,  arg );

    oldLevel  =  interrupt -> SetLevel ( IntOff );
    scheduler -> ReadyToRun ( this );      // ReadyToRun assumes that interrupts 
                     // are disabled!
     ( void )  interrupt -> SetLevel ( oldLevel );
}     

//----------------------------------------------------------------------
// Thread::CheckOverflow
//  Check a thread's stack to see if it has overrun the space
//  that has been allocated for it.  If we had a smarter compiler,
//  we wouldn't need to worry about this, but we don't.
//
//  NOTE: Nachos will not catch all stack overflow conditions.
//  In other words, your program may still crash because of an overflow.
//
//  If you get bizarre results (such as seg faults where there is no code)
//  then you *may* need to increase the stack size.  You can avoid stack
//  overflows by not putting large data structures on the stack.
//  Don't do this: void foo() { int bigArray[10000]; ... }
//----------------------------------------------------------------------

void
Thread :: CheckOverflow ()
{
     if   ( stack  !=  NULL )   {
#ifdef  HPUX          // Stacks grow upward on the Snakes
    ASSERT ( stack [ StackSize   -   1 ]   ==  STACK_FENCEPOST );
#else
    ASSERT ( * stack  ==  STACK_FENCEPOST );
#endif
    }
}

//----------------------------------------------------------------------
// Thread::Begin
//  Called by ThreadRoot when a thread is about to begin
//  executing the forked procedure.
//
//  It's main responsibilities are:
//  1. deallocate the previously running thread if it finished 
//      (see Thread::Finish())
//  2. enable interrupts (so we can get time-sliced)
//----------------------------------------------------------------------

void
Thread :: Begin   ()
{
    ASSERT ( this   ==  kernel -> currentThread );
    DEBUG ( dbgThread ,   "Beginning thread: "   <<  name );
    
    kernel -> scheduler -> CheckToBeDestroyed ();
    kernel -> interrupt -> Enable ();
}

//----------------------------------------------------------------------
// Thread::Finish
//  Called by ThreadRoot when a thread is done executing the 
//  forked procedure.
//
//  NOTE: we can't immediately de-allocate the thread data structure 
//  or the execution stack, because we're still running in the thread 
//  and we're still on the stack!  Instead, we tell the scheduler
//  to call the destructor, once it is running in the context of a different thread.
//
//  NOTE: we disable interrupts, because Sleep() assumes interrupts
//  are disabled.
//----------------------------------------------------------------------

//
void
Thread :: Finish   ()
{
     ( void )  kernel -> interrupt -> SetLevel ( IntOff );      
    ASSERT ( this   ==  kernel -> currentThread );
    
    DEBUG ( dbgThread ,   "Finishing thread: "   <<  name );
    
     Sleep ( TRUE );                  // invokes SWITCH
     // not reached
}

//----------------------------------------------------------------------
// Thread::Yield
//  Relinquish the CPU if any other thread is ready to run.
//  If so, put the thread on the end of the ready list, so that
//  it will eventually be re-scheduled.
//
//  NOTE: returns immediately if no other thread on the ready queue.
//  Otherwise returns when the thread eventually works its way
//  to the front of the ready list and gets re-scheduled.
//
//  NOTE: we disable interrupts, so that looking at the thread
//  on the front of the ready list, and switching to it, can be done
//  atomically.  On return, we re-set the interrupt level to its
//  original state, in case we are called with interrupts disabled. 
//
//  Similar to Thread::Sleep(), but a little different.
//----------------------------------------------------------------------

void
Thread :: Yield   ()
{
     Thread   * nextThread ;
     IntStatus  oldLevel  =  kernel -> interrupt -> SetLevel ( IntOff );
    
    ASSERT ( this   ==  kernel -> currentThread );
    
    DEBUG ( dbgThread ,   "Yielding thread: "   <<  name );
    
    nextThread  =  kernel -> scheduler -> FindNextToRun ();
     if   ( nextThread  !=  NULL )   {
    kernel -> scheduler -> ReadyToRun ( this );
    kernel -> scheduler -> Run ( nextThread ,  FALSE );
     }
     ( void )  kernel -> interrupt -> SetLevel ( oldLevel );
}

//----------------------------------------------------------------------
// Thread::Sleep
//  Relinquish the CPU, because the current thread has either
//  finished or is blocked waiting on a synchronization 
//  variable (Semaphore, Lock, or Condition).  In the latter case,
//  eventually some thread will wake this thread up, and put it
//  back on the ready queue, so that it can be re-scheduled.
//
//  NOTE: if there are no threads on the ready queue, that means
//  we have no thread to run.  "Interrupt::Idle" is called
//  to signify that we should idle the CPU until the next I/O interrupt
//  occurs (the only thing that could cause a thread to become
//  ready to run).
//
//  NOTE: we assume interrupts are already disabled, because it
//  is called from the synchronization routines which must
//  disable interrupts for atomicity.   We need interrupts off 
//  so that there can't be a time slice between pulling the first thread
//  off the ready list, and switching to it.
//----------------------------------------------------------------------
void
Thread :: Sleep   ( bool  finishing )
{
     Thread   * nextThread ;
    
    ASSERT ( this   ==  kernel -> currentThread );
    ASSERT ( kernel -> interrupt -> getLevel ()   ==   IntOff );
    
    DEBUG ( dbgThread ,   "Sleeping thread: "   <<  name );

    status  =  BLOCKED ;
     while   (( nextThread  =  kernel -> scheduler -> FindNextToRun ())   ==  NULL )
    kernel -> interrupt -> Idle ();    // no one to run, wait for an interrupt
    
     // returns when it's time for us to run
    kernel -> scheduler -> Run ( nextThread ,  finishing );  
}

//----------------------------------------------------------------------
// ThreadBegin, ThreadFinish,  ThreadPrint
//  Dummy functions because C++ does not (easily) allow pointers to member
//  functions.  So we create a dummy C function
//  (which we can pass a pointer to), that then simply calls the 
//  member function.
//----------------------------------------------------------------------

static   void   ThreadFinish ()      {  kernel -> currentThread -> Finish ();   }
static   void   ThreadBegin ()   {  kernel -> currentThread -> Begin ();   }
void   ThreadPrint ( Thread   * t )   {  t -> Print ();   }

#ifdef  PARISC

//----------------------------------------------------------------------
// PLabelToAddr
//  On HPUX, function pointers don't always directly point to code,
//  so we need to do the conversion.
//----------------------------------------------------------------------

static   void   *
PLabelToAddr ( void   * plabel )
{
     int  funcPtr  =   ( int )  plabel ;

     if   ( funcPtr  &   0x02 )   {
         // L-Field is set.  This is a PLT pointer
        funcPtr  -=   2 ;     // Get rid of the L bit
         return   ( * ( void   ** ) funcPtr );
     }   else   {
         // L-field not set.
         return  plabel ;
     }
}
#endif

//----------------------------------------------------------------------
// Thread::StackAllocate
//  Allocate and initialize an execution stack.  The stack is
//  initialized with an initial stack frame for ThreadRoot, which:
//      enables interrupts
//      calls (*func)(arg)
//      calls Thread::Finish
//
//  "func" is the procedure to be forked
//  "arg" is the parameter to be passed to the procedure
//----------------------------------------------------------------------

void
Thread :: StackAllocate   ( VoidFunctionPtr  func ,   void   * arg )
{
    stack  =   ( int   * )   AllocBoundedArray ( StackSize   *   sizeof ( int ));

#ifdef  PARISC
     // HP stack works from low addresses to high addresses
     // everyone else works the other way: from high addresses to low addresses
    stackTop  =  stack  +   16 ;    // HP requires 64-byte frame marker
    stack [ StackSize   -   1 ]   =  STACK_FENCEPOST ;
#endif

#ifdef  SPARC
    stackTop  =  stack  +   StackSize   -   96 ;    // SPARC stack must contains at 
                     // least 1 activation record 
                     // to start with.
     * stack  =  STACK_FENCEPOST ;
#endif  

#ifdef   PowerPC   // RS6000
    stackTop  =  stack  +   StackSize   -   16 ;    // RS6000 requires 64-byte frame marker
     * stack  =  STACK_FENCEPOST ;
#endif  

#ifdef  DECMIPS
    stackTop  =  stack  +   StackSize   -   4 ;     // -4 to be on the safe side!
     * stack  =  STACK_FENCEPOST ;
#endif

#ifdef  ALPHA
    stackTop  =  stack  +   StackSize   -   8 ;     // -8 to be on the safe side!
     * stack  =  STACK_FENCEPOST ;
#endif


#ifdef  x86
     // the x86 passes the return address on the stack.  In order for SWITCH() 
     // to go to ThreadRoot when we switch to this thread, the return addres 
     // used in SWITCH() must be the starting address of ThreadRoot.
    stackTop  =  stack  +   StackSize   -   4 ;     // -4 to be on the safe side!
     * ( -- stackTop )   =   ( int )   ThreadRoot ;
     * stack  =  STACK_FENCEPOST ;
#endif
    
#ifdef  PARISC
    machineState [ PCState ]   =   PLabelToAddr ( ThreadRoot );
    machineState [ StartupPCState ]   =   PLabelToAddr ( ThreadBegin );
    machineState [ InitialPCState ]   =   PLabelToAddr ( func );
    machineState [ InitialArgState ]   =  arg ;
    machineState [ WhenDonePCState ]   =   PLabelToAddr ( ThreadFinish );
#else
    machineState [ PCState ]   =   ( void * ) ThreadRoot ;
    machineState [ StartupPCState ]   =   ( void * ) ThreadBegin ;
    machineState [ InitialPCState ]   =   ( void * ) func ;
    machineState [ InitialArgState ]   =   ( void * ) arg ;
    machineState [ WhenDonePCState ]   =   ( void * ) ThreadFinish ;
#endif
}

#include   "machine.h"

//----------------------------------------------------------------------
// Thread::SaveUserState
//  Save the CPU state of a user program on a context switch.
//
//  Note that a user program thread has *two* sets of CPU registers -- 
//  one for its state while executing user code, one for its state 
//  while executing kernel code.  This routine saves the former.
//----------------------------------------------------------------------

void
Thread :: SaveUserState ()
{
     for   ( int  i  =   0 ;  i  <   NumTotalRegs ;  i ++ )
    userRegisters [ i ]   =  kernel -> machine -> ReadRegister ( i );
}

//----------------------------------------------------------------------
// Thread::RestoreUserState
//  Restore the CPU state of a user program on a context switch.
//
//  Note that a user program thread has *two* sets of CPU registers -- 
//  one for its state while executing user code, one for its state 
//  while executing kernel code.  This routine restores the former.
//----------------------------------------------------------------------

void
Thread :: RestoreUserState ()
{
     for   ( int  i  =   0 ;  i  <   NumTotalRegs ;  i ++ )
    kernel -> machine -> WriteRegister ( i ,  userRegisters [ i ]);
}


//----------------------------------------------------------------------
// SimpleThread
//  Loop 5 times, yielding the CPU to another ready thread 
//  each iteration.
//
//  "which" is simply a number identifying the thread, for debugging
//  purposes.
//----------------------------------------------------------------------

static   void
SimpleThread ( int  which )
{
     int  num ;
    
     for   ( num  =   0 ;  num  <   5 ;  num ++ )   {
    cout  <<   "*** thread "   <<  which  <<   " looped "   <<  num  <<   " times\n" ;
        kernel -> currentThread -> Yield ();
     }
}

//----------------------------------------------------------------------
// Thread::SelfTest
//  Set up a ping-pong between two threads, by forking a thread 
//  to call SimpleThread, and then calling SimpleThread ourselves.
//----------------------------------------------------------------------

void
Thread :: SelfTest ()
{
    DEBUG ( dbgThread ,   "Entering Thread::SelfTest" );

     Thread   * =   new   Thread ( "forked thread" );

    t -> Fork (( VoidFunctionPtr )   SimpleThread ,   ( void   * )   1 );
    kernel -> currentThread -> Yield ();
     SimpleThread ( 0 );
}

project4/nachos/code/threads/kernel.cc

project4/nachos/code/threads/kernel.cc

// kernel.cc 
//  Initialization and cleanup routines for the Nachos kernel.
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include   "copyright.h"
#include   "debug.h"
#include   "main.h"
#include   "kernel.h"
#include   "sysdep.h"
#include   "synch.h"
#include   "synchlist.h"
#include   "libtest.h"
#include   "string.h"
#include   "synchconsole.h"
#include   "synchdisk.h"
#include   "post.h"

//----------------------------------------------------------------------
// Kernel::Kernel
//  Interpret command line arguments in order to determine flags 
//  for the initialization (see also comments in main.cc)  
//----------------------------------------------------------------------

Kernel :: Kernel ( int  argc ,   char   ** argv )
{
    randomSlice  =  FALSE ;  
    debugUserProg  =  FALSE ;
    consoleIn  =  NULL ;            // default is stdin
    consoleOut  =  NULL ;           // default is stdout
#ifndef  FILESYS_STUB
    formatFlag  =  FALSE ;
#endif
    reliability  =   1 ;              // network reliability, default is 1.0
    hostName  =   0 ;                 // machine id, also UNIX socket name
                                 // 0 is the default machine id
     for   ( int  i  =   1 ;  i  <  argc ;  i ++ )   {
         if   ( strcmp ( argv [ i ],   "-rs" )   ==   0 )   {
        ASSERT ( +   1   <  argc );
         RandomInit ( atoi ( argv [ +   1 ])); // initialize pseudo-random
                     // number generator
        randomSlice  =  TRUE ;
        i ++ ;
         }   else   if   ( strcmp ( argv [ i ],   "-s" )   ==   0 )   {
            debugUserProg  =  TRUE ;
     }   else   if   ( strcmp ( argv [ i ],   "-ci" )   ==   0 )   {
        ASSERT ( +   1   <  argc );
        consoleIn  =  argv [ +   1 ];
        i ++ ;
     }   else   if   ( strcmp ( argv [ i ],   "-co" )   ==   0 )   {
        ASSERT ( +   1   <  argc );
        consoleOut  =  argv [ +   1 ];
        i ++ ;
#ifndef  FILESYS_STUB
     }   else   if   ( strcmp ( argv [ i ],   "-f" )   ==   0 )   {
        formatFlag  =  TRUE ;
#endif
         }   else   if   ( strcmp ( argv [ i ],   "-n" )   ==   0 )   {
            ASSERT ( +   1   <  argc );     // next argument is float
            reliability  =  atof ( argv [ +   1 ]);
            i ++ ;
         }   else   if   ( strcmp ( argv [ i ],   "-m" )   ==   0 )   {
            ASSERT ( +   1   <  argc );     // next argument is int
            hostName  =  atoi ( argv [ +   1 ]);
            i ++ ;
         }   else   if   ( strcmp ( argv [ i ],   "-u" )   ==   0 )   {
            cout  <<   "Partial usage: nachos [-rs randomSeed]\n" ;
        cout  <<   "Partial usage: nachos [-s]\n" ;
            cout  <<   "Partial usage: nachos [-ci consoleIn] [-co consoleOut]\n" ;
#ifndef  FILESYS_STUB
        cout  <<   "Partial usage: nachos [-nf]\n" ;
#endif
            cout  <<   "Partial usage: nachos [-n #] [-m #]\n" ;
     }
     }
}

//----------------------------------------------------------------------
// Kernel::Initialize
//  Initialize Nachos global data structures.  Separate from the 
//  constructor because some of these refer to earlier initialized
//  data via the "kernel" global variable.
//----------------------------------------------------------------------

void
Kernel :: Initialize ()
{
     // We didn't explicitly allocate the current thread we are running in.
     // But if it ever tries to give up the CPU, we better have a Thread
     // object to save its state. 
    currentThread  =   new   Thread ( "main" );      
    currentThread -> setStatus ( RUNNING );

    stats  =   new   Statistics ();         // collect statistics
    interrupt  =   new   Interrupt ;        // start up interrupt handling
    scheduler  =   new   Scheduler ();      // initialize the ready queue
    alarm  =   new   Alarm ( randomSlice );   // start up time slicing
    machine  =   new   Machine ( debugUserProg );
    synchConsoleIn  =   new   SynchConsoleInput ( consoleIn );   // input from stdin
    synchConsoleOut  =   new   SynchConsoleOutput ( consoleOut );   // output to stdout
    synchDisk  =   new   SynchDisk ();      //
#ifdef  FILESYS_STUB
    fileSystem  =   new   FileSystem ();
#else
    fileSystem  =   new   FileSystem ( formatFlag );
#endif   // FILESYS_STUB
    postOfficeIn  =   new   PostOfficeInput ( 10 );
    postOfficeOut  =   new   PostOfficeOutput ( reliability );

    interrupt -> Enable ();
}

//----------------------------------------------------------------------
// Kernel::~Kernel
//  Nachos is halting.  De-allocate global data structures.
//----------------------------------------------------------------------

Kernel ::~ Kernel ()
{
     delete  stats ;
     delete  interrupt ;
     delete  scheduler ;
     delete  alarm ;
     delete  machine ;
     delete  synchConsoleIn ;
     delete  synchConsoleOut ;
     delete  synchDisk ;
     delete  fileSystem ;
     delete  postOfficeIn ;
     delete  postOfficeOut ;
    
     Exit ( 0 );
}

//----------------------------------------------------------------------
// Kernel::ThreadSelfTest
//      Test threads, semaphores, synchlists
//----------------------------------------------------------------------

void
Kernel :: ThreadSelfTest ()   {
    Semaphore   * semaphore ;
    SynchList < int >   * synchList ;
   
    LibSelfTest ();         // test library routines
   currentThread -> SelfTest ();     // test thread switching
   
                 // test semaphore operation
   semaphore  =   new   Semaphore ( "test" ,   0 );
   semaphore -> SelfTest ();
    delete  semaphore ;
   
                 // test locks, condition variables
                 // using synchronized lists
   synchList  =   new   SynchList < int > ;
   synchList -> SelfTest ( 9 );
    delete  synchList ;

}

//----------------------------------------------------------------------
// Kernel::ConsoleTest
//      Test the synchconsole
//----------------------------------------------------------------------

void
Kernel :: ConsoleTest ()   {
     char  ch ;

    cout  <<   "Testing the console device.\n"  
         <<   "Typed characters will be echoed, until ^D is typed.\n"
         <<   "Note newlines are needed to flush input through UNIX.\n" ;
    cout . flush ();

     do   {
        ch  =  synchConsoleIn -> GetChar ();
         if ( ch  !=  EOF )  synchConsoleOut -> PutChar ( ch );     // echo it!
     }   while   ( ch  !=  EOF );

    cout  <<   "\n" ;

}

//----------------------------------------------------------------------
// Kernel::NetworkTest
//      Test whether the post office is working. On machines #0 and #1, do:
//
//      1. send a message to the other machine at mail box #0
//      2. wait for the other machine's message to arrive (in our mailbox #0)
//      3. send an acknowledgment for the other machine's message
//      4. wait for an acknowledgement from the other machine to our 
//          original message
//
//  This test works best if each Nachos machine has its own window
//----------------------------------------------------------------------

void
Kernel :: NetworkTest ()   {

     if   ( hostName  ==   0   ||  hostName  ==   1 )   {
         // if we're machine 1, send to 0 and vice versa
         int  farHost  =   ( hostName  ==   0   ?   1   :   0 );  
         PacketHeader  outPktHdr ,  inPktHdr ;
         MailHeader  outMailHdr ,  inMailHdr ;
         char   * data  =   "Hello there!" ;
         char   * ack  =   "Got it!" ;
         char  buffer [ MaxMailSize ];

         // construct packet, mail header for original message
         // To: destination machine, mailbox 0
         // From: our machine, reply to: mailbox 1
        outPktHdr . to  =  farHost ;          
        outMailHdr . to  =   0 ;
        outMailHdr . from  =   1 ;
        outMailHdr . length  =  strlen ( data )   +   1 ;

         // Send the first message
        postOfficeOut -> Send ( outPktHdr ,  outMailHdr ,  data );  

         // Wait for the first message from the other machine
        postOfficeIn -> Receive ( 0 ,   & inPktHdr ,   & inMailHdr ,  buffer );
        cout  <<   "Got: "   <<  buffer  <<   " : from "   <<  inPktHdr . from  <<   ", box "  
                                                 <<  inMailHdr . from  <<   "\n" ;
        cout . flush ();

         // Send acknowledgement to the other machine (using "reply to" mailbox
         // in the message that just arrived
        outPktHdr . to  =  inPktHdr . from ;
        outMailHdr . to  =  inMailHdr . from ;
        outMailHdr . length  =  strlen ( ack )   +   1 ;
        postOfficeOut -> Send ( outPktHdr ,  outMailHdr ,  ack );  

         // Wait for the ack from the other machine to the first message we sent
    postOfficeIn -> Receive ( 1 ,   & inPktHdr ,   & inMailHdr ,  buffer );
        cout  <<   "Got: "   <<  buffer  <<   " : from "   <<  inPktHdr . from  <<   ", box "  
                                                 <<  inMailHdr . from  <<   "\n" ;
        cout . flush ();
     }

     // Then we're done!
}

project4/nachos/code/machine/console.h

// console.h // Data structures to simulate the behavior of a terminal // I/O device. A terminal has two parts -- a keyboard input, // and a display output, each of which produces/accepts // characters sequentially. // // The console hardware device is asynchronous. When a character is // written to the device, the routine returns immediately, and an // interrupt handler is called later when the I/O completes. // For reads, an interrupt handler is called when a character arrives. // // In either case, the serial line connecting the computer // to the console has limited bandwidth (like a modem!), and so // each character takes measurable time. // // The user of the device registers itself to be called "back" when // the read/write interrupts occur. There is a separate interrupt // for read and write, and the device is "duplex" -- a character // can be outgoing and incoming at the same time. // // DO NOT CHANGE -- part of the machine emulation // // Copyright (c) 1992-1996 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef CONSOLE_H #define CONSOLE_H #include "copyright.h" #include "utility.h" #include "callback.h" // The following two classes define the input (and output) side of a // hardware console device. Input (and output) to the device is simulated // by reading (and writing) to the UNIX file "readFile" (and "writeFile"). // // Since input (and output) to the device is asynchronous, the interrupt // handler "callWhenAvail" is called when a character has arrived to be // read in (and "callWhenDone" is called when an output character has been // "put" so that the next character can be written). // // In practice, usually a single hardware thing that does both // serial input and serial output. But conceptually simpler to // use two objects. class ConsoleInput : public CallBackObj { public: ConsoleInput(char *readFile, CallBackObj *toCall); // initialize hardware console input ~ConsoleInput(); // clean up console emulation char GetChar(); // Poll the console input. If a char is // available, return it. Otherwise, return EOF. // "callWhenAvail" is called whenever there is // a char to be gotten void CallBack(); // Invoked when a character arrives // from the keyboard. private: int readFileNo; // UNIX file emulating the keyboard CallBackObj *callWhenAvail; // Interrupt handler to call when // there is a char to be read char incoming; // Contains the character to be read, // if there is one available. // Otherwise contains EOF. }; class ConsoleOutput : public CallBackObj { public: ConsoleOutput(char *writeFile, CallBackObj *toCall); // initialize hardware console output ~ConsoleOutput(); // clean up console emulation void PutChar(char ch); // Write "ch" to the console display, // and return immediately. "callWhenDone" // will called when the I/O completes. void CallBack(); // Invoked when next character can be put // out to the display. private: int writeFileNo; // UNIX file emulating the display CallBackObj *callWhenDone; // Interrupt handler to call when // the next char can be put bool putBusy; // Is a PutChar operation in progress? // If so, you can't do another one! }; #endif // CONSOLE_H

project4/nachos/code/machine/machine.h

// machine.h // Data structures for simulating the execution of user programs // running on top of Nachos. // // User programs are loaded into "mainMemory"; to Nachos, // this looks just like an array of bytes. Of course, the Nachos // kernel is in memory too -- but as in most machines these days, // the kernel is loaded into a separate memory region from user // programs, and accesses to kernel memory are not translated or paged. // // In Nachos, user programs are executed one instruction at a time, // by the simulator. Each memory reference is translated, checked // for errors, etc. // // DO NOT CHANGE EXCEPT AS NOTED BELOW -- part of the machine emulation // // Copyright (c) 1992-1996 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef MACHINE_H #define MACHINE_H #include "copyright.h" #include "utility.h" #include "translate.h" // Definitions related to the size, and format of user memory const int PageSize = 128; // set the page size equal to // the disk sector size, for simplicity // // You are allowed to change this value. // Doing so will change the number of pages of physical memory // available on the simulated machine. // const int NumPhysPages = 128; const int MemorySize = (NumPhysPages * PageSize); const int TLBSize = 4; // if there is a TLB, make it small enum ExceptionType { NoException, // Everything ok! SyscallException, // A program executed a system call. PageFaultException, // No valid translation found ReadOnlyException, // Write attempted to page marked // "read-only" BusErrorException, // Translation resulted in an // invalid physical address AddressErrorException, // Unaligned reference or one that // was beyond the end of the // address space OverflowException, // Integer overflow in add or sub. IllegalInstrException, // Unimplemented or reserved instr. NumExceptionTypes }; // User program CPU state. The full set of MIPS registers, plus a few // more because we need to be able to start/stop a user program between // any two instructions (thus we need to keep track of things like load // delay slots, etc.) #define StackReg 29 // User's stack pointer #define RetAddrReg 31 // Holds return address for procedure calls #define NumGPRegs 32 // 32 general purpose registers on MIPS #define HiReg 32 // Double register to hold multiply result #define LoReg 33 #define PCReg 34 // Current program counter #define NextPCReg 35 // Next program counter (for branch delay) #define PrevPCReg 36 // Previous program counter (for debugging) #define LoadReg 37 // The register target of a delayed load. #define LoadValueReg 38 // The value to be loaded by a delayed load. #define BadVAddrReg 39 // The failing virtual address on an exception #define NumTotalRegs 40 // The following class defines the simulated host workstation hardware, as // seen by user programs -- the CPU registers, main memory, etc. // User programs shouldn't be able to tell that they are running on our // simulator or on the real hardware, except // we don't support floating point instructions // the system call interface to Nachos is not the same as UNIX // (10 system calls in Nachos vs. 200 in UNIX!) // If we were to implement more of the UNIX system calls, we ought to be // able to run Nachos on top of Nachos! // // The procedures in this class are defined in machine.cc, mipssim.cc, and // translate.cc. class Instruction; class Interrupt; class Machine { public: Machine(bool debug); // Initialize the simulation of the hardware // for running user programs ~Machine(); // De-allocate the data structures // Routines callable by the Nachos kernel void Run(); // Run a user program int ReadRegister(int num); // read the contents of a CPU register void WriteRegister(int num, int value); // store a value into a CPU register // Data structures accessible to the Nachos kernel -- main memory and the // page table/TLB. // // Note that *all* communication between the user program and the kernel // are in terms of these data structures (plus the CPU registers). char *mainMemory; // physical memory to store user program, // code and data, while executing // NOTE: the hardware translation of virtual addresses in the user program // to physical addresses (relative to the beginning of "mainMemory") // can be controlled by one of: // a traditional linear page table // a software-loaded translation lookaside buffer (tlb) -- a cache of // mappings of virtual page #'s to physical page #'s // // If "tlb" is NULL, the linear page table is used // If "tlb" is non-NULL, the Nachos kernel is responsible for managing // the contents of the TLB. But the kernel can use any data structure // it wants (eg, segmented paging) for handling TLB cache misses. // // For simplicity, both the page table pointer and the TLB pointer are // public. However, while there can be multiple page tables (one per address // space, stored in memory), there is only one TLB (implemented in hardware). // Thus the TLB pointer should be considered as *read-only*, although // the contents of the TLB are free to be modified by the kernel software. TranslationEntry *tlb; // this pointer should be considered // "read-only" to Nachos kernel code TranslationEntry *pageTable; unsigned int pageTableSize; bool ReadMem(int addr, int size, int* value); bool WriteMem(int addr, int size, int value); // Read or write 1, 2, or 4 bytes of virtual // memory (at addr). Return FALSE if a // correct translation couldn't be found. private: // Routines internal to the machine simulation -- DO NOT call these directly void DelayedLoad(int nextReg, int nextVal); // Do a pending delayed load (modifying a reg) void OneInstruction(Instruction *instr); // Run one instruction of a user program. ExceptionType Translate(int virtAddr, int* physAddr, int size,bool writing); // Translate an address, and check for // alignment. Set the use and dirty bits in // the translation entry appropriately, // and return an exception code if the // translation couldn't be completed. void RaiseException(ExceptionType which, int badVAddr); // Trap to the Nachos kernel, because of a // system call or other exception. void Debugger(); // invoke the user program debugger void DumpState(); // print the user CPU and memory state // Internal data structures int registers[NumTotalRegs]; // CPU registers, for executing user programs bool singleStep; // drop back into the debugger after each // simulated instruction int runUntilTime; // drop back into the debugger when simulated // time reaches this value friend class Interrupt; // calls DelayedLoad() }; extern void ExceptionHandler(ExceptionType which); // Entry point into Nachos for handling // user system calls and exceptions // Defined in exception.cc // Routines for converting Words and Short Words to and from the // simulated machine's format of little endian. If the host machine // is little endian (DEC and Intel), these end up being NOPs. // // What is stored in each format: // host byte ordering: // kernel data structures // user registers // simulated machine byte ordering: // contents of main memory unsigned int WordToHost(unsigned int word); unsigned short ShortToHost(unsigned short shortword); unsigned int WordToMachine(unsigned int word); unsigned short ShortToMachine(unsigned short shortword); #endif // MACHINE_H

project4/nachos/code/machine/translate.h

// translate.h // Data structures for managing the translation from // virtual page # -> physical page #, used for managing // physical memory on behalf of user programs. // // The data structures in this file are "dual-use" - they // serve both as a page table entry, and as an entry in // a software-managed translation lookaside buffer (TLB). // Either way, each entry is of the form: // <virtual page #, physical page #>. // // DO NOT CHANGE -- part of the machine emulation // // Copyright (c) 1992-1993 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef TLB_H #define TLB_H #include "copyright.h" #include "utility.h" // The following class defines an entry in a translation table -- either // in a page table or a TLB. Each entry defines a mapping from one // virtual page to one physical page. // In addition, there are some extra bits for access control (valid and // read-only) and some bits for usage information (use and dirty). class TranslationEntry { public: int virtualPage; // The page number in virtual memory. int physicalPage; // The page number in real memory (relative to the // start of "mainMemory" bool valid; // If this bit is set, the translation is ignored. // (In other words, the entry hasn't been initialized.) bool readOnly; // If this bit is set, the user program is not allowed // to modify the contents of the page. bool use; // This bit is set by the hardware every time the // page is referenced or modified. bool dirty; // This bit is set by the hardware every time the // page is modified. }; #endif

project4/nachos/code/machine/machine.cc

project4/nachos/code/machine/machine.cc

// machine.cc 
//  Routines for simulating the execution of user programs.
//
//  DO NOT CHANGE -- part of the machine emulation
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include   "copyright.h"
#include   "machine.h"
#include   "main.h"

// Textual names of the exceptions that can be generated by user program
// execution, for debugging.
static   char *  exceptionNames []   =   {   "no exception" ,   "syscall" ,  
                 "page fault/no TLB entry" ,   "page read only" ,
                 "bus error" ,   "address error" ,   "overflow" ,
                 "illegal instruction"   };

//----------------------------------------------------------------------
// CheckEndian
//  Check to be sure that the host really uses the format it says it 
//  does, for storing the bytes of an integer.  Stop on error.
//----------------------------------------------------------------------

static
void   CheckEndian ()
{
     union  checkit  {
         char  charword [ 4 ];
         unsigned   int  intword ;
     }  check ;

    check . charword [ 0 ]   =   1 ;
    check . charword [ 1 ]   =   2 ;
    check . charword [ 2 ]   =   3 ;
    check . charword [ 3 ]   =   4 ;

#ifdef  HOST_IS_BIG_ENDIAN
    ASSERT  ( check . intword  ==   0x01020304 );
#else
    ASSERT  ( check . intword  ==   0x04030201 );
#endif
}

//----------------------------------------------------------------------
// Machine::Machine
//  Initialize the simulation of user program execution.
//
//  "debug" -- if TRUE, drop into the debugger after each user instruction
//      is executed.
//----------------------------------------------------------------------

Machine :: Machine ( bool  debug )
{
     int  i ;

     for   ( =   0 ;  i  <   NumTotalRegs ;  i ++ )
        registers [ i ]   =   0 ;
    mainMemory  =   new   char [ MemorySize ];
     for   ( =   0 ;  i  <   MemorySize ;  i ++ )
        mainMemory [ i ]   =   0 ;
#ifdef  USE_TLB
    tlb  =   new   TranslationEntry [ TLBSize ];
     for   ( =   0 ;  i  <   TLBSize ;  i ++ )
    tlb [ i ]. valid  =  FALSE ;
    pageTable  =  NULL ;
#else     // use linear page table
    tlb  =  NULL ;
    pageTable  =  NULL ;
#endif

    singleStep  =  debug ;
     CheckEndian ();
}

//----------------------------------------------------------------------
// Machine::~Machine
//  De-allocate the data structures used to simulate user program execution.
//----------------------------------------------------------------------

Machine ::~ Machine ()
{
     delete   []  mainMemory ;
     if   ( tlb  !=  NULL )
         delete   []  tlb ;
}

//----------------------------------------------------------------------
// Machine::RaiseException
//  Transfer control to the Nachos kernel from user mode, because
//  the user program either invoked a system call, or some exception
//  occured (such as the address translation failed).
//
//  "which" -- the cause of the kernel trap
//  "badVaddr" -- the virtual address causing the trap, if appropriate
//----------------------------------------------------------------------

void
Machine :: RaiseException ( ExceptionType  which ,   int  badVAddr )
{
    DEBUG ( dbgMach ,   "Exception: "   <<  exceptionNames [ which ]);
    
    registers [ BadVAddrReg ]   =  badVAddr ;
     DelayedLoad ( 0 ,   0 );            // finish anything in progress
    kernel -> interrupt -> setStatus ( SystemMode );
     ExceptionHandler ( which );          // interrupts are enabled at this point
    kernel -> interrupt -> setStatus ( UserMode );
}

//----------------------------------------------------------------------
// Machine::Debugger
//  Primitive debugger for user programs.  Note that we can't use
//  gdb to debug user programs, since gdb doesn't run on top of Nachos.
//  It could, but you'd have to implement *a lot* more system calls
//  to get it to work!
//
//  So just allow single-stepping, and printing the contents of memory.
//----------------------------------------------------------------------

void   Machine :: Debugger ()
{
     char   * buf  =   new   char [ 80 ];
     int  num ;
     bool  done  =  FALSE ;

    kernel -> interrupt -> DumpState ();
     DumpState ();
     while   ( ! done )   {
       // read commands until we should proceed with more execution
       // prompt for input, giving current simulation time in the prompt
      cout  <<  kernel -> stats -> totalTicks  <<   ">" ;
       // read one line of input (80 chars max)
      cin . get ( buf ,   80 );
       if   ( sscanf ( buf ,   "%d" ,   & num )   ==   1 )   {
    runUntilTime  =  num ;
    done  =  TRUE ;
       }
       else   {
    runUntilTime  =   0 ;
     switch   ( * buf )   {
     case   '\0' :
      done  =  TRUE ;
       break ;
     case   'c' :
      singleStep  =  FALSE ;
      done  =  TRUE ;
       break ;
     case   '?' :
      cout  <<   "Machine commands:\n" ;
      cout  <<   "    <return>  execute one instruction\n" ;
      cout  <<   "    <number>  run until the given timer tick\n" ;
      cout  <<   "    c         run until completion\n" ;
      cout  <<   "    ?         print help message\n" ;
       break ;
     default :
      cout  <<   "Unknown command: "   <<  buf  <<   "\n" ;
      cout  <<   "Type ? for help.\n" ;
     }
       }
       // consume the newline delimiter, which does not get
       // eaten by cin.get(buf,80) above.
      buf [ 0 ]   =  cin . get ();
     }
     delete   []  buf ;
}
 
//----------------------------------------------------------------------
// Machine::DumpState
//  Print the user program's CPU state.  We might print the contents
//  of memory, but that seemed like overkill.
//----------------------------------------------------------------------

void
Machine :: DumpState ()
{
     int  i ;
    
    cout  <<   "Machine registers:\n" ;
     for   ( =   0 ;  i  <   NumGPRegs ;  i ++ )   {
     switch   ( i )   {
       case   StackReg :
        cout  <<   "\tSP("   <<  i  <<   "):\t"   <<  registers [ i ];
         break ;
        
       case   RetAddrReg :
        cout  <<   "\tRA("   <<  i  <<   "):\t"   <<  registers [ i ];
         break ;
      
       default :
        cout  <<   "\t"   <<  i  <<   ":\t"   <<  registers [ i ];
         break ;
     }
     if   (( %   4 )   ==   3 )   {  cout  <<   "\n" ;   }
     }
    
    cout  <<   "\tHi:\t"   <<  registers [ HiReg ];
    cout  <<   "\tLo:\t"   <<  registers [ LoReg ];
    cout  <<   "\tPC:\t"   <<  registers [ PCReg ];
    cout  <<   "\tNextPC:\t"   <<  registers [ NextPCReg ];
    cout  <<   "\tPrevPC:\t"   <<  registers [ PrevPCReg ];
    cout  <<   "\tLoad:\t"   <<  registers [ LoadReg ];
    cout  <<   "\tLoadV:\t"   <<  registers [ LoadValueReg ]   <<   "\n" ;
}

//----------------------------------------------------------------------
// Machine::ReadRegister/WriteRegister
//      Fetch or write the contents of a user program register.
//----------------------------------------------------------------------

int  
Machine :: ReadRegister ( int  num )
{
    ASSERT (( num  >=   0 )   &&   ( num  <   NumTotalRegs ));
     return  registers [ num ];
}

void  
Machine :: WriteRegister ( int  num ,   int   value )
{
    ASSERT (( num  >=   0 )   &&   ( num  <   NumTotalRegs ));
    registers [ num ]   =   value ;
}

project4/nachos/code/machine/network.cc

project4/nachos/code/machine/network.cc

// network.cc 
//  Routines to simulate a network interface, using UNIX sockets
//  to deliver packets between multiple invocations of nachos.
//
//  DO NOT CHANGE -- part of the machine emulation
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include   "copyright.h"
#include   "network.h"
#include   "main.h"

//-----------------------------------------------------------------------
// NetworkInput::NetworkInput
//  Initialize the simulation for the network input
//
//      "toCall" is the interrupt handler to call when packet arrives
//-----------------------------------------------------------------------

NetworkInput :: NetworkInput ( CallBackObj   * toCall )
{
     // set up the stuff to emulate asynchronous interrupts
    callWhenAvail  =  toCall ;
    packetAvail  =  FALSE ;
    inHdr . length  =   0 ;
    
    sock  =   OpenSocket ();
    sprintf ( sockName ,   "SOCKET_%d" ,  kernel -> hostName );
     AssignNameToSocket ( sockName ,  sock );        // Bind socket to a filename 
                          // in the current directory.

     // start polling for incoming packets
    kernel -> interrupt -> Schedule ( this ,   NetworkTime ,   NetworkRecvInt );
}

//-----------------------------------------------------------------------
// NetworkInput::NetworkInput
//  Deallocate the simulation for the network input
//      (basically, deallocate the input mailbox)
//-----------------------------------------------------------------------

NetworkInput ::~ NetworkInput ()
{
     CloseSocket ( sock );
     DeAssignNameToSocket ( sockName );
}

//-----------------------------------------------------------------------
// NetworkInput::CallBack
//  Simulator calls this when a packet may be available to
//  be read in from the simulated network.
//
//      First check to make sure packet is available & there's space to
//  pull it in.  Then invoke the "callBack" registered by whoever 
//  wants the packet.
//-----------------------------------------------------------------------

void
NetworkInput :: CallBack ()
{
     // schedule the next time to poll for a packet
    kernel -> interrupt -> Schedule ( this ,   NetworkTime ,   NetworkRecvInt );

     if   ( inHdr . length  !=   0 )    // do nothing if packet is already buffered
     return ;      
     if   ( ! PollSocket ( sock ))    // do nothing if no packet to be read
     return ;

     // otherwise, read packet in
     char   * buffer  =   new   char [ MaxWireSize ];
     ReadFromSocket ( sock ,  buffer ,   MaxWireSize );

     // divide packet into header and data
    inHdr  =   * ( PacketHeader   * ) buffer ;
    ASSERT (( inHdr . to  ==  kernel -> hostName )   &&   ( inHdr . length  <=   MaxPacketSize ));
    bcopy ( buffer  +   sizeof ( PacketHeader ),  inbox ,  inHdr . length );
     delete   []  buffer  ;

    DEBUG ( dbgNet ,   "Network received packet from "   <<  inHdr . from  <<   ", length "   <<  inHdr . length );
    kernel -> stats -> numPacketsRecvd ++ ;

     // tell post office that the packet has arrived
    callWhenAvail -> CallBack ();
}

//-----------------------------------------------------------------------
// NetworkInput::Receive
//  Read a packet, if one is buffered
//-----------------------------------------------------------------------

PacketHeader
NetworkInput :: Receive ( char *  data )
{
     PacketHeader  hdr  =  inHdr ;

    inHdr . length  =   0 ;
     if   ( hdr . length  !=   0 )   {
        bcopy ( inbox ,  data ,  hdr . length );
     }
     return  hdr ;
}

//-----------------------------------------------------------------------
// NetworkOutput::NetworkOutput
//  Initialize the simulation for sending network packets
//
//      "reliability" says whether we drop packets to emulate unreliable links
//      "toCall" is the interrupt handler to call when next packet can be sent
//-----------------------------------------------------------------------

NetworkOutput :: NetworkOutput ( double  reliability ,   CallBackObj   * toCall )
{
     if   ( reliability  <   0 )  chanceToWork  =   0 ;
     else   if   ( reliability  >   1 )  chanceToWork  =   1 ;
     else  chanceToWork  =  reliability ;

     // set up the stuff to emulate asynchronous interrupts
    callWhenDone  =  toCall ;
    sendBusy  =  FALSE ;
    sock  =   OpenSocket ();
}

//-----------------------------------------------------------------------
// NetworkOutput::~NetworkOutput
//  Deallocate the simulation for sending network packets
//-----------------------------------------------------------------------

NetworkOutput ::~ NetworkOutput ()
{
     CloseSocket ( sock );
}

//-----------------------------------------------------------------------
// NetworkOutput::CallBack
//  Called by simulator when another packet can be sent.
//-----------------------------------------------------------------------

void
NetworkOutput :: CallBack ()
{
    sendBusy  =  FALSE ;
    kernel -> stats -> numPacketsSent ++ ;
    callWhenDone -> CallBack ();
}

//-----------------------------------------------------------------------
// NetworkOutput::Send
//  Send a packet into the simulated network, to the destination in hdr.
//  Concatenate hdr and data, and schedule an interrupt to tell the user 
//  when the next packet can be sent 
//
//  Note we always pad out a packet to MaxWireSize before putting it into
//  the socket, because it's simpler at the receive end.
//-----------------------------------------------------------------------

void
NetworkOutput :: Send ( PacketHeader  hdr ,   char *  data )
{
     char  toName [ 32 ];

    sprintf ( toName ,   "SOCKET_%d" ,   ( int ) hdr . to );
    
    ASSERT (( sendBusy  ==  FALSE )   &&   ( hdr . length  >   0 )   &&  
     ( hdr . length  <=   MaxPacketSize )   &&   ( hdr . from  ==  kernel -> hostName ));
    DEBUG ( dbgNet ,   "Sending to addr "   <<  hdr . to  <<   ", length "   <<  hdr . length );

    kernel -> interrupt -> Schedule ( this ,   NetworkTime ,   NetworkSendInt );

     if   ( RandomNumber ()   %   100   >=  chanceToWork  *   100 )   {   // emulate a lost packet
    DEBUG ( dbgNet ,   "oops, lost it!" );
     return ;
     }

     // concatenate hdr and data into a single buffer, and send it out
     char   * buffer  =   new   char [ MaxWireSize ];
     * ( PacketHeader   * ) buffer  =  hdr ;
    bcopy ( data ,  buffer  +   sizeof ( PacketHeader ),  hdr . length );
     SendToSocket ( sock ,  buffer ,   MaxWireSize ,  toName );
     delete   []  buffer ;
}

project4/nachos/code/machine/disk.h

// disk.h // Data structures to emulate a physical disk. A physical disk // can accept (one at a time) requests to read/write a disk sector; // when the request is satisfied, the CPU gets an interrupt, and // the next request can be sent to the disk. // // Disk contents are preserved across machine crashes, but if // a file system operation (eg, create a file) is in progress when the // system shuts down, the file system may be corrupted. // // DO NOT CHANGE -- part of the machine emulation // // Copyright (c) 1992-1993 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef DISK_H #define DISK_H #include "copyright.h" #include "utility.h" #include "callback.h" // The following class defines a physical disk I/O device. The disk // has a single surface, split up into "tracks", and each track split // up into "sectors" (the same number of sectors on each track, and each // sector has the same number of bytes of storage). // // Addressing is by sector number -- each sector on the disk is given // a unique number: track * SectorsPerTrack + offset within a track. // // As with other I/O devices, the raw physical disk is an asynchronous device -- // requests to read or write portions of the disk return immediately, // and an interrupt is invoked later to signal that the operation completed. // // The physical disk is in fact simulated via operations on a UNIX file. // // To make life a little more realistic, the simulated time for // each operation reflects a "track buffer" -- RAM to store the contents // of the current track as the disk head passes by. The idea is that the // disk always transfers to the track buffer, in case that data is requested // later on. This has the benefit of eliminating the need for // "skip-sector" scheduling -- a read request which comes in shortly after // the head has passed the beginning of the sector can be satisfied more // quickly, because its contents are in the track buffer. Most // disks these days now come with a track buffer. // // The track buffer simulation can be disabled by compiling with -DNOTRACKBUF const int SectorSize = 128; // number of bytes per disk sector const int SectorsPerTrack = 32; // number of sectors per disk track const int NumTracks = 32; // number of tracks per disk const int NumSectors = (SectorsPerTrack * NumTracks); // total # of sectors per disk class Disk : public CallBackObj { public: Disk(CallBackObj *toCall); // Create a simulated disk. // Invoke toCall->CallBack() // when each request completes. ~Disk(); // Deallocate the disk. void ReadRequest(int sectorNumber, char* data); // Read/write an single disk sector. // These routines send a request to // the disk and return immediately. // Only one request allowed at a time! void WriteRequest(int sectorNumber, char* data); void CallBack(); // Invoked when disk request // finishes. In turn calls, callWhenDone. int ComputeLatency(int newSector, bool writing); // Return how long a request to // newSector will take: // (seek + rotational delay + transfer) private: int fileno; // UNIX file number for simulated disk char diskname[32]; // name of simulated disk's file CallBackObj *callWhenDone; // Invoke when any disk request finishes bool active; // Is a disk operation in progress? int lastSector; // The previous disk request int bufferInit; // When the track buffer started // being loaded int TimeToSeek(int newSector, int *rotate); // time to get to the new track int ModuloDiff(int to, int from); // # sectors between to and from void UpdateLast(int newSector); }; #endif // DISK_H

project4/nachos/code/machine/stats.cc

project4/nachos/code/machine/stats.cc

// stats.h 
//  Routines for managing statistics about Nachos performance.
//
// DO NOT CHANGE -- these stats are maintained by the machine emulation.
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include   "copyright.h"
#include   "debug.h"
#include   "stats.h"

//----------------------------------------------------------------------
// Statistics::Statistics
//  Initialize performance metrics to zero, at system startup.
//----------------------------------------------------------------------

Statistics :: Statistics ()
{
    totalTicks  =  idleTicks  =  systemTicks  =  userTicks  =   0 ;
    numDiskReads  =  numDiskWrites  =   0 ;
    numConsoleCharsRead  =  numConsoleCharsWritten  =   0 ;
    numPageFaults  =  numPacketsSent  =  numPacketsRecvd  =   0 ;
}

//----------------------------------------------------------------------
// Statistics::Print
//  Print performance metrics, when we've finished everything
//  at system shutdown.
//----------------------------------------------------------------------

void
Statistics :: Print ()
{
    cout  <<   "Ticks: total "   <<  totalTicks  <<   ", idle "   <<  idleTicks ;
        cout  <<   ", system "   <<  systemTicks  <<   ", user "   <<  userTicks  << "\n" ;
    cout  <<   "Disk I/O: reads "   <<  numDiskReads ;
        cout  <<   ", writes "   <<  numDiskWrites  <<   "\n" ;
        cout  <<   "Console I/O: reads "   <<  numConsoleCharsRead ;
    cout  <<   ", writes "   <<  numConsoleCharsWritten  <<   "\n" ;
    cout  <<   "Paging: faults "   <<  numPageFaults  <<   "\n" ;
    cout  <<   "Network I/O: packets received "   <<  numPacketsRecvd ;
        cout  <<   ", sent "   <<  numPacketsSent  <<   "\n" ;
}

project4/nachos/code/machine/timer.h

// timer.h // Data structures to emulate a hardware timer. // // A hardware timer generates a CPU interrupt every X milliseconds. // This means it can be used for implementing time-slicing, or for // having a thread go to sleep for a specific period of time. // // We emulate a hardware timer by scheduling an interrupt to occur // every time stats->totalTicks has increased by TimerTicks. // // In order to introduce some randomness into time-slicing, if "doRandom" // is set, then the interrupt comes after a random number of ticks. // // DO NOT CHANGE -- part of the machine emulation // // Copyright (c) 1992-1996 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef TIMER_H #define TIMER_H #include "copyright.h" #include "utility.h" #include "callback.h" // The following class defines a hardware timer. class Timer : public CallBackObj { public: Timer(bool doRandom, CallBackObj *toCall); // Initialize the timer, and callback to "toCall" // every time slice. virtual ~Timer() {} void Disable() { disable = TRUE; } // Turn timer device off, so it doesn't // generate any more interrupts. private: bool randomize; // set if we need to use a random timeout delay CallBackObj *callPeriodically; // call this every TimerTicks time units bool disable; // turn off the timer device after next // interrupt. void CallBack(); // called internally when the hardware // timer generates an interrupt void SetInterrupt(); // cause an interrupt to occur in the // the future after a fixed or random // delay }; #endif // TIMER_H

project4/nachos/code/machine/network.h

// network.h // Data structures to emulate a physical network connection. // The network provides the abstraction of ordered, unreliable, // fixed-size packet delivery to other machines on the network. // // You may note that the interface to the network is similar to // the console device -- both are full duplex channels. // // DO NOT CHANGE -- part of the machine emulation // // Copyright (c) 1992-1996 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef NETWORK_H #define NETWORK_H #include "copyright.h" #include "utility.h" #include "callback.h" // Network address -- uniquely identifies a machine. This machine's ID // is given on the command line. typedef int NetworkAddress; // The following class defines the network packet header. // The packet header is prepended to the data payload by the Network driver, // before the packet is sent over the wire. The format on the wire is: // packet header (PacketHeader) // data (containing MailHeader from the PostOffice!) class PacketHeader { public: NetworkAddress to; // Destination machine ID NetworkAddress from; // source machine ID unsigned length; // bytes of packet data, excluding the // packet header (but including the // MailHeader prepended by the post office) }; #define MaxWireSize 64 // largest packet that can go out on the wire #define MaxPacketSize (MaxWireSize - sizeof(struct PacketHeader)) // data "payload" of the largest packet // The following two classes defines a physical network device. The network // is capable of delivering fixed sized packets, in order but unreliably, // to other machines connected to the network. // // The "reliability" of the network can be specified to the constructor. // This number, between 0 and 1, is the chance that the network will lose // a packet. Note that you can change the seed for the random number // generator, by changing the arguments to RandomInit() in Initialize(). // The random number generator is used to choose which packets to drop. class NetworkInput : public CallBackObj{ public: NetworkInput(CallBackObj *toCall); // Allocate and initialize network input driver ~NetworkInput(); // De-allocate the network input driver data PacketHeader Receive(char* data); // Poll the network for incoming messages. // If there is a packet waiting, copy the // packet into "data" and return the header. // If no packet is waiting, return a header // with length 0. void CallBack(); // A packet may have arrived. private: int sock; // UNIX socket number for incoming packets char sockName[32]; // File name corresponding to UNIX socket CallBackObj *callWhenAvail; // Interrupt handler, signalling packet has // arrived. bool packetAvail; // Packet has arrived, can be pulled off of // network PacketHeader inHdr; // Information about arrived packet char inbox[MaxPacketSize]; // Data for arrived packet }; class NetworkOutput : public CallBackObj { public: NetworkOutput(double reliability, CallBackObj *toCall); // Allocate and initialize network output driver ~NetworkOutput(); // De-allocate the network input driver data void Send(PacketHeader hdr, char* data); // Send the packet data to a remote machine, // specified by "hdr". Returns immediately. // "callWhenDone" is invoked once the next // packet can be sent. Note that callWhenDone // is called whether or not the packet is // dropped, and note that the "from" field of // the PacketHeader is filled in automatically // by Send(). void CallBack(); // Interrupt handler, called when message is // sent private: int sock; // UNIX socket number for outgoing packets double chanceToWork; // Likelihood packet will be dropped CallBackObj *callWhenDone; // Interrupt handler, signalling next packet // can be sent. bool sendBusy; // Packet is being sent. }; #endif // NETWORK_H

project4/nachos/code/machine/timer.cc

project4/nachos/code/machine/timer.cc

// timer.cc 
//  Routines to emulate a hardware timer device.
//
//      A hardware timer generates a CPU interrupt every X milliseconds.
//      This means it can be used for implementing time-slicing.
//
//      We emulate a hardware timer by scheduling an interrupt to occur
//      every time stats->totalTicks has increased by TimerTicks.
//
//      In order to introduce some randomness into time-slicing, if "doRandom"
//      is set, then the interrupt is comes after a random number of ticks.
//
//  Remember -- nothing in here is part of Nachos.  It is just
//  an emulation for the hardware that Nachos is running on top of.
//
//  DO NOT CHANGE -- part of the machine emulation
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include   "copyright.h"
#include   "timer.h"
#include   "main.h"
#include   "sysdep.h"

//----------------------------------------------------------------------
// Timer::Timer
//      Initialize a hardware timer device.  Save the place to call
//  on each interrupt, and then arrange for the timer to start
//  generating interrupts.
//
//      "doRandom" -- if true, arrange for the interrupts to occur
//      at random, instead of fixed, intervals.
//      "toCall" is the interrupt handler to call when the timer expires.
//----------------------------------------------------------------------

Timer :: Timer ( bool  doRandom ,   CallBackObj   * toCall )
{
    randomize  =  doRandom ;
    callPeriodically  =  toCall ;
    disable  =  FALSE ;
     SetInterrupt ();
}

//----------------------------------------------------------------------
// Timer::CallBack
//      Routine called when interrupt is generated by the hardware 
//  timer device.  Schedule the next interrupt, and invoke the
//  interrupt handler.
//----------------------------------------------------------------------
void  
Timer :: CallBack ()  
{
     // invoke the Nachos interrupt handler for this device
    callPeriodically -> CallBack ();
    
     SetInterrupt ();   // do last, to let software interrupt handler
                 // decide if it wants to disable future interrupts
}

//----------------------------------------------------------------------
// Timer::SetInterrupt
//      Cause a timer interrupt to occur in the future, unless
//  future interrupts have been disabled.  The delay is either
//  fixed or random.
//----------------------------------------------------------------------

void
Timer :: SetInterrupt ()  
{
     if   ( ! disable )   {
        int  delay  =   TimerTicks ;
    
        if   ( randomize )   {
         delay  =   1   +   ( RandomNumber ()   %   ( TimerTicks   *   2 ));
         }
        // schedule the next timer device interrupt
       kernel -> interrupt -> Schedule ( this ,  delay ,   TimerInt );
     }
}

project4/nachos/code/machine/interrupt.cc

project4/nachos/code/machine/interrupt.cc

// interrupt.cc 
//  Routines to simulate hardware interrupts.
//
//  The hardware provides a routine (SetLevel) to enable or disable
//  interrupts.
//
//  In order to emulate the hardware, we need to keep track of all
//  interrupts the hardware devices would cause, and when they
//  are supposed to occur.  
//
//  This module also keeps track of simulated time.  Time advances
//  only when the following occur: 
//      interrupts are re-enabled
//      a user instruction is executed
//      there is nothing in the ready queue
//
//  DO NOT CHANGE -- part of the machine emulation
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include   "copyright.h"
#include   "interrupt.h"
#include   "main.h"

// String definitions for debugging messages

static   char   * intLevelNames []   =   {   "off" ,   "on" };
static   char   * intTypeNames []   =   {   "timer" ,   "disk" ,   "console write" ,  
             "console read" ,   "network send" ,  
             "network recv" };

//----------------------------------------------------------------------
// PendingInterrupt::PendingInterrupt
//  Initialize a hardware device interrupt that is to be scheduled 
//  to occur in the near future.
//
//  "callOnInt" is the object to call when the interrupt occurs
//  "time" is when (in simulated time) the interrupt is to occur
//  "kind" is the hardware device that generated the interrupt
//----------------------------------------------------------------------

PendingInterrupt :: PendingInterrupt ( CallBackObj   * callOnInt ,  
                     int  time ,   IntType  kind )
{
    callOnInterrupt  =  callOnInt ;
    when  =  time ;
    type  =  kind ;
}

//----------------------------------------------------------------------
// PendingCompare
//  Compare to interrupts based on which should occur first.
//----------------------------------------------------------------------

static   int
PendingCompare   ( PendingInterrupt   * x ,   PendingInterrupt   * y )
{
     if   ( x -> when  <  y -> when )   {   return   - 1 ;   }
     else   if   ( x -> when  >  y -> when )   {   return   1 ;   }
     else   {   return   0 ;   }
}

//----------------------------------------------------------------------
// Interrupt::Interrupt
//  Initialize the simulation of hardware device interrupts.
//  
//  Interrupts start disabled, with no interrupts pending, etc.
//----------------------------------------------------------------------

Interrupt :: Interrupt ()
{
    level  =   IntOff ;
    pending  =   new   SortedList < PendingInterrupt   *> ( PendingCompare );
    inHandler  =  FALSE ;
    yieldOnReturn  =  FALSE ;
    status  =   SystemMode ;
}

//----------------------------------------------------------------------
// Interrupt::~Interrupt
//  De-allocate the data structures needed by the interrupt simulation.
//----------------------------------------------------------------------

Interrupt ::~ Interrupt ()
{
     while   ( ! pending -> IsEmpty ())   {
     delete  pending -> RemoveFront ();
     }
     delete  pending ;
}

//----------------------------------------------------------------------
// Interrupt::ChangeLevel
//  Change interrupts to be enabled or disabled, without advancing 
//  the simulated time (normally, enabling interrupts advances the time).
//
//  Used internally.
//
//  "old" -- the old interrupt status
//  "now" -- the new interrupt status
//----------------------------------------------------------------------

void
Interrupt :: ChangeLevel ( IntStatus  old ,   IntStatus  now )
{
    level  =  now ;
    DEBUG ( dbgInt ,   "\tinterrupts: "   <<  intLevelNames [ old ]   <<   " -> "   <<  intLevelNames [ now ]);
}

//----------------------------------------------------------------------
// Interrupt::SetLevel
//  Change interrupts to be enabled or disabled, and if interrupts
//  are being enabled, advance simulated time by calling OneTick().
//
// Returns:
//  The old interrupt status.
// Parameters:
//  "now" -- the new interrupt status
//----------------------------------------------------------------------

IntStatus
Interrupt :: SetLevel ( IntStatus  now )
{
     IntStatus  old  =  level ;
    
     // interrupt handlers are prohibited from enabling interrupts
    ASSERT (( now  ==   IntOff )   ||   ( inHandler  ==  FALSE ));

     ChangeLevel ( old ,  now );            // change to new state
     if   (( now  ==   IntOn )   &&   ( old  ==   IntOff ))   {
     OneTick ();                // advance simulated time
     }
     return  old ;
}

//----------------------------------------------------------------------
// Interrupt::OneTick
//  Advance simulated time and check if there are any pending 
//  interrupts to be called. 
//
//  Two things can cause OneTick to be called:
//      interrupts are re-enabled
//      a user instruction is executed
//----------------------------------------------------------------------
void
Interrupt :: OneTick ()
{
     MachineStatus  oldStatus  =  status ;
     Statistics   * stats  =  kernel -> stats ;

// advance simulated time
     if   ( status  ==   SystemMode )   {
        stats -> totalTicks  +=   SystemTick ;
    stats -> systemTicks  +=   SystemTick ;
     }   else   {
    stats -> totalTicks  +=   UserTick ;
    stats -> userTicks  +=   UserTick ;
     }
    DEBUG ( dbgInt ,   "== Tick "   <<  stats -> totalTicks  <<   " ==" );

// check any pending interrupts are now ready to fire
     ChangeLevel ( IntOn ,   IntOff );   // first, turn off interrupts
                 // (interrupt handlers run with
                 // interrupts disabled)
     CheckIfDue ( FALSE );        // check for pending interrupts
     ChangeLevel ( IntOff ,   IntOn );   // re-enable interrupts
     if   ( yieldOnReturn )   {      // if the timer device handler asked 
                     // for a context switch, ok to do it now
    yieldOnReturn  =  FALSE ;
    status  =   SystemMode ;          // yield is a kernel routine
    kernel -> currentThread -> Yield ();
    status  =  oldStatus ;
     }
}

//----------------------------------------------------------------------
// Interrupt::YieldOnReturn
//  Called from within an interrupt handler, to cause a context switch
//  (for example, on a time slice) in the interrupted thread,
//  when the handler returns.
//
//  We can't do the context switch here, because that would switch
//  out the interrupt handler, and we want to switch out the 
//  interrupted thread.
//----------------------------------------------------------------------

void
Interrupt :: YieldOnReturn ()
{  
    ASSERT ( inHandler  ==  TRUE );   
    yieldOnReturn  =  TRUE ;  
}

//----------------------------------------------------------------------
// Interrupt::Idle
//  Routine called when there is nothing in the ready queue.
//
//  Since something has to be running in order to put a thread
//  on the ready queue, the only thing to do is to advance 
//  simulated time until the next scheduled hardware interrupt.
//
//  If there are no pending interrupts, stop.  There's nothing
//  more for us to do.
//----------------------------------------------------------------------
void
Interrupt :: Idle ()
{
    DEBUG ( dbgInt ,   "Machine idling; checking for interrupts." );
    status  =   IdleMode ;
     if   ( CheckIfDue ( TRUE ))   {   // check for any pending interrupts
    status  =   SystemMode ;
     return ;           // return in case there's now
                 // a runnable thread
     }

     // if there are no pending interrupts, and nothing is on the ready
     // queue, it is time to stop.   If the console or the network is 
     // operating, there are *always* pending interrupts, so this code
     // is not reached.  Instead, the halt must be invoked by the user program.

    DEBUG ( dbgInt ,   "Machine idle.  No interrupts to do." );
    cout  <<   "No threads ready or runnable, and no pending interrupts.\n" ;
    cout  <<   "Assuming the program completed.\n" ;
     Halt ();
}

//----------------------------------------------------------------------
// Interrupt::Halt
//  Shut down Nachos cleanly, printing out performance statistics.
//----------------------------------------------------------------------
void
Interrupt :: Halt ()
{
    cout  <<   "Machine halting!\n\n" ;
    kernel -> stats -> Print ();
     delete  kernel ;    // Never returns.
}

//----------------------------------------------------------------------
// Interrupt::Schedule
//  Arrange for the CPU to be interrupted when simulated time
//  reaches "now + when".
//
//  Implementation: just put it on a sorted list.
//
//  NOTE: the Nachos kernel should not call this routine directly.
//  Instead, it is only called by the hardware device simulators.
//
//  "toCall" is the object to call when the interrupt occurs
//  "fromNow" is how far in the future (in simulated time) the 
//       interrupt is to occur
//  "type" is the hardware device that generated the interrupt
//----------------------------------------------------------------------
void
Interrupt :: Schedule ( CallBackObj   * toCall ,   int  fromNow ,   IntType  type )
{
     int  when  =  kernel -> stats -> totalTicks  +  fromNow ;
     PendingInterrupt   * toOccur  =   new   PendingInterrupt ( toCall ,  when ,  type );

    DEBUG ( dbgInt ,   "Scheduling interrupt handler the "   <<  intTypeNames [ type ]   <<   " at time = "   <<  when );
    ASSERT ( fromNow  >   0 );

    pending -> Insert ( toOccur );
}

//----------------------------------------------------------------------
// Interrupt::CheckIfDue
//  Check if any interrupts are scheduled to occur, and if so, 
//  fire them off.
//
// Returns:
//  TRUE, if we fired off any interrupt handlers
// Params:
//  "advanceClock" -- if TRUE, there is nothing in the ready queue,
//      so we should simply advance the clock to when the next 
//      pending interrupt would occur (if any).
//----------------------------------------------------------------------
bool
Interrupt :: CheckIfDue ( bool  advanceClock )
{
     PendingInterrupt   * next ;
     Statistics   * stats  =  kernel -> stats ;

    ASSERT ( level  ==   IntOff );          // interrupts need to be disabled,
                     // to invoke an interrupt handler
     if   ( debug -> IsEnabled ( dbgInt ))   {
     DumpState ();
     }
     if   ( pending -> IsEmpty ())   {         // no pending interrupts
     return  FALSE ;    
     }        
    next  =  pending -> Front ();
     if   ( next -> when  >  stats -> totalTicks )   {
         if   ( ! advanceClock )   {          // not time yet
             return  FALSE ;
         }
         else   {                // advance the clock to next interrupt
        stats -> idleTicks  +=   ( next -> when  -  stats -> totalTicks );
        stats -> totalTicks  =  next -> when ;
         // UDelay(1000L); // rcgood - to stop nachos from spinning.
     }
     }

    DEBUG ( dbgInt ,   "Invoking interrupt handler for the " );
    DEBUG ( dbgInt ,  intTypeNames [ next -> type ]   <<   " at time "   <<  next -> when );

     if   ( kernel -> machine  !=  NULL )   {
        kernel -> machine -> DelayedLoad ( 0 ,   0 );
     }

    inHandler  =  TRUE ;
     do   {
        next  =  pending -> RemoveFront ();      // pull interrupt off list
        next -> callOnInterrupt -> CallBack (); // call the interrupt handler
     delete  next ;
     }   while   ( ! pending -> IsEmpty ()  
             &&   ( pending -> Front () -> when  <=  stats -> totalTicks ));
    inHandler  =  FALSE ;
     return  TRUE ;
}

//----------------------------------------------------------------------
// PrintPending
//  Print information about an interrupt that is scheduled to occur.
//  When, where, why, etc.
//----------------------------------------------------------------------

static   void
PrintPending   ( PendingInterrupt   * pending )
{
    cout  <<   "Interrupt handler " <<  intTypeNames [ pending -> type ];
    cout  <<   ", scheduled at "   <<  pending -> when ;
}

//----------------------------------------------------------------------
// DumpState
//  Print the complete interrupt state - the status, and all interrupts
//  that are scheduled to occur in the future.
//----------------------------------------------------------------------

void
Interrupt :: DumpState ()
{
    cout  <<   "Time: "   <<  kernel -> stats -> totalTicks ;
    cout  <<   ", interrupts "   <<  intLevelNames [ level ]   <<   "\n" ;
    cout  <<   "Pending interrupts:\n" ;
    pending -> Apply ( PrintPending );
    cout  <<   "\nEnd of pending interrupts\n" ;
}

project4/nachos/code/machine/interrupt.h

// interrupt.h // Data structures to emulate low-level interrupt hardware. // // The hardware provides a routine (SetLevel) to enable or disable // interrupts. // // In order to emulate the hardware, we need to keep track of all // interrupts the hardware devices would cause, and when they // are supposed to occur. // // This module also keeps track of simulated time. Time advances // only when the following occur: // interrupts are re-enabled // a user instruction is executed // there is nothing in the ready queue // // As a result, unlike real hardware, interrupts (and thus time-slice // context switches) cannot occur anywhere in the code where interrupts // are enabled, but rather only at those places in the code where // simulated time advances (so that it becomes time to invoke an // interrupt in the hardware simulation). // // NOTE: this means that incorrectly synchronized code may work // fine on this hardware simulation (even with randomized time slices), // but it wouldn't work on real hardware. // // DO NOT CHANGE -- part of the machine emulation // // Copyright (c) 1992-1996 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef INTERRUPT_H #define INTERRUPT_H #include "copyright.h" #include "list.h" #include "callback.h" // Interrupts can be disabled (IntOff) or enabled (IntOn) enum IntStatus { IntOff, IntOn }; // Nachos can be running kernel code (SystemMode), user code (UserMode), // or there can be no runnable thread, because the ready list // is empty (IdleMode). enum MachineStatus {IdleMode, SystemMode, UserMode}; // IntType records which hardware device generated an interrupt. // In Nachos, we support a hardware timer device, a disk, a console // display and keyboard, and a network. enum IntType { TimerInt, DiskInt, ConsoleWriteInt, ConsoleReadInt, NetworkSendInt, NetworkRecvInt}; // The following class defines an interrupt that is scheduled // to occur in the future. The internal data structures are // left public to make it simpler to manipulate. class PendingInterrupt { public: PendingInterrupt(CallBackObj *callOnInt, int time, IntType kind); // initialize an interrupt that will // occur in the future CallBackObj *callOnInterrupt;// The object (in the hardware device // emulator) to call when the interrupt occurs int when; // When the interrupt is supposed to fire IntType type; // for debugging }; // The following class defines the data structures for the simulation // of hardware interrupts. We record whether interrupts are enabled // or disabled, and any hardware interrupts that are scheduled to occur // in the future. class Interrupt { public: Interrupt(); // initialize the interrupt simulation ~Interrupt(); // de-allocate data structures IntStatus SetLevel(IntStatus level); // Disable or enable interrupts // and return previous setting. void Enable() { (void) SetLevel(IntOn); } // Enable interrupts. IntStatus getLevel() {return level;} // Return whether interrupts // are enabled or disabled void Idle(); // The ready queue is empty, roll // simulated time forward until the // next interrupt void Halt(); // quit and print out stats void YieldOnReturn(); // cause a context switch on return // from an interrupt handler MachineStatus getStatus() { return status; } void setStatus(MachineStatus st) { status = st; } // idle, kernel, user void DumpState(); // Print interrupt state // NOTE: the following are internal to the hardware simulation code. // DO NOT call these directly. I should make them "private", // but they need to be public since they are called by the // hardware device simulators. void Schedule(CallBackObj *callTo, int when, IntType type); // Schedule an interrupt to occur // at time "when". This is called // by the hardware device simulators. void OneTick(); // Advance simulated time private: IntStatus level; // are interrupts enabled or disabled? SortedList<PendingInterrupt *> *pending; // the list of interrupts scheduled // to occur in the future bool inHandler; // TRUE if we are running an interrupt handler bool yieldOnReturn; // TRUE if we are to context switch // on return from the interrupt handler MachineStatus status; // idle, kernel mode, user mode // these functions are internal to the interrupt simulation code bool CheckIfDue(bool advanceClock); // Check if any interrupts are supposed // to occur now, and if so, do them void ChangeLevel(IntStatus old, // SetLevel, without advancing the IntStatus now); // simulated time }; #endif // INTERRRUPT_H

project4/nachos/code/machine/disk.cc

project4/nachos/code/machine/disk.cc

// disk.cc 
//  Routines to simulate a physical disk device; reading and writing
//  to the disk is simulated as reading and writing to a UNIX file.
//  See disk.h for details about the behavior of disks (and
//  therefore about the behavior of this simulation).
//
//  Disk operations are asynchronous, so we have to invoke an interrupt
//  handler when the simulated operation completes.
//
//  DO NOT CHANGE -- part of the machine emulation
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include   "copyright.h"
#include   "disk.h"
#include   "debug.h"
#include   "sysdep.h"
#include   "main.h"

// We put a magic number at the front of the UNIX file representing the
// disk, to make it less likely we will accidentally treat a useful file 
// as a disk (which would probably trash the file's contents).

const   int   MagicNumber   =   0x456789ab ;
const   int   MagicSize   =   sizeof ( int );
const   int   DiskSize   =   ( MagicSize   +   ( NumSectors   *   SectorSize ));


//----------------------------------------------------------------------
// Disk::Disk()
//  Initialize a simulated disk.  Open the UNIX file (creating it
//  if it doesn't exist), and check the magic number to make sure it's 
//  ok to treat it as Nachos disk storage.
//
//  "toCall" -- object to call when disk read/write request completes
//----------------------------------------------------------------------

Disk :: Disk ( CallBackObj   * toCall )
{
     int  magicNum ;
     int  tmp  =   0 ;

    DEBUG ( dbgDisk ,   "Initializing the disk." );
    callWhenDone  =  toCall ;
    lastSector  =   0 ;
    bufferInit  =   0 ;
    
    sprintf ( diskname , "DISK_%d" , kernel -> hostName );
    fileno  =   OpenForReadWrite ( diskname ,  FALSE );
     if   ( fileno  >=   0 )   {            // file exists, check magic number 
     Read ( fileno ,   ( char   * )   & magicNum ,   MagicSize );
    ASSERT ( magicNum  ==   MagicNumber );
     }   else   {                  // file doesn't exist, create it
        fileno  =   OpenForWrite ( diskname );
    magicNum  =   MagicNumber ;   
     WriteFile ( fileno ,   ( char   * )   & magicNum ,   MagicSize );   // write magic number

     // need to write at end of file, so that reads will not return EOF
         Lseek ( fileno ,   DiskSize   -   sizeof ( int ),   0 );    
     WriteFile ( fileno ,   ( char   * ) & tmp ,   sizeof ( int ));   
     }
    active  =  FALSE ;
}

//----------------------------------------------------------------------
// Disk::~Disk()
//  Clean up disk simulation, by closing the UNIX file representing the
//  disk.
//----------------------------------------------------------------------

Disk ::~ Disk ()
{
     Close ( fileno );
}

//----------------------------------------------------------------------
// Disk::PrintSector()
//  Dump the data in a disk read/write request, for debugging.
//----------------------------------------------------------------------

static   void
PrintSector   ( bool  writing ,   int  sector ,   char   * data )
{
     int   * =   ( int   * )  data ;

     if   ( writing )
        cout  <<   "Writing sector: "   <<  sector  <<   "\n" ;  
     else
        cout  <<   "Reading sector: "   <<  sector  <<   "\n" ;  
     for   ( unsigned   int  i  =   0 ;  i  <   ( SectorSize / sizeof ( int ));  i ++ )   {
    cout  <<  p [ i ]   <<   " " ;
     }
    cout  <<   "\n" ;  
}

//----------------------------------------------------------------------
// Disk::ReadRequest/WriteRequest
//  Simulate a request to read/write a single disk sector
//     Do the read/write immediately to the UNIX file
//     Set up an interrupt handler to be called later,
//        that will notify the caller when the simulator says
//        the operation has completed.
//
//  Note that a disk only allows an entire sector to be read/written,
//  not part of a sector.
//
//  "sectorNumber" -- the disk sector to read/write
//  "data" -- the bytes to be written, the buffer to hold the incoming bytes
//----------------------------------------------------------------------

void
Disk :: ReadRequest ( int  sectorNumber ,   char *  data )
{
     int  ticks  =   ComputeLatency ( sectorNumber ,  FALSE );

    ASSERT ( ! active );                  // only one request at a time
    ASSERT (( sectorNumber  >=   0 )   &&   ( sectorNumber  <   NumSectors ));
    
    DEBUG ( dbgDisk ,   "Reading from sector "   <<  sectorNumber );
     Lseek ( fileno ,   SectorSize   *  sectorNumber  +   MagicSize ,   0 );
     Read ( fileno ,  data ,   SectorSize );
     if   ( debug -> IsEnabled ( 'd' ))
     PrintSector ( FALSE ,  sectorNumber ,  data );
    
    active  =  TRUE ;
     UpdateLast ( sectorNumber );
    kernel -> stats -> numDiskReads ++ ;
    kernel -> interrupt -> Schedule ( this ,  ticks ,   DiskInt );
}

void
Disk :: WriteRequest ( int  sectorNumber ,   char *  data )
{
     int  ticks  =   ComputeLatency ( sectorNumber ,  TRUE );

    ASSERT ( ! active );
    ASSERT (( sectorNumber  >=   0 )   &&   ( sectorNumber  <   NumSectors ));
    
    DEBUG ( dbgDisk ,   "Writing to sector "   <<  sectorNumber );
     Lseek ( fileno ,   SectorSize   *  sectorNumber  +   MagicSize ,   0 );
     WriteFile ( fileno ,  data ,   SectorSize );
     if   ( debug -> IsEnabled ( 'd' ))
     PrintSector ( TRUE ,  sectorNumber ,  data );
    
    active  =  TRUE ;
     UpdateLast ( sectorNumber );
    kernel -> stats -> numDiskWrites ++ ;
    kernel -> interrupt -> Schedule ( this ,  ticks ,   DiskInt );
}

//----------------------------------------------------------------------
// Disk::CallBack()
//  Called by the machine simulation when the disk interrupt occurs.
//----------------------------------------------------------------------

void
Disk :: CallBack   ()
{  
    active  =  FALSE ;
    callWhenDone -> CallBack ();
}

//----------------------------------------------------------------------
// Disk::TimeToSeek()
//  Returns how long it will take to position the disk head over the correct
//  track on the disk.  Since when we finish seeking, we are likely
//  to be in the middle of a sector that is rotating past the head,
//  we also return how long until the head is at the next sector boundary.
//  
//      Disk seeks at one track per SeekTime ticks (cf. stats.h)
//      and rotates at one sector per RotationTime ticks
//----------------------------------------------------------------------

int
Disk :: TimeToSeek ( int  newSector ,   int   * rotation )  
{
     int  newTrack  =  newSector  /   SectorsPerTrack ;
     int  oldTrack  =  lastSector  /   SectorsPerTrack ;
     int  seek  =  abs ( newTrack  -  oldTrack )   *   SeekTime ;
                 // how long will seek take?
     int  over  =   ( kernel -> stats -> totalTicks  +  seek )   %   RotationTime ;  
                 // will we be in the middle of a sector when
                 // we finish the seek?

     * rotation  =   0 ;
     if   ( over  >   0 )         // if so, need to round up to next full sector
     * rotation  =   RotationTime   -  over ;
     return  seek ;
}

//----------------------------------------------------------------------
// Disk::ModuloDiff()
//  Return number of sectors of rotational delay between target sector
//  "to" and current sector position "from"
//----------------------------------------------------------------------

int  
Disk :: ModuloDiff ( int  to ,   int  from )
{
     int  toOffset  =  to  %   SectorsPerTrack ;
     int  fromOffset  =  from  %   SectorsPerTrack ;

     return   (( toOffset  -  fromOffset )   +   SectorsPerTrack )   %   SectorsPerTrack ;
}

//----------------------------------------------------------------------
// Disk::ComputeLatency()
//  Return how long will it take to read/write a disk sector, from
//  the current position of the disk head.
//
//      Latency = seek time + rotational latency + transfer time
//      Disk seeks at one track per SeekTime ticks (cf. stats.h)
//      and rotates at one sector per RotationTime ticks
//
//      To find the rotational latency, we first must figure out where the 
//      disk head will be after the seek (if any).  We then figure out
//      how long it will take to rotate completely past newSector after 
//  that point.
//
//      The disk also has a "track buffer"; the disk continuously reads
//      the contents of the current disk track into the buffer.  This allows 
//      read requests to the current track to be satisfied more quickly.
//      The contents of the track buffer are discarded after every seek to 
//      a new track.
//----------------------------------------------------------------------

int
Disk :: ComputeLatency ( int  newSector ,   bool  writing )
{
     int  rotation ;
     int  seek  =   TimeToSeek ( newSector ,   & rotation );
     int  timeAfter  =  kernel -> stats -> totalTicks  +  seek  +  rotation ;

#ifndef  NOTRACKBUF   // turn this on if you don't want the track buffer stuff
     // check if track buffer applies
     if   (( writing  ==  FALSE )   &&   ( seek  ==   0 )  
         &&   ((( timeAfter  -  bufferInit )   /   RotationTime )  
                 >   ModuloDiff ( newSector ,  bufferInit  /   RotationTime )))   {
        DEBUG ( dbgDisk ,   "Request latency = "   <<   RotationTime );
     return   RotationTime ;   // time to transfer sector from the track buffer
     }
#endif

    rotation  +=   ModuloDiff ( newSector ,  timeAfter  /   RotationTime )   *   RotationTime ;

    DEBUG ( dbgDisk ,   "Request latency = "   <<   ( seek  +  rotation  +   RotationTime ));
     return ( seek  +  rotation  +   RotationTime );
}

//----------------------------------------------------------------------
// Disk::UpdateLast
//      Keep track of the most recently requested sector.  So we can know
//  what is in the track buffer.
//----------------------------------------------------------------------

void
Disk :: UpdateLast ( int  newSector )
{
     int  rotate ;
     int  seek  =   TimeToSeek ( newSector ,   & rotate );
    
     if   ( seek  !=   0 )
    bufferInit  =  kernel -> stats -> totalTicks  +  seek  +  rotate ;
    lastSector  =  newSector ;
    DEBUG ( dbgDisk ,   "Updating last sector = "   <<  lastSector  <<   " , "   <<  bufferInit );
}

project4/nachos/code/machine/mipssim.h

// mipssim.h // Internal data structures for simulating the MIPS instruction set. // // DO NOT CHANGE -- part of the machine emulation // // Copyright (c) 1992-1993 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef MIPSSIM_H #define MIPSSIM_H #include "copyright.h" /* * OpCode values. The names are straight from the MIPS * manual except for the following special ones: * * OP_UNIMP - means that this instruction is legal, but hasn't * been implemented in the simulator yet. * OP_RES - means that this is a reserved opcode (it isn't * supported by the architecture). */ #define OP_ADD 1 #define OP_ADDI 2 #define OP_ADDIU 3 #define OP_ADDU 4 #define OP_AND 5 #define OP_ANDI 6 #define OP_BEQ 7 #define OP_BGEZ 8 #define OP_BGEZAL 9 #define OP_BGTZ 10 #define OP_BLEZ 11 #define OP_BLTZ 12 #define OP_BLTZAL 13 #define OP_BNE 14 #define OP_DIV 16 #define OP_DIVU 17 #define OP_J 18 #define OP_JAL 19 #define OP_JALR 20 #define OP_JR 21 #define OP_LB 22 #define OP_LBU 23 #define OP_LH 24 #define OP_LHU 25 #define OP_LUI 26 #define OP_LW 27 #define OP_LWL 28 #define OP_LWR 29 #define OP_MFHI 31 #define OP_MFLO 32 #define OP_MTHI 34 #define OP_MTLO 35 #define OP_MULT 36 #define OP_MULTU 37 #define OP_NOR 38 #define OP_OR 39 #define OP_ORI 40 #define OP_RFE 41 #define OP_SB 42 #define OP_SH 43 #define OP_SLL 44 #define OP_SLLV 45 #define OP_SLT 46 #define OP_SLTI 47 #define OP_SLTIU 48 #define OP_SLTU 49 #define OP_SRA 50 #define OP_SRAV 51 #define OP_SRL 52 #define OP_SRLV 53 #define OP_SUB 54 #define OP_SUBU 55 #define OP_SW 56 #define OP_SWL 57 #define OP_SWR 58 #define OP_XOR 59 #define OP_XORI 60 #define OP_SYSCALL 61 #define OP_UNIMP 62 #define OP_RES 63 #define MaxOpcode 63 /* * Miscellaneous definitions: */ #define IndexToAddr(x) ((x) << 2) #define SIGN_BIT 0x80000000 #define R31 31 /* * The table below is used to translate bits 31:26 of the instruction * into a value suitable for the "opCode" field of a MemWord structure, * or into a special value for further decoding. */ #define SPECIAL 100 #define BCOND 101 #define IFMT 1 #define JFMT 2 #define RFMT 3 struct OpInfo { int opCode; /* Translated op code. */ int format; /* Format type (IFMT or JFMT or RFMT) */ }; static OpInfo opTable[] = { {SPECIAL, RFMT}, {BCOND, IFMT}, {OP_J, JFMT}, {OP_JAL, JFMT}, {OP_BEQ, IFMT}, {OP_BNE, IFMT}, {OP_BLEZ, IFMT}, {OP_BGTZ, IFMT}, {OP_ADDI, IFMT}, {OP_ADDIU, IFMT}, {OP_SLTI, IFMT}, {OP_SLTIU, IFMT}, {OP_ANDI, IFMT}, {OP_ORI, IFMT}, {OP_XORI, IFMT}, {OP_LUI, IFMT}, {OP_UNIMP, IFMT}, {OP_UNIMP, IFMT}, {OP_UNIMP, IFMT}, {OP_UNIMP, IFMT}, {OP_RES, IFMT}, {OP_RES, IFMT}, {OP_RES, IFMT}, {OP_RES, IFMT}, {OP_RES, IFMT}, {OP_RES, IFMT}, {OP_RES, IFMT}, {OP_RES, IFMT}, {OP_RES, IFMT}, {OP_RES, IFMT}, {OP_RES, IFMT}, {OP_RES, IFMT}, {OP_LB, IFMT}, {OP_LH, IFMT}, {OP_LWL, IFMT}, {OP_LW, IFMT}, {OP_LBU, IFMT}, {OP_LHU, IFMT}, {OP_LWR, IFMT}, {OP_RES, IFMT}, {OP_SB, IFMT}, {OP_SH, IFMT}, {OP_SWL, IFMT}, {OP_SW, IFMT}, {OP_RES, IFMT}, {OP_RES, IFMT}, {OP_SWR, IFMT}, {OP_RES, IFMT}, {OP_UNIMP, IFMT}, {OP_UNIMP, IFMT}, {OP_UNIMP, IFMT}, {OP_UNIMP, IFMT}, {OP_RES, IFMT}, {OP_RES, IFMT}, {OP_RES, IFMT}, {OP_RES, IFMT}, {OP_UNIMP, IFMT}, {OP_UNIMP, IFMT}, {OP_UNIMP, IFMT}, {OP_UNIMP, IFMT}, {OP_RES, IFMT}, {OP_RES, IFMT}, {OP_RES, IFMT}, {OP_RES, IFMT} }; /* * The table below is used to convert the "funct" field of SPECIAL * instructions into the "opCode" field of a MemWord. */ static int specialTable[] = { OP_SLL, OP_RES, OP_SRL, OP_SRA, OP_SLLV, OP_RES, OP_SRLV, OP_SRAV, OP_JR, OP_JALR, OP_RES, OP_RES, OP_SYSCALL, OP_UNIMP, OP_RES, OP_RES, OP_MFHI, OP_MTHI, OP_MFLO, OP_MTLO, OP_RES, OP_RES, OP_RES, OP_RES, OP_MULT, OP_MULTU, OP_DIV, OP_DIVU, OP_RES, OP_RES, OP_RES, OP_RES, OP_ADD, OP_ADDU, OP_SUB, OP_SUBU, OP_AND, OP_OR, OP_XOR, OP_NOR, OP_RES, OP_RES, OP_SLT, OP_SLTU, OP_RES, OP_RES, OP_RES, OP_RES, OP_RES, OP_RES, OP_RES, OP_RES, OP_RES, OP_RES, OP_RES, OP_RES, OP_RES, OP_RES, OP_RES, OP_RES, OP_RES, OP_RES, OP_RES, OP_RES }; // Stuff to help print out each instruction, for debugging enum RegType { NONE, RS, RT, RD, EXTRA }; struct OpString { char *format; // Printed version of instruction RegType args[3]; }; static struct OpString opStrings[] = { {"Shouldn't happen", {NONE, NONE, NONE}}, {"ADD r%d,r%d,r%d", {RD, RS, RT}}, {"ADDI r%d,r%d,%d", {RT, RS, EXTRA}}, {"ADDIU r%d,r%d,%d", {RT, RS, EXTRA}}, {"ADDU r%d,r%d,r%d", {RD, RS, RT}}, {"AND r%d,r%d,r%d", {RD, RS, RT}}, {"ANDI r%d,r%d,%d", {RT, RS, EXTRA}}, {"BEQ r%d,r%d,%d", {RS, RT, EXTRA}}, {"BGEZ r%d,%d", {RS, EXTRA, NONE}}, {"BGEZAL r%d,%d", {RS, EXTRA, NONE}}, {"BGTZ r%d,%d", {RS, EXTRA, NONE}}, {"BLEZ r%d,%d", {RS, EXTRA, NONE}}, {"BLTZ r%d,%d", {RS, EXTRA, NONE}}, {"BLTZAL r%d,%d", {RS, EXTRA, NONE}}, {"BNE r%d,r%d,%d", {RS, RT, EXTRA}}, {"Shouldn't happen", {NONE, NONE, NONE}}, {"DIV r%d,r%d", {RS, RT, NONE}}, {"DIVU r%d,r%d", {RS, RT, NONE}}, {"J %d", {EXTRA, NONE, NONE}}, {"JAL %d", {EXTRA, NONE, NONE}}, {"JALR r%d,r%d", {RD, RS, NONE}}, {"JR r%d,r%d", {RD, RS, NONE}}, {"LB r%d,%d(r%d)", {RT, EXTRA, RS}}, {"LBU r%d,%d(r%d)", {RT, EXTRA, RS}}, {"LH r%d,%d(r%d)", {RT, EXTRA, RS}}, {"LHU r%d,%d(r%d)", {RT, EXTRA, RS}}, {"LUI r%d,%d", {RT, EXTRA, NONE}}, {"LW r%d,%d(r%d)", {RT, EXTRA, RS}}, {"LWL r%d,%d(r%d)", {RT, EXTRA, RS}}, {"LWR r%d,%d(r%d)", {RT, EXTRA, RS}}, {"Shouldn't happen", {NONE, NONE, NONE}}, {"MFHI r%d", {RD, NONE, NONE}}, {"MFLO r%d", {RD, NONE, NONE}}, {"Shouldn't happen", {NONE, NONE, NONE}}, {"MTHI r%d", {RS, NONE, NONE}}, {"MTLO r%d", {RS, NONE, NONE}}, {"MULT r%d,r%d", {RS, RT, NONE}}, {"MULTU r%d,r%d", {RS, RT, NONE}}, {"NOR r%d,r%d,r%d", {RD, RS, RT}}, {"OR r%d,r%d,r%d", {RD, RS, RT}}, {"ORI r%d,r%d,%d", {RT, RS, EXTRA}}, {"RFE", {NONE, NONE, NONE}}, {"SB r%d,%d(r%d)", {RT, EXTRA, RS}}, {"SH r%d,%d(r%d)", {RT, EXTRA, RS}}, {"SLL r%d,r%d,%d", {RD, RT, EXTRA}}, {"SLLV r%d,r%d,r%d", {RD, RT, RS}}, {"SLT r%d,r%d,r%d", {RD, RS, RT}}, {"SLTI r%d,r%d,%d", {RT, RS, EXTRA}}, {"SLTIU r%d,r%d,%d", {RT, RS, EXTRA}}, {"SLTU r%d,r%d,r%d", {RD, RS, RT}}, {"SRA r%d,r%d,%d", {RD, RT, EXTRA}}, {"SRAV r%d,r%d,r%d", {RD, RT, RS}}, {"SRL r%d,r%d,%d", {RD, RT, EXTRA}}, {"SRLV r%d,r%d,r%d", {RD, RT, RS}}, {"SUB r%d,r%d,r%d", {RD, RS, RT}}, {"SUBU r%d,r%d,r%d", {RD, RS, RT}}, {"SW r%d,%d(r%d)", {RT, EXTRA, RS}}, {"SWL r%d,%d(r%d)", {RT, EXTRA, RS}}, {"SWR r%d,%d(r%d)", {RT, EXTRA, RS}}, {"XOR r%d,r%d,r%d", {RD, RS, RT}}, {"XORI r%d,r%d,%d", {RT, RS, EXTRA}}, {"SYSCALL", {NONE, NONE, NONE}}, {"Unimplemented", {NONE, NONE, NONE}}, {"Reserved", {NONE, NONE, NONE}} }; #endif // MIPSSIM_H

project4/nachos/code/machine/console.cc

project4/nachos/code/machine/console.cc

// console.cc 
//  Routines to simulate a serial port to a console device.
//  A console has input (a keyboard) and output (a display).
//  These are each simulated by operations on UNIX files.
//  The simulated device is asynchronous, so we have to invoke 
//  the interrupt handler (after a simulated delay), to signal that 
//  a byte has arrived and/or that a written byte has departed.
//
//  DO NOT CHANGE -- part of the machine emulation
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include   "copyright.h"
#include   "console.h"
#include   "main.h"

//----------------------------------------------------------------------
// ConsoleInput::ConsoleInput
//  Initialize the simulation of the input for a hardware console device.
//
//  "readFile" -- UNIX file simulating the keyboard (NULL -> use stdin)
//  "toCall" is the interrupt handler to call when a character arrives
//      from the keyboard
//----------------------------------------------------------------------

ConsoleInput :: ConsoleInput ( char   * readFile ,   CallBackObj   * toCall )
{
     if   ( readFile  ==  NULL )
    readFileNo  =   0 ;                   // keyboard = stdin
     else
        readFileNo  =   OpenForReadWrite ( readFile ,  TRUE );    // should be read-only

     // set up the stuff to emulate asynchronous interrupts
    callWhenAvail  =  toCall ;
    incoming  =  EOF ;

     // start polling for incoming keystrokes
    kernel -> interrupt -> Schedule ( this ,   ConsoleTime ,   ConsoleReadInt );
}

//----------------------------------------------------------------------
// ConsoleInput::~ConsoleInput
//  Clean up console input emulation
//----------------------------------------------------------------------

ConsoleInput ::~ ConsoleInput ()
{
     if   ( readFileNo  !=   0 )
     Close ( readFileNo );
}


//----------------------------------------------------------------------
// ConsoleInput::CallBack()
//  Simulator calls this when a character may be available to be
//  read in from the simulated keyboard (eg, the user typed something).
//
//  First check to make sure character is available.
//  Then invoke the "callBack" registered by whoever wants the character.
//----------------------------------------------------------------------

void
ConsoleInput :: CallBack ()
{
   char  c ;
   int  readCount ;

    ASSERT ( incoming  ==  EOF );
     if   ( ! PollFile ( readFileNo ))   {   // nothing to be read
         // schedule the next time to poll for a packet
        kernel -> interrupt -> Schedule ( this ,   ConsoleTime ,   ConsoleReadInt );
     }   else   {  
         // otherwise, try to read a character
        readCount  =   ReadPartial ( readFileNo ,   & c ,   sizeof ( char ));
     if   ( readCount  ==   0 )   {
        // this seems to happen at end of file, when the
        // console input is a regular file
        // don't schedule an interrupt, since there will never
        // be any more input
        // just do nothing....
     }
     else   {
       // save the character and notify the OS that
       // it is available
      ASSERT ( readCount  ==   sizeof ( char ));
      incoming  =  c ;
      kernel -> stats -> numConsoleCharsRead ++ ;
     }
    callWhenAvail -> CallBack ();
     }
}

//----------------------------------------------------------------------
// ConsoleInput::GetChar()
//  Read a character from the input buffer, if there is any there.
//  Either return the character, or EOF if none buffered.
//----------------------------------------------------------------------

char
ConsoleInput :: GetChar ()
{
    char  ch  =  incoming ;

    if   ( incoming  !=  EOF )   {     // schedule when next char will arrive
       kernel -> interrupt -> Schedule ( this ,   ConsoleTime ,   ConsoleReadInt );
    }
   incoming  =  EOF ;
    return  ch ;
}



//----------------------------------------------------------------------
// ConsoleOutput::ConsoleOutput
//  Initialize the simulation of the output for a hardware console device.
//
//  "writeFile" -- UNIX file simulating the display (NULL -> use stdout)
//  "toCall" is the interrupt handler to call when a write to 
//  the display completes.
//----------------------------------------------------------------------

ConsoleOutput :: ConsoleOutput ( char   * writeFile ,   CallBackObj   * toCall )
{
     if   ( writeFile  ==  NULL )
    writeFileNo  =   1 ;                  // display = stdout
     else
        writeFileNo  =   OpenForWrite ( writeFile );

    callWhenDone  =  toCall ;
    putBusy  =  FALSE ;
}

//----------------------------------------------------------------------
// ConsoleOutput::~ConsoleOutput
//  Clean up console output emulation
//----------------------------------------------------------------------

ConsoleOutput ::~ ConsoleOutput ()
{
     if   ( writeFileNo  !=   1 )
     Close ( writeFileNo );
}

//----------------------------------------------------------------------
// ConsoleOutput::CallBack()
//  Simulator calls this when the next character can be output to the
//  display.
//----------------------------------------------------------------------

void
ConsoleOutput :: CallBack ()
{
    putBusy  =  FALSE ;
    kernel -> stats -> numConsoleCharsWritten ++ ;
    callWhenDone -> CallBack ();
}

//----------------------------------------------------------------------
// ConsoleOutput::PutChar()
//  Write a character to the simulated display, schedule an interrupt 
//  to occur in the future, and return.
//----------------------------------------------------------------------

void
ConsoleOutput :: PutChar ( char  ch )
{
    ASSERT ( putBusy  ==  FALSE );
     WriteFile ( writeFileNo ,   & ch ,   sizeof ( char ));
    putBusy  =  TRUE ;
    kernel -> interrupt -> Schedule ( this ,   ConsoleTime ,   ConsoleWriteInt );
}

project4/nachos/code/machine/translate.cc

project4/nachos/code/machine/translate.cc

// translate.cc 
//  Routines to translate virtual addresses to physical addresses.
//  Software sets up a table of legal translations.  We look up
//  in the table on every memory reference to find the true physical
//  memory location.
//
// Two types of translation are supported here.
//
//  Linear page table -- the virtual page # is used as an index
//  into the table, to find the physical page #.
//
//  Translation lookaside buffer -- associative lookup in the table
//  to find an entry with the same virtual page #.  If found,
//  this entry is used for the translation.
//  If not, it traps to software with an exception. 
//
//  In practice, the TLB is much smaller than the amount of physical
//  memory (16 entries is common on a machine that has 1000's of
//  pages).  Thus, there must also be a backup translation scheme
//  (such as page tables), but the hardware doesn't need to know
//  anything at all about that.
//
//  Note that the contents of the TLB are specific to an address space.
//  If the address space changes, so does the contents of the TLB!
//
// DO NOT CHANGE -- part of the machine emulation
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include   "copyright.h"
#include   "main.h"

// Routines for converting Words and Short Words to and from the
// simulated machine's format of little endian.  These end up
// being NOPs when the host machine is also little endian (DEC and Intel).

unsigned   int
WordToHost ( unsigned   int  word )   {
#ifdef  HOST_IS_BIG_ENDIAN
      register   unsigned   long  result ;
     result  =   ( word  >>   24 )   &   0x000000ff ;
     result  |=   ( word  >>   8 )   &   0x0000ff00 ;
     result  |=   ( word  <<   8 )   &   0x00ff0000 ;
     result  |=   ( word  <<   24 )   &   0xff000000 ;
      return  result ;
#else  
      return  word ;
#endif   /* HOST_IS_BIG_ENDIAN */
}

unsigned   short
ShortToHost ( unsigned   short  shortword )   {
#ifdef  HOST_IS_BIG_ENDIAN
      register   unsigned   short  result ;
     result  =   ( shortword  <<   8 )   &   0xff00 ;
     result  |=   ( shortword  >>   8 )   &   0x00ff ;
      return  result ;
#else  
      return  shortword ;
#endif   /* HOST_IS_BIG_ENDIAN */
}

unsigned   int
WordToMachine ( unsigned   int  word )   {   return   WordToHost ( word );   }

unsigned   short
ShortToMachine ( unsigned   short  shortword )   {   return   ShortToHost ( shortword );   }


//----------------------------------------------------------------------
// Machine::ReadMem
//      Read "size" (1, 2, or 4) bytes of virtual memory at "addr" into 
//  the location pointed to by "value".
//
//      Returns FALSE if the translation step from virtual to physical memory
//      failed.
//
//  "addr" -- the virtual address to read from
//  "size" -- the number of bytes to read (1, 2, or 4)
//  "value" -- the place to write the result
//----------------------------------------------------------------------

bool
Machine :: ReadMem ( int  addr ,   int  size ,   int   * value )
{
     int  data ;
     ExceptionType  exception ;
     int  physicalAddress ;
    
    DEBUG ( dbgAddr ,   "Reading VA "   <<  addr  <<   ", size "   <<  size );
    
    exception  =   Translate ( addr ,   & physicalAddress ,  size ,  FALSE );
     if   ( exception  !=   NoException )   {
     RaiseException ( exception ,  addr );
     return  FALSE ;
     }
     switch   ( size )   {
       case   1 :
    data  =  mainMemory [ physicalAddress ];
     * value   =  data ;
     break ;
    
       case   2 :
    data  =   * ( unsigned   short   * )   & mainMemory [ physicalAddress ];
     * value   =   ShortToHost ( data );
     break ;
    
       case   4 :
    data  =   * ( unsigned   int   * )   & mainMemory [ physicalAddress ];
     * value   =   WordToHost ( data );
     break ;

       default :  ASSERT ( FALSE );
     }
    
    DEBUG ( dbgAddr ,   "\tvalue read = "   <<   * value );
     return   ( TRUE );
}

//----------------------------------------------------------------------
// Machine::WriteMem
//      Write "size" (1, 2, or 4) bytes of the contents of "value" into
//  virtual memory at location "addr".
//
//      Returns FALSE if the translation step from virtual to physical memory
//      failed.
//
//  "addr" -- the virtual address to write to
//  "size" -- the number of bytes to be written (1, 2, or 4)
//  "value" -- the data to be written
//----------------------------------------------------------------------

bool
Machine :: WriteMem ( int  addr ,   int  size ,   int   value )
{
     ExceptionType  exception ;
     int  physicalAddress ;
     
    DEBUG ( dbgAddr ,   "Writing VA "   <<  addr  <<   ", size "   <<  size  <<   ", value "   <<   value );

    exception  =   Translate ( addr ,   & physicalAddress ,  size ,  TRUE );
     if   ( exception  !=   NoException )   {
     RaiseException ( exception ,  addr );
     return  FALSE ;
     }
     switch   ( size )   {
       case   1 :
    mainMemory [ physicalAddress ]   =   ( unsigned   char )   ( value   &   0xff );
     break ;

       case   2 :
     * ( unsigned   short   * )   & mainMemory [ physicalAddress ]
         =   ShortToMachine (( unsigned   short )   ( value   &   0xffff ));
     break ;
      
       case   4 :
     * ( unsigned   int   * )   & mainMemory [ physicalAddress ]
         =   WordToMachine (( unsigned   int )   value );
     break ;
    
       default :  ASSERT ( FALSE );
     }
    
     return  TRUE ;
}

//----------------------------------------------------------------------
// Machine::Translate
//  Translate a virtual address into a physical address, using 
//  either a page table or a TLB.  Check for alignment and all sorts 
//  of other errors, and if everything is ok, set the use/dirty bits in 
//  the translation table entry, and store the translated physical 
//  address in "physAddr".  If there was an error, returns the type
//  of the exception.
//
//  "virtAddr" -- the virtual address to translate
//  "physAddr" -- the place to store the physical address
//  "size" -- the amount of memory being read or written
//  "writing" -- if TRUE, check the "read-only" bit in the TLB
//----------------------------------------------------------------------

ExceptionType
Machine :: Translate ( int  virtAddr ,   int *  physAddr ,   int  size ,   bool  writing )
{
     int  i ;
     unsigned   int  vpn ,  offset ;
     TranslationEntry   * entry ;
     unsigned   int  pageFrame ;

    DEBUG ( dbgAddr ,   "\tTranslate "   <<  virtAddr  <<   ( writing  ?   " , write"   :   " , read" ));

// check for alignment errors
     if   ((( size  ==   4 )   &&   ( virtAddr  &   0x3 ))   ||   (( size  ==   2 )   &&   ( virtAddr  &   0x1 ))){
    DEBUG ( dbgAddr ,   "Alignment problem at "   <<  virtAddr  <<   ", size "   <<  size );
     return   AddressErrorException ;
     }
    
     // we must have either a TLB or a page table, but not both!
    ASSERT ( tlb  ==  NULL  ||  pageTable  ==  NULL );    
    ASSERT ( tlb  !=  NULL  ||  pageTable  !=  NULL );    

// calculate the virtual page number, and offset within the page,
// from the virtual address
    vpn  =   ( unsigned )  virtAddr  /   PageSize ;
    offset  =   ( unsigned )  virtAddr  %   PageSize ;
    
     if   ( tlb  ==  NULL )   {        // => page table => vpn is index into table
     if   ( vpn  >=  pageTableSize )   {
        DEBUG ( dbgAddr ,   "Illegal virtual page # "   <<  virtAddr );
         return   AddressErrorException ;
     }   else   if   ( ! pageTable [ vpn ]. valid )   {
        DEBUG ( dbgAddr ,   "Invalid virtual page # "   <<  virtAddr );
         return   PageFaultException ;
     }
    entry  =   & pageTable [ vpn ];
     }   else   {
         for   ( entry  =  NULL ,  i  =   0 ;  i  <   TLBSize ;  i ++ )
             if   ( tlb [ i ]. valid  &&   ( tlb [ i ]. virtualPage  ==   (( int ) vpn )))   {
        entry  =   & tlb [ i ];              // FOUND!
         break ;
         }
     if   ( entry  ==  NULL )   {                  // not found
            DEBUG ( dbgAddr ,   "Invalid TLB entry for this virtual page!" );
             return   PageFaultException ;        // really, this is a TLB fault,
                         // the page may be in memory,
                         // but not in the TLB
     }
     }

     if   ( entry -> readOnly  &&  writing )   {     // trying to write to a read-only page
    DEBUG ( dbgAddr ,   "Write to read-only page at "   <<  virtAddr );
     return   ReadOnlyException ;
     }
    pageFrame  =  entry -> physicalPage ;

     // if the pageFrame is too big, there is something really wrong! 
     // An invalid translation was loaded into the page table or TLB. 
     if   ( pageFrame  >=   NumPhysPages )   {  
    DEBUG ( dbgAddr ,   "Illegal pageframe "   <<  pageFrame );
     return   BusErrorException ;
     }
    entry -> use  =  TRUE ;        // set the use, dirty bits
     if   ( writing )
    entry -> dirty  =  TRUE ;
     * physAddr  =  pageFrame  *   PageSize   +  offset ;
    ASSERT (( * physAddr  >=   0 )   &&   (( * physAddr  +  size )   <=   MemorySize ));
    DEBUG ( dbgAddr ,   "phys addr = "   <<   * physAddr );
     return   NoException ;
}

project4/nachos/code/machine/mipssim.cc

project4/nachos/code/machine/mipssim.cc

// mipssim.cc -- simulate a MIPS R2/3000 processor
//
//   This code has been adapted from Ousterhout's MIPSSIM package.
//   Byte ordering is little-endian, so we can be compatible with
//   DEC RISC systems.
//
//   DO NOT CHANGE -- part of the machine emulation
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

// Simulation fixes done by Peter E Reissner, class of Winter 1994/95 (York)
// I've not been able to test this extensively.
// Ported to newer version of Nachos at Waterloo by Scott Graham (Mar 99).


#include   "copyright.h"

#include   "debug.h"
#include   "machine.h"
#include   "mipssim.h"
#include   "main.h"

static   void   Mult ( int  a ,   int  b ,   bool  signedArith ,   int *  hiPtr ,   int *  loPtr );

// The following class defines an instruction, represented in both
//  undecoded binary form
//      decoded to identify
//      operation to do
//      registers to act on
//      any immediate operand value

class   Instruction   {
   public :
     void   Decode ();    // decode the binary representation of the instruction

     unsigned   int   value ;   // binary representation of the instruction

     char  opCode ;       // Type of instruction.  This is NOT the same as the
                  // opcode field from the instruction: see defs in mips.h
     char  rs ,  rt ,  rd ;   // Three registers from instruction.
     int  extra ;         // Immediate or target or shamt field or offset.
                      // Immediates are sign-extended.
};

//----------------------------------------------------------------------
// Machine::Run
//  Simulate the execution of a user-level program on Nachos.
//  Called by the kernel when the program starts up; never returns.
//
//  This routine is re-entrant, in that it can be called multiple
//  times concurrently -- one for each thread executing user code.
//----------------------------------------------------------------------

void
Machine :: Run ()
{
     Instruction   * instr  =   new   Instruction ;    // storage for decoded instruction

     if   ( debug -> IsEnabled ( 'm' ))   {
        cout  <<   "Starting program in thread: "   <<  kernel -> currentThread -> getName ();
    cout  <<   ", at time: "   <<  kernel -> stats -> totalTicks  <<   "\n" ;
     }
    kernel -> interrupt -> setStatus ( UserMode );
     for   (;;)   {
         OneInstruction ( instr );
    kernel -> interrupt -> OneTick ();
     if   ( singleStep  &&   ( runUntilTime  <=  kernel -> stats -> totalTicks ))
       Debugger ();
     }
}


//----------------------------------------------------------------------
// TypeToReg
//  Retrieve the register # referred to in an instruction. 
//----------------------------------------------------------------------

static   int  
TypeToReg ( RegType  reg ,   Instruction   * instr )
{
     switch   ( reg )   {
       case  RS :
     return  instr -> rs ;
       case  RT :
     return  instr -> rt ;
       case  RD :
     return  instr -> rd ;
       case  EXTRA :
     return  instr -> extra ;
       default :
     return   - 1 ;
     }
}

//----------------------------------------------------------------------
// Machine::OneInstruction
//  Execute one instruction from a user-level program
//
//  If there is any kind of exception or interrupt, we invoke the 
//  exception handler, and when it returns, we return to Run(), which
//  will re-invoke us in a loop.  This allows us to
//  re-start the instruction execution from the beginning, in
//  case any of our state has changed.  On a syscall,
//  the OS software must increment the PC so execution begins
//  at the instruction immediately after the syscall. 
//
//  This routine is re-entrant, in that it can be called multiple
//  times concurrently -- one for each thread executing user code.
//  We get re-entrancy by never caching any data -- we always re-start the
//  simulation from scratch each time we are called (or after trapping
//  back to the Nachos kernel on an exception or interrupt), and we always
//  store all data back to the machine registers and memory before
//  leaving.  This allows the Nachos kernel to control our behavior
//  by controlling the contents of memory, the translation table,
//  and the register set.
//----------------------------------------------------------------------

void
Machine :: OneInstruction ( Instruction   * instr )
{
#ifdef  SIM_FIX
     int  byte ;         // described in Kane for LWL,LWR,...
#endif

     int  raw ;
     int  nextLoadReg  =   0 ;     
     int  nextLoadValue  =   0 ;    // record delayed load operation, to apply
                 // in the future

     // Fetch instruction 
     if   ( ! ReadMem ( registers [ PCReg ],   4 ,   & raw ))
     return ;           // exception occurred
    instr -> value   =  raw ;
    instr -> Decode ();

     if   ( debug -> IsEnabled ( 'm' ))   {
         struct   OpString   * str  =   & opStrings [ instr -> opCode ];
     char  buf [ 80 ];

        ASSERT ( instr -> opCode  <=   MaxOpcode );
        cout  <<   "At PC = "   <<  registers [ PCReg ];
    sprintf ( buf ,  str -> format ,   TypeToReg ( str -> args [ 0 ],  instr ),
          TypeToReg ( str -> args [ 1 ],  instr ),   TypeToReg ( str -> args [ 2 ],  instr ));
        cout  <<   "\t"   <<  buf  <<   "\n" ;
     }
    
     // Compute next pc, but don't install in case there's an error or branch.
     int  pcAfter  =  registers [ NextPCReg ]   +   4 ;
     int  sum ,  diff ,  tmp ,   value ;
     unsigned   int  rs ,  rt ,  imm ;

     // Execute the instruction (cf. Kane's book)
     switch   ( instr -> opCode )   {
    
       case  OP_ADD :
    sum  =  registers [ instr -> rs ]   +  registers [ instr -> rt ];
     if   ( ! (( registers [ instr -> rs ]   ^  registers [ instr -> rt ])   &  SIGN_BIT )   &&
         (( registers [ instr -> rs ]   ^  sum )   &  SIGN_BIT ))   {
         RaiseException ( OverflowException ,   0 );
         return ;
     }
    registers [ instr -> rd ]   =  sum ;
     break ;
    
       case  OP_ADDI :
    sum  =  registers [ instr -> rs ]   +  instr -> extra ;
     if   ( ! (( registers [ instr -> rs ]   ^  instr -> extra )   &  SIGN_BIT )   &&
         (( instr -> extra  ^  sum )   &  SIGN_BIT ))   {
         RaiseException ( OverflowException ,   0 );
         return ;
     }
    registers [ instr -> rt ]   =  sum ;
     break ;
    
       case  OP_ADDIU :
    registers [ instr -> rt ]   =  registers [ instr -> rs ]   +  instr -> extra ;
     break ;
    
       case  OP_ADDU :
    registers [ instr -> rd ]   =  registers [ instr -> rs ]   +  registers [ instr -> rt ];
     break ;
    
       case  OP_AND :
    registers [ instr -> rd ]   =  registers [ instr -> rs ]   &  registers [ instr -> rt ];
     break ;
    
       case  OP_ANDI :
    registers [ instr -> rt ]   =  registers [ instr -> rs ]   &   ( instr -> extra  &   0xffff );
     break ;
    
       case  OP_BEQ :
     if   ( registers [ instr -> rs ]   ==  registers [ instr -> rt ])
        pcAfter  =  registers [ NextPCReg ]   +   IndexToAddr ( instr -> extra );
     break ;
    
       case  OP_BGEZAL :
    registers [ R31 ]   =  registers [ NextPCReg ]   +   4 ;
       case  OP_BGEZ :
     if   ( ! ( registers [ instr -> rs ]   &  SIGN_BIT ))
        pcAfter  =  registers [ NextPCReg ]   +   IndexToAddr ( instr -> extra );
     break ;
    
       case  OP_BGTZ :
     if   ( registers [ instr -> rs ]   >   0 )
        pcAfter  =  registers [ NextPCReg ]   +   IndexToAddr ( instr -> extra );
     break ;
    
       case  OP_BLEZ :
     if   ( registers [ instr -> rs ]   <=   0 )
        pcAfter  =  registers [ NextPCReg ]   +   IndexToAddr ( instr -> extra );
     break ;
    
       case  OP_BLTZAL :
    registers [ R31 ]   =  registers [ NextPCReg ]   +   4 ;
       case  OP_BLTZ :
     if   ( registers [ instr -> rs ]   &  SIGN_BIT )
        pcAfter  =  registers [ NextPCReg ]   +   IndexToAddr ( instr -> extra );
     break ;
    
       case  OP_BNE :
     if   ( registers [ instr -> rs ]   !=  registers [ instr -> rt ])
        pcAfter  =  registers [ NextPCReg ]   +   IndexToAddr ( instr -> extra );
     break ;
    
       case  OP_DIV :
     if   ( registers [ instr -> rt ]   ==   0 )   {
        registers [ LoReg ]   =   0 ;
        registers [ HiReg ]   =   0 ;
     }   else   {
        registers [ LoReg ]   =   registers [ instr -> rs ]   /  registers [ instr -> rt ];
        registers [ HiReg ]   =  registers [ instr -> rs ]   %  registers [ instr -> rt ];
     }
     break ;
    
       case  OP_DIVU :    
      rs  =   ( unsigned   int )  registers [ instr -> rs ];
      rt  =   ( unsigned   int )  registers [ instr -> rt ];
       if   ( rt  ==   0 )   {
          registers [ LoReg ]   =   0 ;
          registers [ HiReg ]   =   0 ;
       }   else   {
          tmp  =  rs  /  rt ;
          registers [ LoReg ]   =   ( int )  tmp ;
          tmp  =  rs  %  rt ;
          registers [ HiReg ]   =   ( int )  tmp ;
       }
       break ;
    
       case  OP_JAL :
    registers [ R31 ]   =  registers [ NextPCReg ]   +   4 ;
       case  OP_J :
    pcAfter  =   ( pcAfter  &   0xf0000000 )   |   IndexToAddr ( instr -> extra );
     break ;
    
       case  OP_JALR :
    registers [ instr -> rd ]   =  registers [ NextPCReg ]   +   4 ;
       case  OP_JR :
    pcAfter  =  registers [ instr -> rs ];
     break ;
    
       case  OP_LB :
       case  OP_LBU :
    tmp  =  registers [ instr -> rs ]   +  instr -> extra ;
     if   ( ! ReadMem ( tmp ,   1 ,   & value ))
         return ;

     if   (( value   &   0x80 )   &&   ( instr -> opCode  ==  OP_LB ))
         value   |=   0xffffff00 ;
     else
         value   &=   0xff ;
    nextLoadReg  =  instr -> rt ;
    nextLoadValue  =   value ;
     break ;
    
       case  OP_LH :
       case  OP_LHU :     
    tmp  =  registers [ instr -> rs ]   +  instr -> extra ;
     if   ( tmp  &   0x1 )   {
         RaiseException ( AddressErrorException ,  tmp );
         return ;
     }
     if   ( ! ReadMem ( tmp ,   2 ,   & value ))
         return ;

     if   (( value   &   0x8000 )   &&   ( instr -> opCode  ==  OP_LH ))
         value   |=   0xffff0000 ;
     else
         value   &=   0xffff ;
    nextLoadReg  =  instr -> rt ;
    nextLoadValue  =   value ;
     break ;
        
       case  OP_LUI :
    DEBUG ( dbgMach ,   "Executing: LUI r"   <<  instr -> rt  <<   ", "   <<  instr -> extra );
    registers [ instr -> rt ]   =  instr -> extra  <<   16 ;
     break ;
    
       case  OP_LW :
    tmp  =  registers [ instr -> rs ]   +  instr -> extra ;
     if   ( tmp  &   0x3 )   {
         RaiseException ( AddressErrorException ,  tmp );
         return ;
     }
     if   ( ! ReadMem ( tmp ,   4 ,   & value ))
         return ;
    nextLoadReg  =  instr -> rt ;
    nextLoadValue  =   value ;
     break ;
        
       case  OP_LWL :     
    tmp  =  registers [ instr -> rs ]   +  instr -> extra ;

#ifdef  SIM_FIX
     // The only difference between this code and the BIG ENDIAN code
         // is that the ReadMem call is guaranteed an aligned access as it
         // should be (Kane's book hides the fact that all memory access
         // are done using aligned loads - what the instruction asks for
         // is a arbitrary) This is the whole purpose of LWL and LWR etc.
         // Then the switch uses  3 - (tmp & 0x3)  instead of (tmp & 0x3)

        byte  =  tmp  &   0x3 ;
         // DEBUG('P', "Addr 0x%X\n",tmp-byte);

         if   ( ! ReadMem ( tmp - byte ,   4 ,   & value ))
             return ;
#else
     // ReadMem assumes all 4 byte requests are aligned on an even 
     // word boundary.  Also, the little endian/big endian swap code would
         // fail (I think) if the other cases are ever exercised.
    ASSERT (( tmp  &   0x3 )   ==   0 );   

     if   ( ! ReadMem ( tmp ,   4 ,   & value ))
         return ;
#endif

     if   ( registers [ LoadReg ]   ==  instr -> rt )
        nextLoadValue  =  registers [ LoadValueReg ];
     else
        nextLoadValue  =  registers [ instr -> rt ];
#ifdef  SIM_FIX
     switch   ( 3   -  byte )  
#else
     switch   ( tmp  &   0x3 )
#endif
       {
       case   0 :
        nextLoadValue  =   value ;
         break ;
       case   1 :
        nextLoadValue  =   ( nextLoadValue  &   0xff )   |   ( value   <<   8 );
         break ;
       case   2 :
        nextLoadValue  =   ( nextLoadValue  &   0xffff )   |   ( value   <<   16 );
         break ;
       case   3 :
        nextLoadValue  =   ( nextLoadValue  &   0xffffff )   |   ( value   <<   24 );
         break ;
     }
    nextLoadReg  =  instr -> rt ;
     break ;
        
       case  OP_LWR :
    tmp  =  registers [ instr -> rs ]   +  instr -> extra ;

#ifdef  SIM_FIX
         // The only difference between this code and the BIG ENDIAN code
         // is that the ReadMem call is guaranteed an aligned access as it
         // should be (Kane's book hides the fact that all memory access
         // are done using aligned loads - what the instruction asks 
         // for is a arbitrary) This is the whole purpose of LWL and LWR etc.
         // Then the switch uses  3 - (tmp & 0x3)  instead of (tmp & 0x3)

        byte  =  tmp  &   0x3 ;
         // DEBUG('P', "Addr 0x%X\n",tmp-byte);

         if   ( ! ReadMem ( tmp - byte ,   4 ,   & value ))
             return ;
#else
     // ReadMem assumes all 4 byte requests are aligned on an even 
     // word boundary.  Also, the little endian/big endian swap code would
         // fail (I think) if the other cases are ever exercised.
    ASSERT (( tmp  &   0x3 )   ==   0 );   

     if   ( ! ReadMem ( tmp ,   4 ,   & value ))
         return ;
#endif

     if   ( registers [ LoadReg ]   ==  instr -> rt )
        nextLoadValue  =  registers [ LoadValueReg ];
     else
        nextLoadValue  =  registers [ instr -> rt ];

#ifdef  SIM_FIX
     switch   ( 3   -  byte )  
#else
     switch   ( tmp  &   0x3 )
#endif
       {
       case   0 :
        nextLoadValue  =   ( nextLoadValue  &   0xffffff00 )   |
         (( value   >>   24 )   &   0xff );
         break ;
       case   1 :
        nextLoadValue  =   ( nextLoadValue  &   0xffff0000 )   |
         (( value   >>   16 )   &   0xffff );
         break ;
       case   2 :
        nextLoadValue  =   ( nextLoadValue  &   0xff000000 )
         |   (( value   >>   8 )   &   0xffffff );
         break ;
       case   3 :
        nextLoadValue  =   value ;
         break ;
     }
    nextLoadReg  =  instr -> rt ;
     break ;
        
       case  OP_MFHI :
    registers [ instr -> rd ]   =  registers [ HiReg ];
     break ;
    
       case  OP_MFLO :
    registers [ instr -> rd ]   =  registers [ LoReg ];
     break ;
    
       case  OP_MTHI :
    registers [ HiReg ]   =  registers [ instr -> rs ];
     break ;
    
       case  OP_MTLO :
    registers [ LoReg ]   =  registers [ instr -> rs ];
     break ;
    
       case  OP_MULT :
     Mult ( registers [ instr -> rs ],  registers [ instr -> rt ],  TRUE ,
          & registers [ HiReg ],   & registers [ LoReg ]);
     break ;
    
       case  OP_MULTU :
     Mult ( registers [ instr -> rs ],  registers [ instr -> rt ],  FALSE ,
          & registers [ HiReg ],   & registers [ LoReg ]);
     break ;
    
       case  OP_NOR :
    registers [ instr -> rd ]   =   ~ ( registers [ instr -> rs ]   |  registers [ instr -> rt ]);
     break ;
    
       case  OP_OR :
    registers [ instr -> rd ]   =  registers [ instr -> rs ]   |  registers [ instr -> rt ];
     break ;
    
       case  OP_ORI :
    registers [ instr -> rt ]   =  registers [ instr -> rs ]   |   ( instr -> extra  &   0xffff );
     break ;
    
       case  OP_SB :
     if   ( ! WriteMem (( unsigned )  
         ( registers [ instr -> rs ]   +  instr -> extra ),   1 ,  registers [ instr -> rt ]))
         return ;
     break ;
    
       case  OP_SH :
     if   ( ! WriteMem (( unsigned )  
         ( registers [ instr -> rs ]   +  instr -> extra ),   2 ,  registers [ instr -> rt ]))
         return ;
     break ;
    
       case  OP_SLL :
    registers [ instr -> rd ]   =  registers [ instr -> rt ]   <<  instr -> extra ;
     break ;
    
       case  OP_SLLV :
    registers [ instr -> rd ]   =  registers [ instr -> rt ]   <<
         ( registers [ instr -> rs ]   &   0x1f );
     break ;
    
       case  OP_SLT :
     if   ( registers [ instr -> rs ]   <  registers [ instr -> rt ])
        registers [ instr -> rd ]   =   1 ;
     else
        registers [ instr -> rd ]   =   0 ;
     break ;
    
       case  OP_SLTI :
     if   ( registers [ instr -> rs ]   <  instr -> extra )
        registers [ instr -> rt ]   =   1 ;
     else
        registers [ instr -> rt ]   =   0 ;
     break ;
    
       case  OP_SLTIU :       
    rs  =  registers [ instr -> rs ];
    imm  =  instr -> extra ;
     if   ( rs  <  imm )
        registers [ instr -> rt ]   =   1 ;
     else
        registers [ instr -> rt ]   =   0 ;
     break ;
        
       case  OP_SLTU :    
    rs  =  registers [ instr -> rs ];
    rt  =  registers [ instr -> rt ];
     if   ( rs  <  rt )
        registers [ instr -> rd ]   =   1 ;
     else
        registers [ instr -> rd ]   =   0 ;
     break ;
        
       case  OP_SRA :
    registers [ instr -> rd ]   =  registers [ instr -> rt ]   >>  instr -> extra ;
     break ;
    
       case  OP_SRAV :
    registers [ instr -> rd ]   =  registers [ instr -> rt ]   >>
         ( registers [ instr -> rs ]   &   0x1f );
     break ;
    
       case  OP_SRL :
    tmp  =  registers [ instr -> rt ];
    tmp  >>=  instr -> extra ;
    registers [ instr -> rd ]   =  tmp ;
     break ;
    
       case  OP_SRLV :
    tmp  =  registers [ instr -> rt ];
    tmp  >>=   ( registers [ instr -> rs ]   &   0x1f );
    registers [ instr -> rd ]   =  tmp ;
     break ;
    
       case  OP_SUB :     
    diff  =  registers [ instr -> rs ]   -  registers [ instr -> rt ];
     if   ((( registers [ instr -> rs ]   ^  registers [ instr -> rt ])   &  SIGN_BIT )   &&
         (( registers [ instr -> rs ]   ^  diff )   &  SIGN_BIT ))   {
         RaiseException ( OverflowException ,   0 );
         return ;
     }
    registers [ instr -> rd ]   =  diff ;
     break ;
        
       case  OP_SUBU :
    registers [ instr -> rd ]   =  registers [ instr -> rs ]   -  registers [ instr -> rt ];
     break ;
    
       case  OP_SW :
     if   ( ! WriteMem (( unsigned )  
         ( registers [ instr -> rs ]   +  instr -> extra ),   4 ,  registers [ instr -> rt ]))
         return ;
     break ;
    
       case  OP_SWL :     
    tmp  =  registers [ instr -> rs ]   +  instr -> extra ;

#ifdef  SIM_FIX
         // The only difference between this code and the BIG ENDIAN code
         // is that the ReadMem call is guaranteed an aligned access as it
         // should be (Kane's book hides the fact that all memory access
         // are done using aligned loads - what the instruction asks for
         // is a arbitrary) This is the whole purpose of LWL and LWR etc.

        byte  =  tmp  &   0x3 ;
         // DEBUG('P', "Addr 0x%X\n",tmp-byte);
         if   ( ! ReadMem ( tmp - byte ,   4 ,   & value ))
             return ;

         // DEBUG('P', "Value 0x%X\n",value);
#else

     // The little endian/big endian swap code would
         // fail (I think) if the other cases are ever exercised.
    ASSERT (( tmp  &   0x3 )   ==   0 );   

     if   ( ! ReadMem (( tmp  &   ~ 0x3 ),   4 ,   & value ))
         return ;
#endif

#ifdef  SIM_FIX
     switch (   3   -  byte  )
#else
       switch   ( tmp  &   0x3 )  
#endif   // SIM_FIX
         {
       case   0 :
         value   =  registers [ instr -> rt ];
         break ;
       case   1 :
         value   =   ( value   &   0xff000000 )   |   (( registers [ instr -> rt ]   >>   8 )   &
                         0xffffff );
         break ;
       case   2 :
         value   =   ( value   &   0xffff0000 )   |   (( registers [ instr -> rt ]   >>   16 )   &
                         0xffff );
         break ;
       case   3 :
         value   =   ( value   &   0xffffff00 )   |   (( registers [ instr -> rt ]   >>   24 )   &
                         0xff );
         break ;
     }
#ifndef  SIM_FIX
         if   ( ! WriteMem (( tmp  &   ~ 0x3 ),   4 ,   value ))
             return ;
#else
         // DEBUG('P', "Value 0x%X\n",value);

         if   ( ! WriteMem (( tmp  -  byte ),   4 ,   value ))
             return ;
#endif   // SIM_FIX
     break ;
        
       case  OP_SWR :     
    tmp  =  registers [ instr -> rs ]   +  instr -> extra ;

#ifndef  SIM_FIX
         // The little endian/big endian swap code would
         // fail (I think) if the other cases are ever exercised.
        ASSERT (( tmp  &   0x3 )   ==   0 );   

         if   ( ! ReadMem (( tmp  &   ~ 0x3 ),   4 ,   & value ))
             return ;
#else
         // The only difference between this code and the BIG ENDIAN code
         // is that the ReadMem call is guaranteed an aligned access as 
         // it should be (Kane's book hides the fact that all memory 
         // access are done using aligned loads - what the instruction 
         // asks for is a arbitrary) This is the whole purpose of LWL 
         // and LWR etc.

        byte  =  tmp  &   0x3 ;
         // DEBUG('P', "Addr 0x%X\n",tmp-byte);

         if   ( ! ReadMem ( tmp - byte ,   4 ,   & value ))
             return ;
         // DEBUG('P', "Value 0x%X\n",value);
#endif   // SIM_FIX

#ifndef  SIM_FIX
         switch   ( tmp  &   0x3 )  
#else
       switch (   3   -  byte  )  
#endif   // SIM_FIX
         {
         case   0 :
         value   =   ( value   &   0xffffff )   |   ( registers [ instr -> rt ]   <<   24 );
         break ;
       case   1 :
         value   =   ( value   &   0xffff )   |   ( registers [ instr -> rt ]   <<   16 );
         break ;
       case   2 :
         value   =   ( value   &   0xff )   |   ( registers [ instr -> rt ]   <<   8 );
         break ;
       case   3 :
         value   =  registers [ instr -> rt ];
         break ;
     }

#ifndef  SIM_FIX
         if   ( ! WriteMem (( tmp  &   ~ 0x3 ),   4 ,   value ))
             return ;
#else
         // DEBUG('P', "Value 0x%X\n",value);

         if   ( ! WriteMem (( tmp  -  byte ),   4 ,   value ))
             return ;
#endif   // SIM_FIX


     break ;
        
       case  OP_SYSCALL :
     RaiseException ( SyscallException ,   0 );
     return ;  
    
       case  OP_XOR :
    registers [ instr -> rd ]   =  registers [ instr -> rs ]   ^  registers [ instr -> rt ];
     break ;
    
       case  OP_XORI :
    registers [ instr -> rt ]   =  registers [ instr -> rs ]   ^   ( instr -> extra  &   0xffff );
     break ;
    
       case  OP_RES :
       case  OP_UNIMP :
     RaiseException ( IllegalInstrException ,   0 );
     return ;
    
       default :
    ASSERT ( FALSE );
     }
    
     // Now we have successfully executed the instruction.
    
     // Do any delayed load operation
     DelayedLoad ( nextLoadReg ,  nextLoadValue );
    
     // Advance program counters.
    registers [ PrevPCReg ]   =  registers [ PCReg ];      // for debugging, in case we
                         // are jumping into lala-land
    registers [ PCReg ]   =  registers [ NextPCReg ];
    registers [ NextPCReg ]   =  pcAfter ;
}

//----------------------------------------------------------------------
// Machine::DelayedLoad
//  Simulate effects of a delayed load.
//
//  NOTE -- RaiseException/CheckInterrupts must also call DelayedLoad,
//  since any delayed load must get applied before we trap to the kernel.
//----------------------------------------------------------------------

void
Machine :: DelayedLoad ( int  nextReg ,   int  nextValue )
{
    registers [ registers [ LoadReg ]]   =  registers [ LoadValueReg ];
    registers [ LoadReg ]   =  nextReg ;
    registers [ LoadValueReg ]   =  nextValue ;
    registers [ 0 ]   =   0 ;     // and always make sure R0 stays zero.
}

//----------------------------------------------------------------------
// Instruction::Decode
//  Decode a MIPS instruction 
//----------------------------------------------------------------------

void
Instruction :: Decode ()
{
     OpInfo   * opPtr ;
    
    rs  =   ( value   >>   21 )   &   0x1f ;
    rt  =   ( value   >>   16 )   &   0x1f ;
    rd  =   ( value   >>   11 )   &   0x1f ;
    opPtr  =   & opTable [( value   >>   26 )   &   0x3f ];
    opCode  =  opPtr -> opCode ;
     if   ( opPtr -> format  ==  IFMT )   {
    extra  =   value   &   0xffff ;
     if   ( extra  &   0x8000 )   {
           extra  |=   0xffff0000 ;
     }
     }   else   if   ( opPtr -> format  ==  RFMT )   {
    extra  =   ( value   >>   6 )   &   0x1f ;
     }   else   {
    extra  =   value   &   0x3ffffff ;
     }
     if   ( opCode  ==  SPECIAL )   {
    opCode  =  specialTable [ value   &   0x3f ];
     }   else   if   ( opCode  ==  BCOND )   {
     int  i  =   value   &   0x1f0000 ;

     if   ( ==   0 )   {
            opCode  =  OP_BLTZ ;
     }   else   if   ( ==   0x10000 )   {
            opCode  =  OP_BGEZ ;
     }   else   if   ( ==   0x100000 )   {
            opCode  =  OP_BLTZAL ;
     }   else   if   ( ==   0x110000 )   {
            opCode  =  OP_BGEZAL ;
     }   else   {
            opCode  =  OP_UNIMP ;
     }
     }
}

//----------------------------------------------------------------------
// Mult
//  Simulate R2000 multiplication.
//  The words at *hiPtr and *loPtr are overwritten with the
//  double-length result of the multiplication.
//----------------------------------------------------------------------

static   void
Mult ( int  a ,   int  b ,   bool  signedArith ,   int *  hiPtr ,   int *  loPtr )
{
     if   (( ==   0 )   ||   ( ==   0 ))   {
     * hiPtr  =   * loPtr  =   0 ;
     return ;
     }

     // Compute the sign of the result, then make everything positive
     // so unsigned computation can be done in the main loop.
     bool  negative  =  FALSE ;
     if   ( signedArith )   {
     if   ( <   0 )   {
        negative  =   ! negative ;
        a  =   - a ;
     }
     if   ( <   0 )   {
        negative  =   ! negative ;
        b  =   - b ;
     }
     }

     // Compute the result in unsigned arithmetic (check a's bits one at
     // a time, and add in a shifted value of b).
     unsigned   int  bLo  =  b ;
     unsigned   int  bHi  =   0 ;
     unsigned   int  lo  =   0 ;
     unsigned   int  hi  =   0 ;
     for   ( int  i  =   0 ;  i  <   32 ;  i ++ )   {
     if   ( &   1 )   {
        lo  +=  bLo ;
         if   ( lo  <  bLo )    // Carry out of the low bits?
        hi  +=   1 ;
        hi  +=  bHi ;
         if   (( &   0xfffffffe )   ==   0 )
         break ;
     }
    bHi  <<=   1 ;
     if   ( bLo  &   0x80000000 )
        bHi  |=   1 ;
    
    bLo  <<=   1 ;
    a  >>=   1 ;
     }

     // If the result is supposed to be negative, compute the two's
     // complement of the double-word result.
     if   ( negative )   {
    hi  =   ~ hi ;
    lo  =   ~ lo ;
    lo ++ ;
     if   ( lo  ==   0 )
        hi ++ ;
     }
    
     * hiPtr  =   ( int )  hi ;
     * loPtr  =   ( int )  lo ;
}

project4/nachos/code/machine/callback.h

// callback.h // Data structure to allow an object to register a "callback". // On an asynchronous operation, the call to start the operation // returns immediately. When the operation completes, the called // object must somehow notify the caller of the completion. // In the general case, the called object doesn't know the type // of the caller. // // We implement this using virtual functions in C++. An object // that needs to register a callback is set up as a derived class of // the abstract base class "CallbackObj". When we pass a // pointer to the object to a lower level module, that module // calls back via "obj->CallBack()", without knowing the // type of the object being called back. // // Note that this isn't a general-purpose mechanism, // because a class can only register a single callback. // // DO NOT CHANGE -- part of the machine emulation // // Copyright (c) 1992-1996 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. // #ifndef CALLBACK_H #define CALLBACK_H #include "copyright.h" // Abstract base class for objects that register callbacks class CallBackObj { public: virtual void CallBack() = 0; protected: CallBackObj() {}; // to prevent anyone from creating // an instance of this class. Only // allow creation of instances of // classes derived from this class. virtual ~CallBackObj() {}; }; #endif

project4/nachos/code/machine/stats.h

// stats.h // Data structures for gathering statistics about Nachos performance. // // DO NOT CHANGE -- these stats are maintained by the machine emulation // // // Copyright (c) 1992-1993 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef STATS_H #define STATS_H #include "copyright.h" // The following class defines the statistics that are to be kept // about Nachos behavior -- how much time (ticks) elapsed, how // many user instructions executed, etc. // // The fields in this class are public to make it easier to update. class Statistics { public: int totalTicks; // Total time running Nachos int idleTicks; // Time spent idle (no threads to run) int systemTicks; // Time spent executing system code int userTicks; // Time spent executing user code // (this is also equal to # of // user instructions executed) int numDiskReads; // number of disk read requests int numDiskWrites; // number of disk write requests int numConsoleCharsRead; // number of characters read from the keyboard int numConsoleCharsWritten; // number of characters written to the display int numPageFaults; // number of virtual memory page faults int numPacketsSent; // number of packets sent over the network int numPacketsRecvd; // number of packets received over the network Statistics(); // initialize everything to zero void Print(); // print collected statistics }; // Constants used to reflect the relative time an operation would // take in a real system. A "tick" is a just a unit of time -- if you // like, a microsecond. // // Since Nachos kernel code is directly executed, and the time spent // in the kernel measured by the number of calls to enable interrupts, // these time constants are none too exact. const int UserTick = 1; // advance for each user-level instruction const int SystemTick = 10; // advance each time interrupts are enabled const int RotationTime = 500; // time disk takes to rotate one sector const int SeekTime = 500; // time disk takes to seek past one track const int ConsoleTime = 100; // time to read or write one character const int NetworkTime = 100; // time to send or receive one packet const int TimerTicks = 100; // (average) time between timer interrupts #endif // STATS_H

project4/nachos/code/userprog/synchconsole.cc

project4/nachos/code/userprog/synchconsole.cc

// synchconsole.cc 
//  Routines providing synchronized access to the keyboard 
//  and console display hardware devices.
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include   "copyright.h"
#include   "synchconsole.h"

//----------------------------------------------------------------------
// SynchConsoleInput::SynchConsoleInput
//      Initialize synchronized access to the keyboard
//
//      "inputFile" -- if NULL, use stdin as console device
//              otherwise, read from this file
//----------------------------------------------------------------------

SynchConsoleInput :: SynchConsoleInput ( char   * inputFile )
{
    consoleInput  =   new   ConsoleInput ( inputFile ,   this );
    lock  =   new   Lock ( "console in" );
    waitFor  =   new   Semaphore ( "console in" ,   0 );
}

//----------------------------------------------------------------------
// SynchConsoleInput::~SynchConsoleInput
//      Deallocate data structures for synchronized access to the keyboard
//----------------------------------------------------------------------

SynchConsoleInput ::~ SynchConsoleInput ()
{  
     delete  consoleInput ;  
     delete  lock ;  
     delete  waitFor ;
}

//----------------------------------------------------------------------
// SynchConsoleInput::GetChar
//      Read a character typed at the keyboard, waiting if necessary.
//----------------------------------------------------------------------

char
SynchConsoleInput :: GetChar ()
{
     char  ch ;

    lock -> Acquire ();
    waitFor -> P ();     // wait for EOF or a char to be available.
    ch  =  consoleInput -> GetChar ();
    lock -> Release ();
     return  ch ;
}

//----------------------------------------------------------------------
// SynchConsoleInput::CallBack
//      Interrupt handler called when keystroke is hit; wake up
//  anyone waiting.
//----------------------------------------------------------------------

void
SynchConsoleInput :: CallBack ()
{
    waitFor -> V ();
}

//----------------------------------------------------------------------
// SynchConsoleOutput::SynchConsoleOutput
//      Initialize synchronized access to the console display
//
//      "outputFile" -- if NULL, use stdout as console device
//              otherwise, read from this file
//----------------------------------------------------------------------

SynchConsoleOutput :: SynchConsoleOutput ( char   * outputFile )
{
    consoleOutput  =   new   ConsoleOutput ( outputFile ,   this );
    lock  =   new   Lock ( "console out" );
    waitFor  =   new   Semaphore ( "console out" ,   0 );
}

//----------------------------------------------------------------------
// SynchConsoleOutput::~SynchConsoleOutput
//      Deallocate data structures for synchronized access to the keyboard
//----------------------------------------------------------------------

SynchConsoleOutput ::~ SynchConsoleOutput ()
{  
     delete  consoleOutput ;  
     delete  lock ;  
     delete  waitFor ;
}

//----------------------------------------------------------------------
// SynchConsoleOutput::PutChar
//      Write a character to the console display, waiting if necessary.
//----------------------------------------------------------------------

void
SynchConsoleOutput :: PutChar ( char  ch )
{
    lock -> Acquire ();
    consoleOutput -> PutChar ( ch );
    waitFor -> P ();
    lock -> Release ();
}

//----------------------------------------------------------------------
// SynchConsoleOutput::CallBack
//      Interrupt handler called when it's safe to send the next 
//  character can be sent to the display.
//----------------------------------------------------------------------

void
SynchConsoleOutput :: CallBack ()
{
    waitFor -> V ();
}

project4/nachos/code/userprog/synchconsole.h

// synchconsole.h // Data structures for synchronized access to the keyboard // and console display devices. // // NOTE: this abstraction is not completely implemented. // // Copyright (c) 1992-1996 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef SYNCHCONSOLE_H #define SYNCHCONSOLE_H #include "copyright.h" #include "utility.h" #include "callback.h" #include "console.h" #include "synch.h" // The following two classes define synchronized input and output to // a console device class SynchConsoleInput : public CallBackObj { public: SynchConsoleInput(char *inputFile); // Initialize the console device ~SynchConsoleInput(); // Deallocate console device char GetChar(); // Read a character, waiting if necessary private: ConsoleInput *consoleInput; // the hardware keyboard Lock *lock; // only one reader at a time Semaphore *waitFor; // wait for callBack void CallBack(); // called when a keystroke is available }; class SynchConsoleOutput : public CallBackObj { public: SynchConsoleOutput(char *outputFile); // Initialize the console device ~SynchConsoleOutput(); void PutChar(char ch); // Write a character, waiting if necessary private: ConsoleOutput *consoleOutput;// the hardware display Lock *lock; // only one writer at a time Semaphore *waitFor; // wait for callBack void CallBack(); // called when more data can be written }; #endif // SYNCHCONSOLE_H

project4/nachos/code/userprog/addrspace.cc

#include "copyright.h" #include "main.h" #include "addrspace.h" #include "machine.h" #include "noff.h" int AddrSpace::mark = 0; //---------------------------------------------------------------------- // SwapHeader // Do little endian to big endian conversion on the bytes in the // object file header, in case the file was generated on a little // endian machine, and we're now running on a big endian machine. //---------------------------------------------------------------------- static void SwapHeader (NoffHeader *noffH) { noffH->noffMagic = WordToHost(noffH->noffMagic); noffH->code.size = WordToHost(noffH->code.size); noffH->code.virtualAddr = WordToHost(noffH->code.virtualAddr); noffH->code.inFileAddr = WordToHost(noffH->code.inFileAddr); #ifdef RDATA noffH->readonlyData.size = WordToHost(noffH->readonlyData.size); noffH->readonlyData.virtualAddr = WordToHost(noffH->readonlyData.virtualAddr); noffH->readonlyData.inFileAddr = WordToHost(noffH->readonlyData.inFileAddr); #endif noffH->initData.size = WordToHost(noffH->initData.size); noffH->initData.virtualAddr = WordToHost(noffH->initData.virtualAddr); noffH->initData.inFileAddr = WordToHost(noffH->initData.inFileAddr); noffH->uninitData.size = WordToHost(noffH->uninitData.size); noffH->uninitData.virtualAddr = WordToHost(noffH->uninitData.virtualAddr); noffH->uninitData.inFileAddr = WordToHost(noffH->uninitData.inFileAddr); #ifdef RDATA DEBUG(dbgAddr, "code = " << noffH->code.size << " readonly = " << noffH->readonlyData.size << " init = " << noffH->initData.size << " uninit = " << noffH->uninitData.size << "\n"); #endif } //---------------------------------------------------------------------- // AddrSpace::AddrSpace // Create an address space to run a user program. // Set up the translation from program memory to physical // memory. For now, this is really simple (1:1), since we are // only uniprogramming, and we have a single unsegmented page table //---------------------------------------------------------------------- AddrSpace::AddrSpace() { } //---------------------------------------------------------------------- // AddrSpace::~AddrSpace // Dealloate an address space. //---------------------------------------------------------------------- AddrSpace::~AddrSpace() { delete pageTable; } //---------------------------------------------------------------------- // AddrSpace::Load // Load a user program into memory from a file. // // Assumes that the page table has been initialized, and that // the object code file is in NOFF format. // // "fileName" is the file containing the object code to load into memory //---------------------------------------------------------------------- bool AddrSpace::Load(char *fileName) { OpenFile *executable = kernel->fileSystem->Open(fileName); NoffHeader noffH; unsigned int size; if (executable == NULL) { cerr << "Unable to open file " << fileName << "\n"; return FALSE; } executable->ReadAt((char *)&noffH, sizeof(noffH), 0); if ((noffH.noffMagic != NOFFMAGIC) && (WordToHost(noffH.noffMagic) == NOFFMAGIC)) SwapHeader(&noffH); ASSERT(noffH.noffMagic == NOFFMAGIC); #ifdef RDATA // how big is address space? size = noffH.code.size + noffH.readonlyData.size + noffH.initData.size + noffH.uninitData.size + UserStackSize; // we need to increase the size // to leave room for the stack #else // how big is address space? size = noffH.code.size + noffH.initData.size + noffH.uninitData.size + UserStackSize; // we need to increase the size // to leave room for the stack #endif numPages = divRoundUp(size, PageSize); size = numPages * PageSize; ASSERT(numPages <= NumPhysPages); // check we're not trying // to run anything too big -- // at least until we have // virtual memory DEBUG(dbgAddr, "Initializing address space: " << numPages << ", " << size); pageTable = new TranslationEntry[numPages]; for (int i = 0; i < numPages; i++) { pageTable[i].virtualPage = i; // for now, virt page # = phys page # pageTable[i].physicalPage = i + mark; pageTable[i].valid = TRUE; pageTable[i].use = FALSE; pageTable[i].dirty = FALSE; pageTable[i].readOnly = FALSE; } // zero out the entire address space bzero(&kernel->machine->mainMemory[mark * PageSize], size); // then, copy in the code and data segments into memory // Note: this code assumes that virtual address = physical address if (noffH.code.size > 0) { DEBUG(dbgAddr, "Initializing code segment."); DEBUG(dbgAddr, noffH.code.virtualAddr << ", " << noffH.code.size); executable->ReadAt( &(kernel->machine->mainMemory[noffH.code.virtualAddr + mark * PageSize]), noffH.code.size, noffH.code.inFileAddr); } if (noffH.initData.size > 0) { DEBUG(dbgAddr, "Initializing data segment."); DEBUG(dbgAddr, noffH.initData.virtualAddr << ", " << noffH.initData.size); executable->ReadAt( &(kernel->machine->mainMemory[noffH.initData.virtualAddr + mark * PageSize]), noffH.initData.size, noffH.initData.inFileAddr); } #ifdef RDATA if (noffH.readonlyData.size > 0) { DEBUG(dbgAddr, "Initializing read only data segment."); DEBUG(dbgAddr, noffH.readonlyData.virtualAddr << ", " << noffH.readonlyData.size); executable->ReadAt( &(kernel->machine->mainMemory[noffH.readonlyData.virtualAddr + mark * PageSize]), noffH.readonlyData.size, noffH.readonlyData.inFileAddr); } #endif mark += numPages; delete executable; // close file return TRUE; // success } //---------------------------------------------------------------------- // AddrSpace::Execute // Run a user program using the current thread // // The program is assumed to have already been loaded into // the address space // //---------------------------------------------------------------------- void AddrSpace::Execute() { kernel->currentThread->space = this; this->InitRegisters(); // set the initial register values this->RestoreState(); // load page table register kernel->machine->Run(); // jump to the user progam ASSERTNOTREACHED(); // machine->Run never returns; // the address space exits // by doing the syscall "exit" } //---------------------------------------------------------------------- // AddrSpace::InitRegisters // Set the initial values for the user-level register set. // // We write these directly into the "machine" registers, so // that we can immediately jump to user code. Note that these // will be saved/restored into the currentThread->userRegisters // when this thread is context switched out. //---------------------------------------------------------------------- void AddrSpace::InitRegisters() { Machine *machine = kernel->machine; int i; for (i = 0; i < NumTotalRegs; i++) machine->WriteRegister(i, 0); // Initial program counter -- must be location of "Start", which // is assumed to be virtual address zero machine->WriteRegister(PCReg, 0); // Need to also tell MIPS where next instruction is, because // of branch delay possibility // Since instructions occupy four bytes each, the next instruction // after start will be at virtual address four. machine->WriteRegister(NextPCReg, 4); // Set the stack register to the end of the address space, where we // allocated the stack; but subtract off a bit, to make sure we don't // accidentally reference off the end! machine->WriteRegister(StackReg, numPages * PageSize - 16); DEBUG(dbgAddr, "Initializing stack pointer: " << numPages * PageSize - 16); } //---------------------------------------------------------------------- // AddrSpace::SaveState // On a context switch, save any machine state, specific // to this address space, that needs saving. // // For now, don't need to save anything! //---------------------------------------------------------------------- void AddrSpace::SaveState() {} //---------------------------------------------------------------------- // AddrSpace::RestoreState // On a context switch, restore the machine state so that // this address space can run. // // For now, tell the machine where to find the page table. //---------------------------------------------------------------------- void AddrSpace::RestoreState() { kernel->machine->pageTable = pageTable; kernel->machine->pageTableSize = numPages; } //---------------------------------------------------------------------- // AddrSpace::Translate // Translate the virtual address in _vaddr_ to a physical address // and store the physical address in _paddr_. // The flag _isReadWrite_ is false (0) for read-only access; true (1) // for read-write access. // Return any exceptions caused by the address translation. //---------------------------------------------------------------------- ExceptionType AddrSpace::Translate(unsigned int vaddr, unsigned int *paddr, int isReadWrite) { TranslationEntry *pte; int pfn; unsigned int vpn = vaddr / PageSize; unsigned int offset = vaddr % PageSize; if(vpn >= numPages) { return AddressErrorException; } pte = &pageTable[vpn]; if(isReadWrite && pte->readOnly) { return ReadOnlyException; } pfn = pte->physicalPage; // if the pageFrame is too big, there is something really wrong! // An invalid translation was loaded into the page table or TLB. if (pfn >= NumPhysPages) { DEBUG(dbgAddr, "Illegal physical page " << pfn); return BusErrorException; } pte->use = TRUE; // set the use, dirty bits if(isReadWrite) pte->dirty = TRUE; *paddr = pfn*PageSize + offset; ASSERT((*paddr < MemorySize)); //cerr << " -- AddrSpace::Translate(): vaddr: " << vaddr << // ", paddr: " << *paddr << "\n"; return NoException; }

project4/nachos/code/userprog/ksyscall.h

/************************************************************** * * userprog/ksyscall.h * * Kernel interface for systemcalls * * by Marcus Voelp (c) Universitaet Karlsruhe * **************************************************************/ #ifndef __USERPROG_KSYSCALL_H__ #define __USERPROG_KSYSCALL_H__ #include "kernel.h" void SysHalt() { kernel->interrupt->Halt(); } int SysAdd(int op1, int op2) { return op1 + op2; } #endif /* ! __USERPROG_KSYSCALL_H__ */

project4/nachos/code/userprog/addrspace.h

#ifndef ADDRSPACE_H #define ADDRSPACE_H #include "copyright.h" #include "filesys.h" #define UserStackSize 1024 // increase this as necessary! class AddrSpace { public: AddrSpace(); // Create an address space. ~AddrSpace(); // De-allocate an address space bool Load(char *fileName); // Load a program into addr space from // a file // return false if not found void Execute(); // Run a program // assumes the program has already // been loaded void SaveState(); // Save/restore address space-specific void RestoreState(); // info on a context switch // Translate virtual address _vaddr_ // to physical address _paddr_. _mode_ // is 0 for Read, 1 for Write. ExceptionType Translate(unsigned int vaddr, unsigned int *paddr, int mode); private: TranslationEntry *pageTable; // Assume linear page table translation // for now! unsigned int numPages; // Number of pages in the virtual // address space void InitRegisters(); // Initialize user-level CPU registers, // before jumping to user code static int mark; }; #endif // ADDRSPACE_H

project4/nachos/code/userprog/errno.h

/* errno.h * Error codes for system calls. * * Do not modify the contents of this file. * * Try to use the most descriptive error number for the error. * You may find it helpful to see what errors equivalent UNIX * system calls return under various error conditions. * For example the man page for the write system call "man 2 write" * provides a list of different error number values for different * conditions. * NOTE: there are way more errors here than you should be supporting * and many more error conditions listed in man pages than * Nachos can possibly generate. The list here is to give you * some ideas and to hopefully standardize on some error numbers. * * ALSO NOTE: These definitions may not correspond to Solaris definitions * (for copyright reasons these are taken from Linux). */ #ifndef ERRNO_H #define ERRNO_H #include "copyright.h" #define EPERM -1 /* Operation not permitted */ #define ENOENT -2 /* No such file or directory */ #define ESRCH -3 /* No such process */ #define EINTR -4 /* Interrupted system call */ #define EIO -5 /* I/O error */ #define ENXIO -6 /* No such device or address */ #define E2BIG -7 /* Arg list too long */ #define ENOEXEC -8 /* Exec format error */ #define EBADF -9 /* Bad file number */ #define ECHILD -10 /* No child processes */ #define EAGAIN -11 /* Try again */ #define ENOMEM -12 /* Out of memory */ #define EACCES -13 /* Permission denied */ #define EFAULT -14 /* Bad address */ #define ENOTBLK -15 /* Block device required */ #define EBUSY -16 /* Device or resource busy */ #define EEXIST -17 /* File exists */ #define EXDEV -18 /* Cross-device link */ #define ENODEV -19 /* No such device */ #define ENOTDIR -20 /* Not a directory */ #define EISDIR -21 /* Is a directory */ #define EINVAL -22 /* Invalid argument */ #define ENFILE -23 /* File table overflow */ #define EMFILE -24 /* Too many open files */ #define ENOTTY -25 /* Not a typewriter */ #define ETXTBSY -26 /* Text file busy */ #define EFBIG -27 /* File too large */ #define ENOSPC -28 /* No space left on device */ #define ESPIPE -29 /* Illegal seek */ #define EROFS -30 /* Read-only file system */ #define EMLINK -31 /* Too many links */ #define EPIPE -32 /* Broken pipe */ #define EDOM -33 /* Math argument out of domain of func */ #define ERANGE -34 /* Math result not representable */ #define EDEADLK -35 /* Resource deadlock would occur */ #define ENAMETOOLONG -36 /* File name too long */ #define ENOLCK -37 /* No record locks available */ #define ENOSYS -38 /* Function not implemented */ #define ENOTEMPTY -39 /* Directory not empty */ #define ELOOP -40 /* Too many symbolic links encountered */ #define EWOULDBLOCK EAGAIN /* Operation would block */ #define ENOMSG -42 /* No message of desired type */ #define EIDRM -43 /* Identifier removed */ #define ECHRNG -44 /* Channel number out of range */ #define EL2NSYNC -45 /* Level 2 not synchronized */ #define EL3HLT -46 /* Level 3 halted */ #define EL3RST -47 /* Level 3 reset */ #define ELNRNG -48 /* Link number out of range */ #define EUNATCH -49 /* Protocol driver not attached */ #define ENOCSI -50 /* No CSI structure available */ #define EL2HLT -51 /* Level 2 halted */ #define EBADE -52 /* Invalid exchange */ #define EBADR -53 /* Invalid request descriptor */ #define EXFULL -54 /* Exchange full */ #define ENOANO -55 /* No anode */ #define EBADRQC -56 /* Invalid request code */ #define EBADSLT -57 /* Invalid slot */ #endif // ERRNO_H

project4/nachos/code/userprog/exception.cc

#include "copyright.h" #include "main.h" #include "syscall.h" #include "ksyscall.h" //---------------------------------------------------------------------- // ExceptionHandler // Entry point into the Nachos kernel. Called when a user program // is executing, and either does a syscall, or generates an addressing // or arithmetic exception. // // For system calls, the following is the calling convention: // // system call code -- r2 // arg1 -- r4 // arg2 -- r5 // arg3 -- r6 // arg4 -- r7 // // The result of the system call, if any, must be put back into r2. // // If you are handling a system call, don't forget to increment the pc // before returning. (Or else you'll loop making the same system call forever!) // // "which" is the kind of exception. The list of possible exceptions // is in machine.h. //---------------------------------------------------------------------- void ExceptionHandler(ExceptionType which) { int type = kernel->machine->ReadRegister(2); DEBUG(dbgSys, "Received Exception " << which << " type: " << type << "\n"); switch (which) { case SyscallException: switch(type) { case SC_Halt: DEBUG(dbgSys, "Shutdown, initiated by user program.\n"); SysHalt(); break; case SC_Add: DEBUG(dbgSys, "Add " << kernel->machine->ReadRegister(4) << " + " << kernel->machine->ReadRegister(5) << "\n"); /* Process SysAdd Systemcall*/ int result; result = SysAdd(/* int op1 */(int)kernel->machine->ReadRegister(4), /* int op2 */(int)kernel->machine->ReadRegister(5)); DEBUG(dbgSys, "Add returning with " << result << "\n"); /* Prepare Result */ kernel->machine->WriteRegister(2, (int)result); break; case SC_Write: printf("Write system call made by %s\n", kernel->currentThread->getName()); break; case SC_Exit: printf("Exit system call made by %s\n", kernel->currentThread->getName()); kernel->currentThread->Finish(); break; default: cerr << "Unexpected system call " << type << "\n"; break; } break; default: cerr << "Unexpected user mode exception" << (int)which << "\n"; break; } /* Modify return point */ { /* set previous programm counter (debugging only)*/ kernel->machine->WriteRegister(PrevPCReg, kernel->machine->ReadRegister(PCReg)); /* set programm counter to next instruction (all Instructions are 4 byte wide)*/ kernel->machine->WriteRegister(PCReg, kernel->machine->ReadRegister(PCReg) + 4); /* set next programm counter for brach execution */ kernel->machine->WriteRegister(NextPCReg, kernel->machine->ReadRegister(PCReg)+4); } }

project4/nachos/code/userprog/syscall.h

/* syscalls.h * Nachos system call interface. These are Nachos kernel operations * that can be invoked from user programs, by trapping to the kernel * via the "syscall" instruction. * * This file is included by user programs and by the Nachos kernel. * * Copyright (c) 1992-1993 The Regents of the University of California. * All rights reserved. See copyright.h for copyright notice and limitation * of liability and disclaimer of warranty provisions. */ #ifndef SYSCALLS_H #define SYSCALLS_H #include "copyright.h" #include "errno.h" /* system call codes -- used by the stubs to tell the kernel which system call * is being asked for */ #define SC_Halt 0 #define SC_Exit 1 #define SC_Exec 2 #define SC_Join 3 #define SC_Create 4 #define SC_Remove 5 #define SC_Open 6 #define SC_Read 7 #define SC_Write 8 #define SC_Seek 9 #define SC_Close 10 #define SC_ThreadFork 11 #define SC_ThreadYield 12 #define SC_ExecV 13 #define SC_ThreadExit 14 #define SC_ThreadJoin 15 #define SC_Add 42 #ifndef IN_ASM /* The system call interface. These are the operations the Nachos * kernel needs to support, to be able to run user programs. * * Each of these is invoked by a user program by simply calling the * procedure; an assembly language stub stuffs the system call code * into a register, and traps to the kernel. The kernel procedures * are then invoked in the Nachos kernel, after appropriate error checking, * from the system call entry point in exception.cc. */ /* Stop Nachos, and print out performance stats */ void Halt(); /* * Add the two operants and return the result */ int Add(int op1, int op2); /* Address space control operations: Exit, Exec, Execv, and Join */ /* This user program is done (status = 0 means exited normally). */ void Exit(int status); /* A unique identifier for an executing user program (address space) */ typedef int SpaceId; /* A unique identifier for a thread within a task */ typedef int ThreadId; /* Run the specified executable, with no args */ /* This can be implemented as a call to ExecV. */ SpaceId Exec(char* exec_name); /* Run the executable, stored in the Nachos file "argv[0]", with * parameters stored in argv[1..argc-1] and return the * address space identifier */ SpaceId ExecV(int argc, char* argv[]); /* Only return once the user program "id" has finished. * Return the exit status. */ int Join(SpaceId id); /* File system operations: Create, Remove, Open, Read, Write, Close * These functions are patterned after UNIX -- files represent * both files *and* hardware I/O devices. * * Note that the Nachos file system has a stub implementation, which * can be used to support these system calls if the regular Nachos * file system has not been implemented. */ /* A unique identifier for an open Nachos file. */ typedef int OpenFileId; /* when an address space starts up, it has two open files, representing * keyboard input and display output (in UNIX terms, stdin and stdout). * Read and Write can be used directly on these, without first opening * the console device. */ #define ConsoleInput 0 #define ConsoleOutput 1 /* Create a Nachos file, with name "name" */ /* Note: Create does not open the file. */ /* Return 1 on success, negative error code on failure */ int Create(char *name); /* Remove a Nachos file, with name "name" */ int Remove(char *name); /* Open the Nachos file "name", and return an "OpenFileId" that can * be used to read and write to the file. */ OpenFileId Open(char *name); /* Write "size" bytes from "buffer" to the open file. * Return the number of bytes actually read on success. * On failure, a negative error code is returned. */ int Write(char *buffer, int size, OpenFileId id); /* Read "size" bytes from the open file into "buffer". * Return the number of bytes actually read -- if the open file isn't * long enough, or if it is an I/O device, and there aren't enough * characters to read, return whatever is available (for I/O devices, * you should always wait until you can return at least one character). */ int Read(char *buffer, int size, OpenFileId id); /* Set the seek position of the open file "id" * to the byte "position". */ int Seek(int position, OpenFileId id); /* Close the file, we're done reading and writing to it. * Return 1 on success, negative error code on failure */ int Close(OpenFileId id); /* User-level thread operations: Fork and Yield. To allow multiple * threads to run within a user program. * * Could define other operations, such as LockAcquire, LockRelease, etc. */ /* Fork a thread to run a procedure ("func") in the *same* address space * as the current thread. * Return a positive ThreadId on success, negative error code on failure */ ThreadId ThreadFork(void (*func)()); /* Yield the CPU to another runnable thread, whether in this address space * or not. */ void ThreadYield(); /* * Blocks current thread until lokal thread ThreadID exits with ThreadExit. * Function returns the ExitCode of ThreadExit() of the exiting thread. */ int ThreadJoin(ThreadId id); /* * Deletes current thread and returns ExitCode to every waiting lokal thread. */ void ThreadExit(int ExitCode); #endif /* IN_ASM */ #endif /* SYSCALL_H */

project4/nachos/code/userprog/noff.h

/* noff.h * Data structures defining the Nachos Object Code Format * * Basically, we only know about three types of segments: * code (read-only), initialized data, and unitialized data */ #define NOFFMAGIC 0xbadfad /* magic number denoting Nachos * object code file */ typedef struct segment { int virtualAddr; /* location of segment in virt addr space */ int inFileAddr; /* location of segment in this file */ int size; /* size of segment */ } Segment; typedef struct noffHeader { int noffMagic; /* should be NOFFMAGIC */ Segment code; /* executable code segment */ Segment initData; /* initialized data segment */ #ifdef RDATA Segment readonlyData; /* read only data */ #endif Segment uninitData; /* uninitialized data segment -- * should be zero'ed before use */ } NoffHeader;

project4/nachos/code/lib/sysdep.h

// sysdep.h // System-dependent interface. Nachos uses the routines defined // here, rather than directly calling the UNIX library functions, to // simplify porting between versions of UNIX, and even to // other systems, such as MSDOS and the Macintosh. // // Copyright (c) 1992-1996 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef SYSDEP_H #define SYSDEP_H #include "copyright.h" #include <iostream> #include <stdlib.h> #include <stdio.h> #include <string.h> using namespace std; // Process control: abort, exit, and sleep extern void Abort(); extern void Exit(int exitCode); extern void Delay(int seconds); extern void UDelay(unsigned int usec);// rcgood - to avoid spinners. // Initialize system so that cleanUp routine is called when user hits ctl-C extern void CallOnUserAbort(void (*cleanup)(int)); // Initialize the pseudo random number generator extern void RandomInit(unsigned seed); extern unsigned int RandomNumber(); // Allocate, de-allocate an array, such that de-referencing // just beyond either end of the array will cause an error extern char *AllocBoundedArray(int size); extern void DeallocBoundedArray(char *p, int size); // Check file to see if there are any characters to be read. // If no characters in the file, return without waiting. extern bool PollFile(int fd); // File operations: open/read/write/lseek/close, and check for error // For simulating the disk and the console devices. extern int OpenForWrite(char *name); extern int OpenForReadWrite(char *name, bool crashOnError); extern void Read(int fd, char *buffer, int nBytes); extern int ReadPartial(int fd, char *buffer, int nBytes); extern void WriteFile(int fd, char *buffer, int nBytes); extern void Lseek(int fd, int offset, int whence); extern int Tell(int fd); extern int Close(int fd); extern bool Unlink(char *name); // Other C library routines that are used by Nachos. // These are assumed to be portable, so we don't include a wrapper. extern "C" { int atoi(const char *str); double atof(const char *str); int abs(int i); void bcopy(const void *s1, void *s2, size_t n); void bzero(void *s, size_t n); } // Interprocess communication operations, for simulating the network extern int OpenSocket(); extern void CloseSocket(int sockID); extern void AssignNameToSocket(char *socketName, int sockID); extern void DeAssignNameToSocket(char *socketName); extern bool PollSocket(int sockID); extern void ReadFromSocket(int sockID, char *buffer, int packetSize); extern void SendToSocket(int sockID, char *buffer, int packetSize,char *toName); #endif // SYSDEP_H

project4/nachos/code/lib/bitmap.cc

project4/nachos/code/lib/bitmap.cc

// bitmap.cc
//  Routines to manage a bitmap -- an array of bits each of which
//  can be either on or off.  Represented as an array of integers.
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include   "copyright.h"
#include   "debug.h"
#include   "bitmap.h"

//----------------------------------------------------------------------
// BitMap::BitMap
//  Initialize a bitmap with "numItems" bits, so that every bit is clear.
//  it can be added somewhere on a list.
//
//  "numItems" is the number of bits in the bitmap.
//----------------------------------------------------------------------

Bitmap :: Bitmap ( int  numItems )  
{  
     int  i ;

    ASSERT ( numItems  >   0 );

    numBits  =  numItems ;
    numWords  =  divRoundUp ( numBits ,   BitsInWord );
    map  =   new   unsigned   int [ numWords ];
     for   ( =   0 ;  i  <  numWords ;  i ++ )   {
    map [ i ]   =   0 ;       // initialize map to keep Purify happy
     }
     for   ( =   0 ;  i  <  numBits ;  i ++ )   {
         Clear ( i );
     }
}

//----------------------------------------------------------------------
// Bitmap::~Bitmap
//  De-allocate a bitmap.
//----------------------------------------------------------------------

Bitmap ::~ Bitmap ()
{  
     delete  map ;
}

//----------------------------------------------------------------------
// Bitmap::Set
//  Set the "nth" bit in a bitmap.
//
//  "which" is the number of the bit to be set.
//----------------------------------------------------------------------

void
Bitmap :: Mark ( int  which )  
{  
    ASSERT ( which  >=   0   &&  which  <  numBits );

    map [ which  /   BitsInWord ]   |=   1   <<   ( which  %   BitsInWord );

    ASSERT ( Test ( which ));
}
    
//----------------------------------------------------------------------
// Bitmap::Clear
//  Clear the "nth" bit in a bitmap.
//
//  "which" is the number of the bit to be cleared.
//----------------------------------------------------------------------

void  
Bitmap :: Clear ( int  which )  
{
    ASSERT ( which  >=   0   &&  which  <  numBits );

    map [ which  /   BitsInWord ]   &=   ~ ( 1   <<   ( which  %   BitsInWord ));

    ASSERT ( ! Test ( which ));
}

//----------------------------------------------------------------------
// Bitmap::Test
//  Return TRUE if the "nth" bit is set.
//
//  "which" is the number of the bit to be tested.
//----------------------------------------------------------------------

bool  
Bitmap :: Test ( int  which )   const
{
    ASSERT ( which  >=   0   &&  which  <  numBits );
    
     if   ( map [ which  /   BitsInWord ]   &   ( 1   <<   ( which  %   BitsInWord )))   {
     return  TRUE ;
     }   else   {
     return  FALSE ;
     }
}

//----------------------------------------------------------------------
// Bitmap::FindAndSet
//  Return the number of the first bit which is clear.
//  As a side effect, set the bit (mark it as in use).
//  (In other words, find and allocate a bit.)
//
//  If no bits are clear, return -1.
//----------------------------------------------------------------------

int  
Bitmap :: FindAndSet ()  
{
     for   ( int  i  =   0 ;  i  <  numBits ;  i ++ )   {
     if   ( ! Test ( i ))   {
         Mark ( i );
         return  i ;
     }
     }
     return   - 1 ;
}

//----------------------------------------------------------------------
// Bitmap::NumClear
//  Return the number of clear bits in the bitmap.
//  (In other words, how many bits are unallocated?)
//----------------------------------------------------------------------

int  
Bitmap :: NumClear ()   const
{
     int  count  =   0 ;

     for   ( int  i  =   0 ;  i  <  numBits ;  i ++ )   {
     if   ( ! Test ( i ))   {
        count ++ ;
     }
     }
     return  count ;
}

//----------------------------------------------------------------------
// Bitmap::Print
//  Print the contents of the bitmap, for debugging.
//
//  Could be done in a number of ways, but we just print the #'s of
//  all the bits that are set in the bitmap.
//----------------------------------------------------------------------

void
Bitmap :: Print ()   const
{
    cout  <<   "Bitmap set:\n" ;  
     for   ( int  i  =   0 ;  i  <  numBits ;  i ++ )   {
     if   ( Test ( i ))   {
        cout  <<  i  <<   ", " ;
     }
     }
    cout  <<   "\n" ;  
}


//----------------------------------------------------------------------
// Bitmap::SelfTest
//  Test whether this module is working.
//----------------------------------------------------------------------

void
Bitmap :: SelfTest ()  
{
     int  i ;
    
    ASSERT ( numBits  >=   BitsInWord );    // bitmap must be big enough

    ASSERT ( NumClear ()   ==  numBits );    // bitmap must be empty
    ASSERT ( FindAndSet ()   ==   0 );
     Mark ( 31 );
    ASSERT ( Test ( 0 )   &&   Test ( 31 ));

    ASSERT ( FindAndSet ()   ==   1 );
     Clear ( 0 );
     Clear ( 1 );
     Clear ( 31 );

     for   ( =   0 ;  i  <  numBits ;  i ++ )   {
         Mark ( i );
     }
    ASSERT ( FindAndSet ()   ==   - 1 );       // bitmap should be full!
     for   ( =   0 ;  i  <  numBits ;  i ++ )   {
         Clear ( i );
     }
}

project4/nachos/code/lib/debug.h

// debug.h // Data structures for debugging routines. // // The debugging routines allow the user to turn on selected // debugging messages, controllable from the command line arguments // passed to Nachos (-d). You are encouraged to add your own // debugging flags. Please.... // // Copyright (c) 1992-1996 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef DEBUG_H #define DEBUG_H #include "copyright.h" #include "utility.h" #include "sysdep.h" // The pre-defined debugging flags are: const char dbgAll = '+'; // turn on all debug messages const char dbgThread = 't'; // threads const char dbgSynch = 's'; // locks, semaphores, condition vars const char dbgInt = 'i'; // interrupt emulation const char dbgMach = 'm'; // machine emulation const char dbgDisk = 'd'; // disk emulation const char dbgFile = 'f'; // file system const char dbgAddr = 'a'; // address spaces const char dbgNet = 'n'; // network emulation const char dbgSys = 'u'; // systemcall class Debug { public: Debug(char *flagList); bool IsEnabled(char flag); private: char *enableFlags; // controls which DEBUG messages are printed }; extern Debug *debug; //---------------------------------------------------------------------- // DEBUG // If flag is enabled, print a message. //---------------------------------------------------------------------- #define DEBUG(flag,expr) \ if (!debug->IsEnabled(flag)) {} else { \ cerr << expr << "\n"; \ } //---------------------------------------------------------------------- // ASSERT // If condition is false, print a message and dump core. // Useful for documenting assumptions in the code. // // NOTE: needs to be a #define, to be able to print the location // where the error occurred. //---------------------------------------------------------------------- #define ASSERT(condition) \ if (condition) {} else { \ cerr << "Assertion failed: line " << __LINE__ << " file " << __FILE__ << "\n"; \ Abort(); \ } //---------------------------------------------------------------------- // ASSERTNOTREACHED // Print a message and dump core (equivalent to ASSERT(FALSE) without // making the compiler whine). Useful for documenting when // code should not be reached. // // NOTE: needs to be a #define, to be able to print the location // where the error occurred. //---------------------------------------------------------------------- #define ASSERTNOTREACHED() \ { \ cerr << "Assertion failed: line " << __LINE__ << " file " << __FILE__ << "\n"; \ Abort(); \ } //---------------------------------------------------------------------- // ASSERTUNIMPLEMENTED // Print a message that unimplemented code is executed and dump core //---------------------------------------------------------------------- #define UNIMPLEMENTED() \ { \ cerr << "Reached UNIMPLEMENTED function " << __FUNCTION__ << " in file: " \ << __FILE__ << " line: " << __LINE__ << ".\n"; \ } #endif // DEBUG_H

project4/nachos/code/lib/libtest.h

// libtest.h // Defines self test module for standard library routines. // // Copyright (c) 1992-1996 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef LIBTEST_H #define LIBTEST_H #include "copyright.h" extern void LibSelfTest(); #endif // LIBTEST_H

project4/nachos/code/lib/sysdep.cc

project4/nachos/code/lib/sysdep.cc

// sysdep.cc
//  Implementation of system-dependent interface.  Nachos uses the 
//  routines defined here, rather than directly calling the UNIX library,
//  to simplify porting between versions of UNIX, and even to
//  other systems, such as MSDOS.
//
//  On UNIX, almost all of these routines are simple wrappers
//  for the underlying UNIX system calls.
//
//  NOTE: all of these routines refer to operations on the underlying
//  host machine (e.g., the DECstation, SPARC, etc.), supporting the 
//  Nachos simulation code.  Nachos implements similar operations,
//  (such as opening a file), but those are implemented in terms
//  of hardware devices, which are simulated by calls to the underlying
//  routines in the host workstation OS.
//
//  This file includes lots of calls to C routines.  C++ requires
//  us to wrap all C definitions with a "extern "C" block".
//  This prevents the internal forms of the names from being
//  changed by the C++ compiler.
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include   "copyright.h"
#include   "debug.h"
#include   "sysdep.h"
#include   < stdlib . h >
#include   < unistd . h >
#include   < sys / time . h >
#include   < sys / file . h >
#include   < sys / socket . h >
#include   < sys / un . h >
#include   < cerrno >

#ifdef  SOLARIS
// KMS
// for open()
#include   < fcntl . h >
#endif

#ifdef  LINUX      // at this point, linux doesn't support mprotect 
#define  NO_MPROT     
#endif
#ifdef  DOS   // neither does DOS
#define  NO_MPROT
#endif

extern   "C"   {
#include   < signal . h >
#include   < sys / types . h >

#ifndef  NO_MPROT 
#include   < sys / mman . h >
#endif

// UNIX routines called by procedures in this file 

#if  defined CYGWIN
  size_t getpagesize ( void );
#else
  int  getpagesize ( void );
#endif
unsigned  sleep ( unsigned );
//#ifdef SOLARIS
//int usleep(useconds_t);
//#else
//void usleep(unsigned int);  // rcgood - to avoid spinning processes.
//#endif


#ifndef  NO_MPROT    

#ifdef  OSF
#define  OSF_OR_AIX
#endif
#ifdef  AIX
#define  OSF_OR_AIX
#endif

#ifdef  OSF_OR_AIX
int  mprotect ( const   void   * ,   long   unsigned   int ,   int );
#else
int  mprotect ( char   * ,   unsigned   int ,   int );
#endif
#endif

#if  defined ( BSD )   ||  defined ( SOLARIS )   ||  defined ( LINUX )
//KMS
// added Solaris and LINUX
int  select ( int  nfds ,  fd_set  * readfds ,  fd_set  * writefds ,  fd_set  * exceptfds ,
              struct  timeval  * timeout );
#else
int  select ( int  numBits ,   void   * readFds ,   void   * writeFds ,   void   * exceptFds ,  
     struct  timeval  * timeout );
#endif

int  socket ( int ,   int ,   int );

#if  defined ( SUNOS )   ||  defined ( ULTRIX )
long  tell ( int );
int  bind  ( int ,   const   void * ,   int );
int  recvfrom  ( int ,   void * ,   int ,   int ,   void * ,   int   * );
int  sendto  ( int ,   const   void * ,   int ,   int ,   void * ,   int );
#endif

}

//----------------------------------------------------------------------
// CallOnUserAbort
//  Arrange that "func" will be called when the user aborts (e.g., by
//  hitting ctl-C.
//----------------------------------------------------------------------

void  
CallOnUserAbort ( void   ( * func )( int ))
{
     ( void ) signal ( SIGINT ,  func );
}

//----------------------------------------------------------------------
// Delay
//  Put the UNIX process running Nachos to sleep for x seconds,
//  to give the user time to start up another invocation of Nachos
//  in a different UNIX shell.
//----------------------------------------------------------------------

void  
Delay ( int  seconds )
{
     ( void )  sleep (( unsigned )  seconds );
}

//----------------------------------------------------------------------
// UDelay
//  Put the UNIX process running Nachos to sleep for x microseconds,
//  to prevent an idle Nachos process from spinning...
//----------------------------------------------------------------------

void  
UDelay ( unsigned   int  useconds )
{
//#ifdef SOLARIS
//   usleep(useconds_t useconds);
//#else
//   usleep(useconds);
//#endif /* SOLARIS */

}

//----------------------------------------------------------------------
// Abort
//  Quit and drop core.
//----------------------------------------------------------------------

void  
Abort ()
{
    abort ();
}

//----------------------------------------------------------------------
// Exit
//  Quit without dropping core.
//----------------------------------------------------------------------

void  
Exit ( int  exitCode )
{
    exit ( exitCode );
}

//----------------------------------------------------------------------
// RandomInit
//  Initialize the pseudo-random number generator.  We use the
//  now obsolete "srand" and "rand" because they are more portable!
//----------------------------------------------------------------------

void  
RandomInit ( unsigned  seed )
{
    srand ( seed );
}

//----------------------------------------------------------------------
// RandomNumber
//  Return a pseudo-random number.
//----------------------------------------------------------------------

unsigned   int  
RandomNumber ()
{
     return  rand ();
}

//----------------------------------------------------------------------
// AllocBoundedArray
//  Return an array, with the two pages just before 
//  and after the array unmapped, to catch illegal references off
//  the end of the array.  Particularly useful for catching overflow
//  beyond fixed-size thread execution stacks.
//
//  Note: Just return the useful part!
//
//  "size" -- amount of useful space needed (in bytes)
//----------------------------------------------------------------------

char   *  
AllocBoundedArray ( int  size )
{
#ifdef  NO_MPROT
     return   new   char [ size ];
#else
     int  pgSize  =  getpagesize ();
     char   * ptr  =   new   char [ pgSize  *   2   +  size ];

    mprotect ( ptr ,  pgSize ,   0 );
    mprotect ( ptr  +  pgSize  +  size ,  pgSize ,   0 );
     return  ptr  +  pgSize ;
#endif
}

//----------------------------------------------------------------------
// DeallocBoundedArray
//  Deallocate an array of integers, unprotecting its two boundary pages.
//
//  "ptr" -- the array to be deallocated
//  "size" -- amount of useful space in the array (in bytes)
//----------------------------------------------------------------------

#ifdef  NO_MPROT
void  
DeallocBoundedArray ( char   * ptr ,   int   /* size */ )
{
     delete   []  ptr ;
}
#else
void  
DeallocBoundedArray ( char   * ptr ,   int  size )
{
     int  pgSize  =  getpagesize ();

    mprotect ( ptr  -  pgSize ,  pgSize ,  PROT_READ  |  PROT_WRITE  |  PROT_EXEC );
    mprotect ( ptr  +  size ,  pgSize ,  PROT_READ  |  PROT_WRITE  |  PROT_EXEC );
     delete   []   ( ptr  -  pgSize );
}
#endif

//----------------------------------------------------------------------
// PollFile
//  Check open file or open socket to see if there are any 
//  characters that can be read immediately.  If so, read them
//  in, and return TRUE.
//
//  "fd" -- the file descriptor of the file to be polled
//----------------------------------------------------------------------

bool
PollFile ( int  fd )
{
#if  defined ( SOLARIS )   ||  defined ( LINUX )
// KMS
    fd_set rfd , wfd , xfd ;
#else
     int  rfd  =   ( 1   <<  fd ),  wfd  =   0 ,  xfd  =   0 ;
#endif
     int  retVal ;
     struct  timeval pollTime ;

#if  defined ( SOLARIS )   ||  defined ( LINUX )
// KMS
    FD_ZERO ( & rfd );
    FD_ZERO ( & wfd );
    FD_ZERO ( & xfd );
    FD_SET ( fd , & rfd );
#endif

// don't wait if there are no characters on the file
    pollTime . tv_sec  =   0 ;
    pollTime . tv_usec  =   0 ;

// poll file or socket
#if  defined ( BSD )
    retVal  =  select ( 32 ,   ( fd_set * ) & rfd ,   ( fd_set * ) & wfd ,   ( fd_set * ) & xfd ,   & pollTime );
#elif  defined ( SOLARIS )   ||  defined ( LINUX )
     // KMS
    retVal  =  select ( 32 ,   & rfd ,   & wfd ,   & xfd ,   & pollTime );
#else
    retVal  =  select ( 32 ,   & rfd ,   & wfd ,   & xfd ,   & pollTime );
#endif

    ASSERT (( retVal  ==   0 )   ||   ( retVal  ==   1 ));
     if   ( retVal  ==   0 )
     return  FALSE ;                         // no char waiting to be read
     return  TRUE ;
}

//----------------------------------------------------------------------
// OpenForWrite
//  Open a file for writing.  Create it if it doesn't exist; truncate it 
//  if it does already exist.  Return the file descriptor.
//
//  "name" -- file name
//----------------------------------------------------------------------

int
OpenForWrite ( char   * name )
{
     int  fd  =  open ( name ,  O_RDWR | O_CREAT | O_TRUNC ,   0666 );

    ASSERT ( fd  >=   0 );  
     return  fd ;
}

//----------------------------------------------------------------------
// OpenForReadWrite
//  Open a file for reading or writing.
//  Return the file descriptor, or error if it doesn't exist.
//
//  "name" -- file name
//----------------------------------------------------------------------

int
OpenForReadWrite ( char   * name ,   bool  crashOnError )
{
     int  fd  =  open ( name ,  O_RDWR ,   0 );

    ASSERT ( ! crashOnError  ||  fd  >=   0 );
     return  fd ;
}

//----------------------------------------------------------------------
// Read
//  Read characters from an open file.  Abort if read fails.
//----------------------------------------------------------------------

void
Read ( int  fd ,   char   * buffer ,   int  nBytes )
{
     int  retVal  =  read ( fd ,  buffer ,  nBytes );
    ASSERT ( retVal  ==  nBytes );
}

//----------------------------------------------------------------------
// ReadPartial
//  Read characters from an open file, returning as many as are
//  available.
//----------------------------------------------------------------------

int
ReadPartial ( int  fd ,   char   * buffer ,   int  nBytes )
{
     return  read ( fd ,  buffer ,  nBytes );
}


//----------------------------------------------------------------------
// WriteFile
//  Write characters to an open file.  Abort if write fails.
//----------------------------------------------------------------------

void
WriteFile ( int  fd ,   char   * buffer ,   int  nBytes )
{
     int  retVal  =  write ( fd ,  buffer ,  nBytes );
    ASSERT ( retVal  ==  nBytes );
}

//----------------------------------------------------------------------
// Lseek
//  Change the location within an open file.  Abort on error.
//----------------------------------------------------------------------

void  
Lseek ( int  fd ,   int  offset ,   int  whence )
{
     int  retVal  =  lseek ( fd ,  offset ,  whence );
    ASSERT ( retVal  >=   0 );
}

//----------------------------------------------------------------------
// Tell
//  Report the current location within an open file.
//----------------------------------------------------------------------

int  
Tell ( int  fd )
{
#if  defined ( BSD )   ||  defined ( SOLARIS )   ||  defined ( LINUX )
     return  lseek ( fd , 0 , SEEK_CUR );   // 386BSD doesn't have the tell() system call
                                  // neither do Solaris and Linux  -KMS
#else
     return  tell ( fd );
#endif
}


//----------------------------------------------------------------------
// Close
//  Close a file.  Abort on error.
//----------------------------------------------------------------------

int  
Close ( int  fd )
{
     int  retVal  =  close ( fd );
    ASSERT ( retVal  >=   0 );  
     return  retVal ;
}

//----------------------------------------------------------------------
// Unlink
//  Delete a file.
//----------------------------------------------------------------------

bool  
Unlink ( char   * name )
{
     return  unlink ( name );
}

//----------------------------------------------------------------------
// OpenSocket
//  Open an interprocess communication (IPC) connection.  For now, 
//  just open a datagram port where other Nachos (simulating 
//  workstations on a network) can send messages to this Nachos.
//----------------------------------------------------------------------

int
OpenSocket ()
{
     int  sockID ;
    
    sockID  =  socket ( AF_UNIX ,  SOCK_DGRAM ,   0 );
    ASSERT ( sockID  >=   0 );

     return  sockID ;
}

//----------------------------------------------------------------------
// CloseSocket
//  Close the IPC connection. 
//----------------------------------------------------------------------

void
CloseSocket ( int  sockID )
{
     ( void )  close ( sockID );
}

//----------------------------------------------------------------------
// InitSocketName
//  Initialize a UNIX socket address -- magical!
//----------------------------------------------------------------------

static   void  
InitSocketName ( struct  sockaddr_un  * uname ,   char   * name )
{
    uname -> sun_family  =  AF_UNIX ;
    strcpy ( uname -> sun_path ,  name );
}

//----------------------------------------------------------------------
// AssignNameToSocket
//  Give a UNIX file name to the IPC port, so other instances of Nachos
//  can locate the port. 
//----------------------------------------------------------------------

void
AssignNameToSocket ( char   * socketName ,   int  sockID )
{
     struct  sockaddr_un uName ;
     int  retVal ;

     ( void )  unlink ( socketName );      // in case it's still around from last time

     InitSocketName ( & uName ,  socketName );
    retVal  =  bind ( sockID ,   ( struct  sockaddr  * )   & uName ,   sizeof ( uName ));
    ASSERT ( retVal  >=   0 );
    DEBUG ( dbgNet ,   "Created socket "   <<  socketName );
}

//----------------------------------------------------------------------
// DeAssignNameToSocket
//  Delete the UNIX file name we assigned to our IPC port, on cleanup.
//----------------------------------------------------------------------
void
DeAssignNameToSocket ( char   * socketName )
{
     ( void )  unlink ( socketName );
}

//----------------------------------------------------------------------
// PollSocket
//  Return TRUE if there are any messages waiting to arrive on the
//  IPC port.
//----------------------------------------------------------------------
bool
PollSocket ( int  sockID )
{
     return   PollFile ( sockID );      // on UNIX, socket ID's are just file ID's
}

//----------------------------------------------------------------------
// ReadFromSocket
//  Read a fixed size packet off the IPC port.  Abort on error.
//----------------------------------------------------------------------
void
ReadFromSocket ( int  sockID ,   char   * buffer ,   int  packetSize )
{
     int  retVal ;
     struct  sockaddr_un uName ;
#ifdef  LINUX
    socklen_t size  =   sizeof ( uName );
#else
     int  size  =   sizeof ( uName );
#endif
   
    retVal  =  recvfrom ( sockID ,  buffer ,  packetSize ,   0 ,
                    ( struct  sockaddr  * )   & uName ,   & size );

     if   ( retVal  !=  packetSize )   {
        perror ( "in recvfrom" );
#if  defined CYGWIN
    cerr  <<   "called with "   <<  packetSize  <<   ", got back "   <<  retVal 
                         <<   ", and "   <<   "\n" ;
#else    
        cerr  <<   "called with "   <<  packetSize  <<   ", got back "   <<  retVal 
                         <<   ", and "   <<  errno  <<   "\n" ;
#endif  
     }
    ASSERT ( retVal  ==  packetSize );
}

//----------------------------------------------------------------------
//    modified by KMS to add retry...
// SendToSocket
//  Transmit a fixed size packet to another Nachos' IPC port.
//  Try 10 times with a one second delay between attempts.
//      This is useful, e.g., to give the other socket a chance
//      to get set up.
//      Terminate if we still fail after 10 tries.
//----------------------------------------------------------------------
void
SendToSocket ( int  sockID ,   char   * buffer ,   int  packetSize ,   char   * toName )
{
     struct  sockaddr_un uName ;
     int  retVal ;
     int  retryCount ;

     InitSocketName ( & uName ,  toName );

     for ( retryCount = 0 ; retryCount  <   10 ; retryCount ++ )   {
      retVal  =  sendto ( sockID ,  buffer ,  packetSize ,   0 ,  
             ( struct  sockaddr  * )   & uName ,   sizeof ( uName ));
       if   ( retVal  ==  packetSize )   return ;
       // if we did not succeed, we should see a negative
       // return value indicating complete failure.  If we
       // don't, something fishy is going on...
      ASSERT ( retVal  <   0 );
       // wait a second before trying again
       Delay ( 1 );
     }
     // At this point, we have failed many times
     // The most common reason for this is that the target machine
     // has halted and its socket no longer exists.
     // We simply do nothing (drop the packet).
     // This may mask other kinds of failures, but it is the
     // right thing to do in the common case.
}

project4/nachos/code/lib/hash.cc

project4/nachos/code/lib/hash.cc

// hash.cc 
//      Routines to manage a self-expanding hash table of arbitrary things.
//  The hashing function is supplied by the objects being put into
//  the table; we use chaining to resolve hash conflicts.
//
//  The hash table is implemented as an array of sorted lists,
//  and we expand the hash table if the number of elements in the table
//  gets too big.
// 
//      NOTE: Mutual exclusion must be provided by the caller.
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

const   int   InitialBuckets   =   4 ;     // how big a hash table do we start with
const   int   ResizeRatio   =   3 ;    // when do we grow the hash table?
const   int   IncreaseSizeBy   =   4 ;     // how much do we grow table when needed?

#include   "copyright.h"

//----------------------------------------------------------------------
// HashTable<Key,T>::HashTable
//  Initialize a hash table, empty to start with.
//  Elements can now be added to the table.
//----------------------------------------------------------------------

template   < class   Key ,   class  T >
HashTable < Key , T >:: HashTable ( Key   ( * get )( T x ),   unsigned   ( * hFunc )( Key  x ))
{  
    numItems  =   0 ;
     InitBuckets ( InitialBuckets );
    getKey  =  get ;
    hash  =  hFunc ;
}

//----------------------------------------------------------------------
// HashTable<Key,T>::InitBuckets
//  Initialize the bucket array for a hash table.
//  Called by the constructor and by ReHash().
//----------------------------------------------------------------------

template   < class   Key ,   class  T >
void
HashTable < Key , T >:: InitBuckets ( int  sz )
{  
    numBuckets  =  sz ;
    buckets  =   new   Bucket [ numBuckets ];
     for   ( int  i  =   0 ;  i  <  sz ;  i ++ )   {
        buckets [ i ]   =   new   List < T > ;
     }
}

//----------------------------------------------------------------------
// HashTable<T>::~HashTable
//  Prepare a hash table for deallocation.  
//----------------------------------------------------------------------

template   < class   Key ,   class  T >
HashTable < Key , T >::~ HashTable ()
{  
    ASSERT ( IsEmpty ());        // make sure table is empty
     DeleteBuckets ( buckets ,  numBuckets );
}

//----------------------------------------------------------------------
// HashTable<Key,T>::DeleteBuckets
//  De-Initialize the bucket array for a hash table.
//  Called by the destructor and by ReHash().
//----------------------------------------------------------------------

template   < class   Key ,   class  T >
void
HashTable < Key , T >:: DeleteBuckets ( List < T >   ** table ,   int  sz )
{  
     for   ( int  i  =   0 ;  i  <  sz ;  i ++ )   {
         delete  table [ i ];
     }
     delete   []  table ;
}

//----------------------------------------------------------------------
// HashTable<Key,T>::HashValue
//      Return hash table bucket that would contain key.
//----------------------------------------------------------------------

template   < class   Key ,   class  T >
int
HashTable < Key ,  T >:: HashValue ( Key  key )   const  
{
     int  result  =   ( * hash )( key )   %  numBuckets ;
    ASSERT ( result  >=   0   &&  result  <  numBuckets );
     return  result ;
}

//----------------------------------------------------------------------
// HashTable<Key,T>::Insert
//      Put an item into the hashtable.
//      
//  Resize the table if the # of elements / # of buckets is too big.
//  Then allocate a HashElement to keep track of the key, item pair,
//  and add it to the right bucket.
//
//  "key" is the key we'll use to find this item.
//  "item" is the thing to put in the table.
//----------------------------------------------------------------------

template   < class   Key ,   class  T >
void
HashTable < Key , T >:: Insert ( T item )
{
     Key  key  =  getKey ( item );

    ASSERT ( ! IsInTable ( key ));

     if   (( numItems  /  numBuckets )   >=   ResizeRatio )   {
     ReHash ();
     }

    buckets [ HashValue ( key )] -> Append ( item );
    numItems ++ ;

    ASSERT ( IsInTable ( key ));
}

//----------------------------------------------------------------------
// HashTable<Key,T>::ReHash
//      Increase the size of the hashtable, by 
//    (i) making a new table
//    (ii) moving all the elements into the new table
//    (iii) deleting the old table
//----------------------------------------------------------------------

template   < class   Key ,   class  T >
void
HashTable < Key , T >:: ReHash ()
{
     Bucket   * oldTable  =  buckets ;
     int  oldSize  =  numBuckets ;
    T item ;

     SanityCheck ();
     InitBuckets ( numBuckets  *   IncreaseSizeBy );

     for   ( int  i  =   0 ;  i  <  oldSize ;  i ++ )   {
     while   ( ! oldTable [ i ] -> IsEmpty ())   {
        item  =  oldTable [ i ] -> RemoveFront ();
        buckets [ HashValue ( getKey ( item ))] -> Append ( item );
         }
     }
     DeleteBuckets ( oldTable ,  oldSize );
     SanityCheck ();
}

//----------------------------------------------------------------------
// HashTable<Key,T>::FindInBucket
//      Find an item in a hash table bucket, from it's key
//
//  "bucket" -- the list storing the item, if it's in the table 
//  "key" -- the key uniquely identifying the item
// 
// Returns:
//  Whether item is found, and if found, the item.
//----------------------------------------------------------------------

template   < class   Key ,   class  T >
bool
HashTable < Key , T >:: FindInBucket ( int  bucket ,  
                 Key  key ,  T  * itemPtr )   const
{
     ListIterator < T >  iterator ( buckets [ bucket ]);

     for   (;   ! iterator . IsDone ();  iterator . Next ())   {
     if   ( key  ==  getKey ( iterator . Item ()))   {   // found!
         * itemPtr  =  iterator . Item ();
         return  TRUE ;
         }
     }
     * itemPtr  =  NULL ;
     return  FALSE ;
}

//----------------------------------------------------------------------
// HashTable<Key,T>::Find
//      Find an item from the hash table.
// 
// Returns:
//  The item or NULL if not found. 
//----------------------------------------------------------------------

template   < class   Key ,   class  T >
bool
HashTable < Key , T >:: Find ( Key  key ,  T  * itemPtr )   const
{
     int  bucket  =   HashValue ( key );
    
     return   FindInBucket ( bucket ,  key ,  itemPtr );  
}

//----------------------------------------------------------------------
// HashTable<Key,T>::Remove
//      Remove an item from the hash table. The item must be in the table.
// 
// Returns:
//  The removed item.
//----------------------------------------------------------------------

template   < class   Key ,   class  T >
T
HashTable < Key , T >:: Remove ( Key  key )
{
     int  bucket  =   HashValue ( key );
    T item ;
     bool  found  =   FindInBucket ( bucket ,  key ,   & item );  

    ASSERT ( found );    // item must be in table

    buckets [ bucket ] -> Remove ( item );
    numItems -- ;

    ASSERT ( ! IsInTable ( key ));
     return  item ;
}


//----------------------------------------------------------------------
// HashTable<Key,T>::Apply
//      Apply function to every item in the hash table.
//
//  "func" -- the function to apply
//----------------------------------------------------------------------

template   < class   Key , class  T >
void
HashTable < Key , T >:: Apply ( void   ( * func )( T ))   const
{
     for   ( int  bucket  =   0 ;  bucket  <  numBuckets ;  bucket ++ )   {
        buckets [ bucket ] -> Apply ( func );
     }
}

//----------------------------------------------------------------------
// HashTable<Key,T>::FindNextFullBucket
//      Find the next bucket in the hash table that has any items in it.
//
//  "bucket" -- where to start looking for full buckets
//----------------------------------------------------------------------

template   < class   Key , class  T >
int
HashTable < Key , T >:: FindNextFullBucket ( int  bucket )   const
{  
     for   (;  bucket  <  numBuckets ;  bucket ++ )   {
     if   ( ! buckets [ bucket ] -> IsEmpty ())   {
          break ;
     }
     }
     return  bucket ;
}

//----------------------------------------------------------------------
// HashTable<Key,T>::SanityCheck
//      Test whether this is still a legal hash table.
//
//  Tests: are all the buckets legal?
//         does the table have the right # of elements?
//         do all the elements hash to where they are stored?
//----------------------------------------------------------------------

template   < class   Key ,   class  T >
void  
HashTable < Key , T >:: SanityCheck ()   const
{
     int  numFound  =   0 ;
     ListIterator < T >   * iterator ;

     for   ( int  i  =   0 ;  i  <  numBuckets ;  i ++ )   {
    buckets [ i ] -> SanityCheck ();
    numFound  +=  buckets [ i ] -> NumInList ();
    iterator  =   new   ListIterator < T > ( buckets [ i ]);
         for   (;   ! iterator -> IsDone ();  iterator -> Next ())   {
        ASSERT ( ==   HashValue ( getKey ( iterator -> Item ())));
         }
         delete  iterator ;
     }
    ASSERT ( numItems  ==  numFound );

}

//----------------------------------------------------------------------
// HashTable<Key,T>::SelfTest
//      Test whether this module is working.
//----------------------------------------------------------------------

template   < class   Key ,   class  T >
void  
HashTable < Key , T >:: SelfTest ( * p ,   int  numEntries )
{
     int  i ;
     HashIterator < Key ,  T >   * iterator  =   new   HashIterator < Key , T > ( this );
    
     SanityCheck ();
    ASSERT ( IsEmpty ());    // check that table is empty in various ways
     for   (;   ! iterator -> IsDone ();  iterator -> Next ())   {
    ASSERTNOTREACHED ();
     }
     delete  iterator ;

     for   ( =   0 ;  i  <  numEntries ;  i ++ )   {
         Insert ( p [ i ]);
        ASSERT ( IsInTable ( getKey ( p [ i ])));
        ASSERT ( ! IsEmpty ());
     }
    
     // should be able to get out everything we put in
     for   ( =   0 ;  i  <  numEntries ;  i ++ )   {   
        ASSERT ( Remove ( getKey ( p [ i ]))   ==  p [ i ]);
     }

    ASSERT ( IsEmpty ());
     SanityCheck ();
}


//----------------------------------------------------------------------
// HashIterator<Key,T>::HashIterator
//      Initialize a data structure to allow us to step through
//  every entry in a has table.
//----------------------------------------------------------------------

template   < class   Key ,   class  T >
HashIterator < Key , T >:: HashIterator ( HashTable < Key , T >   * tbl )  
{  
    table  =  tbl ;
    bucket  =  table -> FindNextFullBucket ( 0 );
    bucketIter  =  NULL ;
     if   ( bucket  <  table -> numBuckets )   {
    bucketIter  =   new   ListIterator < T > ( table -> buckets [ bucket ]);
     }
}

//----------------------------------------------------------------------
// HashIterator<Key,T>::Next
//      Update iterator to point to the next item in the table.
//----------------------------------------------------------------------

template   < class   Key , class  T >
void
HashIterator < Key , T >:: Next ()  
{  
    bucketIter -> Next ();
     if   ( bucketIter -> IsDone ())   {
     delete  bucketIter ;
    bucketIter  =  NULL ;
        bucket  =  table -> FindNextFullBucket ( ++ bucket );
         if   ( bucket  <  table -> numBuckets )   {
        bucketIter  =   new   ListIterator < T > ( table -> buckets [ bucket ]);
         }
     }
}

project4/nachos/code/lib/debug.cc

project4/nachos/code/lib/debug.cc

// debug.cc 
//  Debugging routines.  Allows users to control whether to 
//  print DEBUG statements, based on a command line argument.
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include   "copyright.h"
#include   "utility.h"
#include   "debug.h"  
#include   "string.h"

//----------------------------------------------------------------------
// Debug::Debug
//      Initialize so that only DEBUG messages with a flag in flagList 
//  will be printed.
//
//  If the flag is "+", we enable all DEBUG messages.
//
//  "flagList" is a string of characters for whose DEBUG messages are 
//      to be enabled.
//----------------------------------------------------------------------

Debug :: Debug ( char   * flagList )
{
    enableFlags  =  flagList ;
}


//----------------------------------------------------------------------
// Debug::IsEnabled
//      Return TRUE if DEBUG messages with "flag" are to be printed.
//----------------------------------------------------------------------

bool
Debug :: IsEnabled ( char  flag )
{
     if   ( enableFlags  !=  NULL )   {
     return   (( strchr ( enableFlags ,  flag )   !=   0 )  
         ||   ( strchr ( enableFlags ,   '+' )   !=   0 ));
     }   else   {
         return  FALSE ;
     }
}

project4/nachos/code/lib/copyright.h

/* Copyright (c) 1992-1996 The Regents of the University of California. All rights reserved. Permission to use, copy, modify, and distribute this software and its documentation for any purpose, without fee, and without written agreement is hereby granted, provided that the above copyright notice and the following two paragraphs appear in all copies of this software. IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */ #ifdef MAIN /* include the copyright message in every executable */ static char *copyright = "Copyright (c) 1992-1993 The Regents of the University of California. All rights reserved."; #endif // MAIN

project4/nachos/code/lib/list.h

// list.h // Data structures to manage LISP-like lists. // // As in LISP, a list can contain any type of data structure // as an item on the list: thread control blocks, // pending interrupts, etc. Allocation and deallocation of the // items on the list are to be done by the caller. // // Copyright (c) 1992-1996 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef LIST_H #define LIST_H #include "copyright.h" #include "debug.h" // The following class defines a "list element" -- which is // used to keep track of one item on a list. It is equivalent to a // LISP cell, with a "car" ("next") pointing to the next element on the list, // and a "cdr" ("item") pointing to the item on the list. // // This class is private to this module (and classes that inherit // from this module). Made public for notational convenience. template <class T> class ListElement { public: ListElement(T itm); // initialize a list element ListElement *next; // next element on list, NULL if this is last T item; // item on the list }; // The following class defines a "list" -- a singly linked list of // list elements, each of which points to a single item on the list. // The class has been tested only for primitive types (ints, pointers); // no guarantees it will work in general. For instance, all types // to be inserted into a list must have a "==" operator defined. template <class T> class ListIterator; template <class T> class List { public: List(); // initialize the list virtual ~List(); // de-allocate the list virtual void Prepend(T item);// Put item at the beginning of the list virtual void Append(T item); // Put item at the end of the list T Front() { return first->item; } // Return first item on list // without removing it T RemoveFront(); // Take item off the front of the list void Remove(T item); // Remove specific item from list bool IsInList(T item) const;// is the item in the list? unsigned int NumInList() { return numInList;}; // how many items in the list? bool IsEmpty() { return (numInList == 0); }; // is the list empty? void Apply(void (*f)(T)) const; // apply function to all elements in list virtual void SanityCheck() const; // has this list been corrupted? void SelfTest(T *p, int numEntries); // verify module is working protected: ListElement<T> *first; // Head of the list, NULL if list is empty ListElement<T> *last; // Last element of list int numInList; // number of elements in list friend class ListIterator<T>; }; // The following class defines a "sorted list" -- a singly linked list of // list elements, arranged so that "Remove" always returns the smallest // element. // All types to be inserted onto a sorted list must have a "Compare" // function defined: // int Compare(T x, T y) // returns -1 if x < y // returns 0 if x == y // returns 1 if x > y template <class T> class SortedList : public List<T> { public: SortedList(int (*comp)(T x, T y)) : List<T>() { compare = comp;}; ~SortedList() {}; // base class destructor called automatically void Insert(T item); // insert an item onto the list in sorted order void SanityCheck() const; // has this list been corrupted? void SelfTest(T *p, int numEntries); // verify module is working private: int (*compare)(T x, T y); // function for sorting list elements void Prepend(T item) { Insert(item); } // *pre*pending has no meaning // in a sorted list void Append(T item) { Insert(item); } // neither does *ap*pend }; // The following class can be used to step through a list. // Example code: // ListIterator<T> *iter(list); // // for (; !iter->IsDone(); iter->Next()) { // Operation on iter->Item() // } template <class T> class ListIterator { public: ListIterator(List<T> *list) { current = list->first; } // initialize an iterator bool IsDone() { return current == NULL; }; // return TRUE if we are at the end of the list T Item() { ASSERT(!IsDone()); return current->item; }; // return current element on list void Next() { current = current->next; }; // update iterator to point to next private: ListElement<T> *current; // where we are in the list }; #include "list.cc" // templates are really like macros // so needs to be included in every // file that uses the template #endif // LIST_H

project4/nachos/code/lib/utility.h

// utility.h // Miscellaneous useful definitions. // // Copyright (c) 1992-1996 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef UTILITY_H #define UTILITY_H #include "copyright.h" // Miscellaneous useful routines #define NULL 0 #define TRUE true #define FALSE false // #define bool int // necessary on the Mac? #define min(a,b) (((a) < (b)) ? (a) : (b)) #define max(a,b) (((a) > (b)) ? (a) : (b)) // Divide and either round up or down #define divRoundDown(n,s) ((n) / (s)) #define divRoundUp(n,s) (((n) / (s)) + ((((n) % (s)) > 0) ? 1 : 0)) // This declares the type "VoidFunctionPtr" to be a "pointer to a // function taking an arbitrary pointer argument and returning nothing". With // such a function pointer (say it is "func"), we can call it like this: // // (*func) ("help!"); // // This is used by Thread::Fork as well as a couple of other places. typedef void (*VoidFunctionPtr)(void *arg); typedef void (*VoidNoArgFunctionPtr)(); #endif // UTILITY_H

project4/nachos/code/lib/bitmap.h

// bitmap.h // Data structures defining a bitmap -- an array of bits each of which // can be either on or off. // // Represented as an array of unsigned integers, on which we do // modulo arithmetic to find the bit we are interested in. // // The bitmap can be parameterized with with the number of bits being // managed. // // Copyright (c) 1992-1996 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef BITMAP_H #define BITMAP_H #include "copyright.h" #include "utility.h" // Definitions helpful for representing a bitmap as an array of integers const int BitsInByte = 8; const int BitsInWord = sizeof(unsigned int) * BitsInByte; // The following class defines a "bitmap" -- an array of bits, // each of which can be independently set, cleared, and tested. // // Most useful for managing the allocation of the elements of an array -- // for instance, disk sectors, or main memory pages. // Each bit represents whether the corresponding sector or page is // in use or free. class Bitmap { public: Bitmap(int numItems); // Initialize a bitmap, with "numItems" bits // initially, all bits are cleared. ~Bitmap(); // De-allocate bitmap void Mark(int which); // Set the "nth" bit void Clear(int which); // Clear the "nth" bit bool Test(int which) const; // Is the "nth" bit set? int FindAndSet(); // Return the # of a clear bit, and as a side // effect, set the bit. // If no bits are clear, return -1. int NumClear() const; // Return the number of clear bits void Print() const; // Print contents of bitmap void SelfTest(); // Test whether bitmap is working protected: int numBits; // number of bits in the bitmap int numWords; // number of words of bitmap storage // (rounded up if numBits is not a // multiple of the number of bits in // a word) unsigned int *map; // bit storage }; #endif // BITMAP_H

project4/nachos/code/lib/hash.h

// hash.h // Data structures to manage a hash table to relate arbitrary // keys to arbitrary values. A hash table allows efficient lookup // for the value given the key. // // I've only tested this implementation when both the key and the // value are primitive types (ints or pointers). There is no // guarantee that it will work in general. In particular, it // assumes that the "==" operator works for both keys and values. // // In addition, the key must have Hash() defined: // unsigned Hash(Key k); // returns a randomized # based on value of key // // The value must have a function defined to retrieve the key: // Key GetKey(T x); // // The hash table automatically resizes itself as items are // put into the table. The implementation uses chaining // to resolve hash conflicts. // // Allocation and deallocation of the items in the table are to // be done by the caller. // // Copyright (c) 1992-1996 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef HASH_H #define HASH_H #include "copyright.h" #include "list.h" // The following class defines a "hash table" -- allowing quick // lookup according to the hash function defined for the items // being put into the table. template <class Key,class T> class HashIterator; template <class Key, class T> class HashTable { public: HashTable(Key (*get)(T x), unsigned (*hFunc)(Key x)); // initialize a hash table ~HashTable(); // deallocate a hash table void Insert(T item); // Put item into hash table T Remove(Key key); // Remove item from hash table. bool Find(Key key, T *itemPtr) const; // Find an item from its key bool IsInTable(Key key) { T dummy; return Find(key, &dummy); } // Is the item in the table? bool IsEmpty() { return numItems == 0; } // does the table have anything in it void Apply(void (*f)(T)) const; // apply function to all elements in table void SanityCheck() const;// is this still a legal hash table? void SelfTest(T *p, int numItems); // is the module working? private: typedef List<T> *Bucket; Bucket *buckets; // the array of hash buckets int numBuckets; // the number of buckets int numItems; // the number of items in the table Key (*getKey)(T x); // get Key from value unsigned (*hash)(Key x); // the hash function void InitBuckets(int size);// initialize bucket array void DeleteBuckets(Bucket *table, int size); // deallocate bucket array int HashValue(Key key) const; // which bucket does the key hash to? void ReHash(); // expand the hash table bool FindInBucket(int bucket, Key key, T *itemPtr) const; // find item in bucket int FindNextFullBucket(int start) const; // find next full bucket starting from this one friend class HashIterator<Key,T>; }; // The following class can be used to step through a hash table -- // same interface as ListIterator. Example code: // HashIterator<Key, T> iter(table); // // for (; !iter->IsDone(); iter->Next()) { // Operation on iter->Item() // } template <class Key,class T> class HashIterator { public: HashIterator(HashTable<Key,T> *table); // initialize an iterator ~HashIterator() { if (bucketIter != NULL) delete bucketIter;}; // destruct an iterator bool IsDone() { return (bucket == table->numBuckets); }; // return TRUE if no more items in table T Item() { ASSERT(!IsDone()); return bucketIter->Item(); }; // return current item in table void Next(); // update iterator to point to next private: HashTable<Key,T> *table; // the hash table we're stepping through int bucket; // current bucket we are in ListIterator<T> *bucketIter; // where we are in the bucket }; #include "hash.cc" // templates are really like macros // so needs to be included in every // file that uses the template #endif // HASH_H

project4/nachos/code/lib/list.cc

project4/nachos/code/lib/list.cc

// list.cc 
//      Routines to manage a singly linked list of "things".
//  Lists are implemented as templates so that we can store
//  anything on the list in a type-safe manner.
//
//  A "ListElement" is allocated for each item to be put on the
//  list; it is de-allocated when the item is removed. This means
//      we don't need to keep a "next" pointer in every object we
//      want to put on a list.
// 
//      NOTE: Mutual exclusion must be provided by the caller.
//      If you want a synchronized list, you must use the routines 
//  in synchlist.cc.
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include   "copyright.h"

//----------------------------------------------------------------------
// ListElement<T>::ListElement
//  Initialize a list element, so it can be added somewhere on a list.
//
//  "itm" is the thing to be put on the list.
//----------------------------------------------------------------------

template   < class  T >
ListElement < T >:: ListElement ( T itm )
{
     item  =  itm ;
     next  =  NULL ;     // always initialize to something!
}


//----------------------------------------------------------------------
// List<T>::List
//  Initialize a list, empty to start with.
//  Elements can now be added to the list.
//----------------------------------------------------------------------

template   < class  T >
List < T >:: List ()
{  
    first  =  last  =  NULL ;  
    numInList  =   0 ;
}

//----------------------------------------------------------------------
// List<T>::~List
//  Prepare a list for deallocation.  
//      This does *NOT* free list elements, nor does it
//      free the data those elements point to.
//      Normally, the list should be empty when this is called.
//----------------------------------------------------------------------

template   < class  T >
List < T >::~ List ()
{  
}

//----------------------------------------------------------------------
// List<T>::Append
//      Append an "item" to the end of the list.
//      
//  Allocate a ListElement to keep track of the item.
//      If the list is empty, then this will be the only element.
//  Otherwise, put it at the end.
//
//  "item" is the thing to put on the list.
//----------------------------------------------------------------------

template   < class  T >
void
List < T >:: Append ( T item )
{
     ListElement < T >   * element  =   new   ListElement < T > ( item );

    ASSERT ( ! this -> IsInList ( item ));
     if   ( IsEmpty ())   {          // list is empty
    first  =  element ;
    last  =  element ;
     }   else   {              // else put it after last
    last -> next  =  element ;
    last  =  element ;
     }
    numInList ++ ;
    ASSERT ( this -> IsInList ( item ));
}

//----------------------------------------------------------------------
// List<T>::Prepend
//  Same as Append, only put "item" on the front.
//----------------------------------------------------------------------

template   < class  T >
void
List < T >:: Prepend ( T item )
{
     ListElement < T >   * element  =   new   ListElement < T > ( item );

    ASSERT ( ! this -> IsInList ( item ));
     if   ( IsEmpty ())   {          // list is empty
    first  =  element ;
    last  =  element ;
     }   else   {              // else put it before first
    element -> next  =  first ;
    first  =  element ;
     }
    numInList ++ ;
    ASSERT ( this -> IsInList ( item ));
}

//----------------------------------------------------------------------
// List<T>::RemoveFront
//      Remove the first "item" from the front of the list.
//  List must not be empty.
// 
// Returns:
//  The removed item.
//----------------------------------------------------------------------

template   < class  T >
T
List < T >:: RemoveFront ()
{
     ListElement < T >   * element  =  first ;
    T thing ;

    ASSERT ( ! IsEmpty ());

    thing  =  first -> item ;
     if   ( first  ==  last )   {      // list had one item, now has none 
        first  =  NULL ;
    last  =  NULL ;
     }   else   {
        first  =  element -> next ;
     }
    numInList -- ;
     delete  element ;
     return  thing ;
}

//----------------------------------------------------------------------
// List<T>::Remove
//      Remove a specific item from the list.  Must be in the list!
//----------------------------------------------------------------------

template   < class  T >
void
List < T >:: Remove ( T item )
{
     ListElement < T >   * prev ,   * ptr ;
    T removed ;

    ASSERT ( this -> IsInList ( item ));

     // if first item on list is match, then remove from front
     if   ( item  ==  first -> item )   {   
        removed  =   RemoveFront ();
        ASSERT ( item  ==  removed );
     }   else   {
    prev  =  first ;
         for   ( ptr  =  first -> next ;  ptr  !=  NULL ;  prev  =  ptr ,  ptr  =  ptr -> next )   {
             if   ( item  ==  ptr -> item )   {
        prev -> next  =  ptr -> next ;
         if   ( prev -> next  ==  NULL )   {
            last  =  prev ;
         }
         delete  ptr ;
        numInList -- ;
         break ;
         }
         }
    ASSERT ( ptr  !=  NULL );      // should always find item!
     }
   ASSERT ( ! this -> IsInList ( item ));
}

//----------------------------------------------------------------------
// List<T>::IsInList
//      Return TRUE if the item is in the list.
//----------------------------------------------------------------------

template   < class  T >
bool
List < T >:: IsInList ( T item )   const
{  
     ListElement < T >   * ptr ;

     for   ( ptr  =  first ;  ptr  !=  NULL ;  ptr  =  ptr -> next )   {
         if   ( item  ==  ptr -> item )   {
             return  TRUE ;
         }
     }
     return  FALSE ;
}


//----------------------------------------------------------------------
// List<T>::Apply
//      Apply function to every item on a list.
//
//  "func" -- the function to apply
//----------------------------------------------------------------------

template   < class  T >
void
List < T >:: Apply ( void   ( * func )( T ))   const
{  
     ListElement < T >   * ptr ;

     for   ( ptr  =  first ;  ptr  !=  NULL ;  ptr  =  ptr -> next )   {
         ( * func )( ptr -> item );
     }
}


//----------------------------------------------------------------------
// SortedList::Insert
//      Insert an "item" into a list, so that the list elements are
//  sorted in increasing order.
//      
//  Allocate a ListElement to keep track of the item.
//      If the list is empty, then this will be the only element.
//  Otherwise, walk through the list, one element at a time,
//  to find where the new item should be placed.
//
//  "item" is the thing to put on the list. 
//----------------------------------------------------------------------

template   < class  T >
void
SortedList < T >:: Insert ( T item )
{
     ListElement < T >   * element  =   new   ListElement < T > ( item );
     ListElement < T >   * ptr ;          // keep track

    ASSERT ( ! this -> IsInList ( item ));
     if   ( this -> IsEmpty ())   {            // if list is empty, put at front
         this -> first  =  element ;
         this -> last  =  element ;
     }   else   if   ( compare ( item ,   this -> first -> item )   <   0 )   {    // item goes at front 
    element -> next  =   this -> first ;
     this -> first  =  element ;
     }   else   {          // look for first elt in list bigger than item
         for   ( ptr  =   this -> first ;  ptr -> next  !=  NULL ;  ptr  =  ptr -> next )   {
             if   ( compare ( item ,  ptr -> next -> item )   <   0 )   {
        element -> next  =  ptr -> next ;
            ptr -> next  =  element ;
         this -> numInList ++ ;
         return ;
         }
     }
     this -> last -> next  =  element ;       // item goes at end of list
     this -> last  =  element ;
     }
     this -> numInList ++ ;
    ASSERT ( this -> IsInList ( item ));
}

//----------------------------------------------------------------------
// List::SanityCheck
//      Test whether this is still a legal list.
//
//  Tests: do I get to last starting from first?
//         does the list have the right # of elements?
//----------------------------------------------------------------------

template   < class  T >
void  
List < T >:: SanityCheck ()   const
{
     ListElement < T >   * ptr ;
     int  numFound ;

     if   ( first  ==  NULL )   {
    ASSERT (( numInList  ==   0 )   &&   ( last  ==  NULL ));
     }   else   if   ( first  ==  last )   {
    ASSERT (( numInList  ==   1 )   &&   ( last -> next  ==  NULL ));
     }   else   {
         for   ( numFound  =   1 ,  ptr  =  first ;  ptr  !=  last ;  ptr  =  ptr -> next )   {
        numFound ++ ;
            ASSERT ( numFound  <=  numInList );    // prevent infinite loop
         }
        ASSERT ( numFound  ==  numInList );
        ASSERT ( last -> next  ==  NULL );
     }
}

//----------------------------------------------------------------------
// List::SelfTest
//      Test whether this module is working.
//----------------------------------------------------------------------

template   < class  T >
void  
List < T >:: SelfTest ( * p ,   int  numEntries )
{
     int  i ;
     ListIterator < T >   * iterator  =   new   ListIterator < T > ( this );

     SanityCheck ();
     // check various ways that list is empty
    ASSERT ( IsEmpty ()   &&   ( first  ==  NULL ));
     for   (;   ! iterator -> IsDone ();  iterator -> Next ())   {
    ASSERTNOTREACHED ();   // nothing on list
     }

     for   ( =   0 ;  i  <  numEntries ;  i ++ )   {
      Append ( p [ i ]);
     ASSERT ( this -> IsInList ( p [ i ]));
     ASSERT ( ! IsEmpty ());
      }
      SanityCheck ();

      // should be able to get out everything we put in
      for   ( =   0 ;  i  <  numEntries ;  i ++ )   {
      Remove ( p [ i ]);
         ASSERT ( ! this -> IsInList ( p [ i ]));
      }
     ASSERT ( IsEmpty ());
      SanityCheck ();
      delete  iterator ;
}

//----------------------------------------------------------------------
// SortedList::SanityCheck
//      Test whether this is still a legal sorted list.
//
//  Test: is the list sorted?
//----------------------------------------------------------------------

template   < class  T >
void  
SortedList < T >:: SanityCheck ()   const
{
     ListElement < T >   * prev ,   * ptr ;

     List < T >:: SanityCheck ();
     if   ( this -> first  !=   this -> last )   {
         for   ( prev  =   this -> first ,  ptr  =   this -> first -> next ;  ptr  !=  NULL ;  
                        prev  =  ptr ,  ptr  =  ptr -> next )   {
            ASSERT ( compare ( prev -> item ,  ptr -> item )   <=   0 );
         }
     }
}

//----------------------------------------------------------------------
// SortedList::SelfTest
//      Test whether this module is working.
//----------------------------------------------------------------------

template   < class  T >
void  
SortedList < T >:: SelfTest ( * p ,   int  numEntries )
{
     int  i ;
    T  * =   new  T [ numEntries ];

     List < T >:: SelfTest ( p ,  numEntries );

     for   ( =   0 ;  i  <  numEntries ;  i ++ )   {
      Insert ( p [ i ]);
     ASSERT ( this -> IsInList ( p [ i ]));
      }
      SanityCheck ();

      // should be able to get out everything we put in
      for   ( =   0 ;  i  <  numEntries ;  i ++ )   {
     q [ i ]   =   this -> RemoveFront ();
         ASSERT ( ! this -> IsInList ( q [ i ]));
      }
     ASSERT ( this -> IsEmpty ());

      // make sure everything came out in the right order
      for   ( =   0 ;  i  <   ( numEntries  -   1 );  i ++ )   {
     ASSERT ( compare ( q [ i ],  q [ +   1 ])   <=   0 );
      }
      SanityCheck ();

      delete  q ;
}

project4/nachos/code/lib/libtest.cc

project4/nachos/code/lib/libtest.cc

// libtest.cc 
//  Driver code to call self-test routines for standard library
//  classes -- bitmaps, lists, sorted lists, and hash tables.
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include   "copyright.h"
#include   "libtest.h"
#include   "bitmap.h"
#include   "list.h"
#include   "hash.h"
#include   "sysdep.h"

//----------------------------------------------------------------------
// IntCompare
//  Compare two integers together.  Serves as the comparison
//  function for testing SortedLists
//----------------------------------------------------------------------

static   int  
IntCompare ( int  x ,   int  y )   {
     if   ( <  y )   return   - 1 ;
     else   if   ( ==  y )   return   0 ;
     else   return   1 ;
}

//----------------------------------------------------------------------
// HashInt, HashKey
//  Compute a hash function on an integer.  Serves as the
//  hashing function for testing HashTables.
//----------------------------------------------------------------------

static   unsigned   int  
HashInt ( int  key )   {
     return   ( unsigned   int )  key ;
}

//----------------------------------------------------------------------
// HashKey
//  Convert a string into an integer.  Serves as the function
//  to retrieve the key from the item in the hash table, for
//  testing HashTables.  Should be able to use "atoi" directly,
//  but some compilers complain about that.
//----------------------------------------------------------------------

static   int  
HashKey ( char   * str )   {
     return  atoi ( str );
}

// Array of values to be inserted into a List or SortedList. 
static   int  listTestVector []   =   {   9 ,   5 ,   7   };

// Array of values to be inserted into the HashTable
// There are enough here to force a ReHash().
static   char   * hashTestVector []   =   {   "0" ,   "1" ,   "2" ,   "3" ,   "4" ,   "5" ,   "6" ,
      "7" ,   "8" ,   "9" ,   "10" ,   "11" ,   "12" ,   "13" ,   "14" };

//----------------------------------------------------------------------
// LibSelfTest
//  Run self tests on bitmaps, lists, sorted lists, and 
//  hash tables.
//----------------------------------------------------------------------

void
LibSelfTest   ()   {
     Bitmap   * map  =   new   Bitmap ( 200 );
     List < int >   * list  =   new   List < int > ;
     SortedList < int >   * sortList  =   new   SortedList < int > ( IntCompare );
     HashTable < int ,   char   *>   * hashTable  =  
     new   HashTable < int ,   char   *> ( HashKey ,   HashInt );
    
        
    map -> SelfTest ();
    list -> SelfTest ( listTestVector ,   sizeof ( listTestVector ) / sizeof ( int ));
    sortList -> SelfTest ( listTestVector ,   sizeof ( listTestVector ) / sizeof ( int ));
    hashTable -> SelfTest ( hashTestVector ,   sizeof ( hashTestVector ) / sizeof ( char   * ));

     delete  map ;
     delete  list ;
     delete  sortList ;
     delete  hashTable ;
}

project4/nachos/code/build.linux/filehdr.o

project4/nachos/code/build.linux/main.o

project4/nachos/code/build.linux/Makefile.dep

################################################################## # Machine Dependencies - this file is included automatically # into the main Makefile # # This file contains definitions below for x86 running Linux # It has *not* been tested! ################################################################## HOSTCFLAGS = -Dx86 -DLINUX #----------------------------------------------------------------- # Do not put anything below this point - it will be destroyed by # "make depend" # # DO NOT DELETE THIS LINE -- make depend uses it bitmap.o: ../lib/bitmap.cc /usr/include/stdc-predef.h ../lib/copyright.h \ ../lib/debug.h ../lib/utility.h ../lib/sysdep.h \ /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h \ ../lib/bitmap.h debug.o: ../lib/debug.cc /usr/include/stdc-predef.h ../lib/copyright.h \ ../lib/utility.h ../lib/debug.h ../lib/sysdep.h \ /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h hash.o: ../lib/hash.cc /usr/include/stdc-predef.h ../lib/copyright.h libtest.o: ../lib/libtest.cc /usr/include/stdc-predef.h \ ../lib/copyright.h ../lib/libtest.h ../lib/bitmap.h ../lib/utility.h \ ../lib/list.h ../lib/debug.h ../lib/sysdep.h /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h \ ../lib/list.cc ../lib/hash.h ../lib/hash.cc list.o: ../lib/list.cc /usr/include/stdc-predef.h ../lib/copyright.h sysdep.o: ../lib/sysdep.cc /usr/include/stdc-predef.h ../lib/copyright.h \ ../lib/debug.h ../lib/utility.h ../lib/sysdep.h \ /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h \ /usr/include/unistd.h /usr/include/x86_64-linux-gnu/bits/posix_opt.h \ /usr/include/x86_64-linux-gnu/bits/environments.h \ /usr/include/x86_64-linux-gnu/bits/confname.h /usr/include/getopt.h \ /usr/include/x86_64-linux-gnu/sys/time.h \ /usr/include/x86_64-linux-gnu/sys/file.h /usr/include/fcntl.h \ /usr/include/x86_64-linux-gnu/bits/fcntl.h \ /usr/include/x86_64-linux-gnu/bits/fcntl-linux.h \ /usr/include/x86_64-linux-gnu/bits/uio.h \ /usr/include/x86_64-linux-gnu/bits/stat.h \ /usr/include/x86_64-linux-gnu/sys/socket.h \ /usr/include/x86_64-linux-gnu/sys/uio.h \ /usr/include/x86_64-linux-gnu/bits/socket.h \ /usr/include/x86_64-linux-gnu/bits/socket_type.h \ /usr/include/x86_64-linux-gnu/bits/sockaddr.h \ /usr/include/x86_64-linux-gnu/asm/socket.h \ /usr/include/asm-generic/socket.h \ /usr/include/x86_64-linux-gnu/asm/sockios.h \ /usr/include/asm-generic/sockios.h \ /usr/include/x86_64-linux-gnu/sys/un.h /usr/include/c++/5/cerrno \ /usr/include/errno.h /usr/include/x86_64-linux-gnu/bits/errno.h \ /usr/include/linux/errno.h /usr/include/x86_64-linux-gnu/asm/errno.h \ /usr/include/asm-generic/errno.h /usr/include/asm-generic/errno-base.h \ /usr/include/signal.h /usr/include/x86_64-linux-gnu/bits/signum.h \ /usr/include/x86_64-linux-gnu/bits/siginfo.h \ /usr/include/x86_64-linux-gnu/bits/sigaction.h \ /usr/include/x86_64-linux-gnu/bits/sigcontext.h \ /usr/include/x86_64-linux-gnu/bits/sigstack.h \ /usr/include/x86_64-linux-gnu/sys/ucontext.h \ /usr/include/x86_64-linux-gnu/bits/sigthread.h interrupt.o: ../machine/interrupt.cc /usr/include/stdc-predef.h \ ../lib/copyright.h ../machine/interrupt.h ../lib/list.h ../lib/debug.h \ ../lib/utility.h ../lib/sysdep.h /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h \ ../lib/list.cc ../machine/callback.h ../threads/main.h \ ../threads/kernel.h ../threads/thread.h ../machine/machine.h \ ../machine/translate.h ../userprog/addrspace.h ../filesys/filesys.h \ ../filesys/openfile.h ../threads/scheduler.h ../machine/stats.h \ ../threads/alarm.h ../machine/timer.h stats.o: ../machine/stats.cc /usr/include/stdc-predef.h \ ../lib/copyright.h ../lib/debug.h ../lib/utility.h ../lib/sysdep.h \ /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h \ ../machine/stats.h timer.o: ../machine/timer.cc /usr/include/stdc-predef.h \ ../lib/copyright.h ../machine/timer.h ../lib/utility.h \ ../machine/callback.h ../threads/main.h ../lib/debug.h ../lib/sysdep.h \ /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h \ ../threads/kernel.h ../threads/thread.h ../machine/machine.h \ ../machine/translate.h ../userprog/addrspace.h ../filesys/filesys.h \ ../filesys/openfile.h ../threads/scheduler.h ../lib/list.h \ ../lib/list.cc ../machine/interrupt.h ../machine/stats.h \ ../threads/alarm.h console.o: ../machine/console.cc /usr/include/stdc-predef.h \ ../lib/copyright.h ../machine/console.h ../lib/utility.h \ ../machine/callback.h ../threads/main.h ../lib/debug.h ../lib/sysdep.h \ /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h \ ../threads/kernel.h ../threads/thread.h ../machine/machine.h \ ../machine/translate.h ../userprog/addrspace.h ../filesys/filesys.h \ ../filesys/openfile.h ../threads/scheduler.h ../lib/list.h \ ../lib/list.cc ../machine/interrupt.h ../machine/stats.h \ ../threads/alarm.h ../machine/timer.h machine.o: ../machine/machine.cc /usr/include/stdc-predef.h \ ../lib/copyright.h ../machine/machine.h ../lib/utility.h \ ../machine/translate.h ../threads/main.h ../lib/debug.h ../lib/sysdep.h \ /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h \ ../threads/kernel.h ../threads/thread.h ../userprog/addrspace.h \ ../filesys/filesys.h ../filesys/openfile.h ../threads/scheduler.h \ ../lib/list.h ../lib/list.cc ../machine/interrupt.h \ ../machine/callback.h ../machine/stats.h ../threads/alarm.h \ ../machine/timer.h mipssim.o: ../machine/mipssim.cc /usr/include/stdc-predef.h \ ../lib/copyright.h ../lib/debug.h ../lib/utility.h ../lib/sysdep.h \ /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h \ ../machine/machine.h ../machine/translate.h ../machine/mipssim.h \ ../threads/main.h ../threads/kernel.h ../threads/thread.h \ ../userprog/addrspace.h ../filesys/filesys.h ../filesys/openfile.h \ ../threads/scheduler.h ../lib/list.h ../lib/list.cc \ ../machine/interrupt.h ../machine/callback.h ../machine/stats.h \ ../threads/alarm.h ../machine/timer.h translate.o: ../machine/translate.cc /usr/include/stdc-predef.h \ ../lib/copyright.h ../threads/main.h ../lib/debug.h ../lib/utility.h \ ../lib/sysdep.h /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h \ ../threads/kernel.h ../threads/thread.h ../machine/machine.h \ ../machine/translate.h ../userprog/addrspace.h ../filesys/filesys.h \ ../filesys/openfile.h ../threads/scheduler.h ../lib/list.h \ ../lib/list.cc ../machine/interrupt.h ../machine/callback.h \ ../machine/stats.h ../threads/alarm.h ../machine/timer.h network.o: ../machine/network.cc /usr/include/stdc-predef.h \ ../lib/copyright.h ../machine/network.h ../lib/utility.h \ ../machine/callback.h ../threads/main.h ../lib/debug.h ../lib/sysdep.h \ /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h \ ../threads/kernel.h ../threads/thread.h ../machine/machine.h \ ../machine/translate.h ../userprog/addrspace.h ../filesys/filesys.h \ ../filesys/openfile.h ../threads/scheduler.h ../lib/list.h \ ../lib/list.cc ../machine/interrupt.h ../machine/stats.h \ ../threads/alarm.h ../machine/timer.h disk.o: ../machine/disk.cc /usr/include/stdc-predef.h ../lib/copyright.h \ ../machine/disk.h ../lib/utility.h ../machine/callback.h ../lib/debug.h \ ../lib/sysdep.h /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h \ ../threads/main.h ../threads/kernel.h ../threads/thread.h \ ../machine/machine.h ../machine/translate.h ../userprog/addrspace.h \ ../filesys/filesys.h ../filesys/openfile.h ../threads/scheduler.h \ ../lib/list.h ../lib/list.cc ../machine/interrupt.h ../machine/stats.h \ ../threads/alarm.h ../machine/timer.h alarm.o: ../threads/alarm.cc /usr/include/stdc-predef.h \ ../lib/copyright.h ../threads/alarm.h ../lib/utility.h \ ../machine/callback.h ../machine/timer.h ../threads/main.h \ ../lib/debug.h ../lib/sysdep.h /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h \ ../threads/kernel.h ../threads/thread.h ../machine/machine.h \ ../machine/translate.h ../userprog/addrspace.h ../filesys/filesys.h \ ../filesys/openfile.h ../threads/scheduler.h ../lib/list.h \ ../lib/list.cc ../machine/interrupt.h ../machine/stats.h kernel.o: ../threads/kernel.cc /usr/include/stdc-predef.h \ ../lib/copyright.h ../lib/debug.h ../lib/utility.h ../lib/sysdep.h \ /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h \ ../threads/main.h ../threads/kernel.h ../threads/thread.h \ ../machine/machine.h ../machine/translate.h ../userprog/addrspace.h \ ../filesys/filesys.h ../filesys/openfile.h ../threads/scheduler.h \ ../lib/list.h ../lib/list.cc ../machine/interrupt.h \ ../machine/callback.h ../machine/stats.h ../threads/alarm.h \ ../machine/timer.h ../threads/synch.h ../threads/synchlist.h \ ../threads/synchlist.cc ../lib/libtest.h ../userprog/synchconsole.h \ ../machine/console.h ../filesys/synchdisk.h ../machine/disk.h \ ../network/post.h ../machine/network.h main.o: ../threads/main.cc /usr/include/stdc-predef.h ../lib/copyright.h \ ../threads/main.h ../lib/debug.h ../lib/utility.h ../lib/sysdep.h \ /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h \ ../threads/kernel.h ../threads/thread.h ../machine/machine.h \ ../machine/translate.h ../userprog/addrspace.h ../filesys/filesys.h \ ../filesys/openfile.h ../threads/scheduler.h ../lib/list.h \ ../lib/list.cc ../machine/interrupt.h ../machine/callback.h \ ../machine/stats.h ../threads/alarm.h ../machine/timer.h scheduler.o: ../threads/scheduler.cc /usr/include/stdc-predef.h \ ../lib/copyright.h ../lib/debug.h ../lib/utility.h ../lib/sysdep.h \ /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h \ ../threads/scheduler.h ../lib/list.h ../lib/list.cc ../threads/thread.h \ ../machine/machine.h ../machine/translate.h ../userprog/addrspace.h \ ../filesys/filesys.h ../filesys/openfile.h ../threads/main.h \ ../threads/kernel.h ../machine/interrupt.h ../machine/callback.h \ ../machine/stats.h ../threads/alarm.h ../machine/timer.h synch.o: ../threads/synch.cc /usr/include/stdc-predef.h \ ../lib/copyright.h ../threads/synch.h ../threads/thread.h \ ../lib/utility.h ../lib/sysdep.h /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h \ ../machine/machine.h ../machine/translate.h ../userprog/addrspace.h \ ../filesys/filesys.h ../filesys/openfile.h ../lib/list.h ../lib/debug.h \ ../lib/list.cc ../threads/main.h ../threads/kernel.h \ ../threads/scheduler.h ../machine/interrupt.h ../machine/callback.h \ ../machine/stats.h ../threads/alarm.h ../machine/timer.h synchlist.o: ../threads/synchlist.cc /usr/include/stdc-predef.h \ ../lib/copyright.h ../threads/synchlist.h ../lib/list.h ../lib/debug.h \ ../lib/utility.h ../lib/sysdep.h /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h \ ../lib/list.cc ../threads/synch.h ../threads/thread.h \ ../machine/machine.h ../machine/translate.h ../userprog/addrspace.h \ ../filesys/filesys.h ../filesys/openfile.h ../threads/main.h \ ../threads/kernel.h ../threads/scheduler.h ../machine/interrupt.h \ ../machine/callback.h ../machine/stats.h ../threads/alarm.h \ ../machine/timer.h ../threads/synchlist.cc thread.o: ../threads/thread.cc /usr/include/stdc-predef.h \ ../lib/copyright.h ../threads/thread.h ../lib/utility.h ../lib/sysdep.h \ /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h \ ../machine/machine.h ../machine/translate.h ../userprog/addrspace.h \ ../filesys/filesys.h ../filesys/openfile.h ../threads/switch.h \ ../threads/synch.h ../lib/list.h ../lib/debug.h ../lib/list.cc \ ../threads/main.h ../threads/kernel.h ../threads/scheduler.h \ ../machine/interrupt.h ../machine/callback.h ../machine/stats.h \ ../threads/alarm.h ../machine/timer.h threadtest.o: ../threads/threadtest.cc /usr/include/stdc-predef.h \ ../threads/kernel.h ../lib/copyright.h ../lib/debug.h ../lib/utility.h \ ../lib/sysdep.h /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h \ ../threads/thread.h ../machine/machine.h ../machine/translate.h \ ../userprog/addrspace.h ../filesys/filesys.h ../filesys/openfile.h \ ../threads/scheduler.h ../lib/list.h ../lib/list.cc \ ../machine/interrupt.h ../machine/callback.h ../machine/stats.h \ ../threads/alarm.h ../machine/timer.h addrspace.o: ../userprog/addrspace.cc /usr/include/stdc-predef.h \ ../lib/copyright.h ../threads/main.h ../lib/debug.h ../lib/utility.h \ ../lib/sysdep.h /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h \ ../threads/kernel.h ../threads/thread.h ../machine/machine.h \ ../machine/translate.h ../userprog/addrspace.h ../filesys/filesys.h \ ../filesys/openfile.h ../threads/scheduler.h ../lib/list.h \ ../lib/list.cc ../machine/interrupt.h ../machine/callback.h \ ../machine/stats.h ../threads/alarm.h ../machine/timer.h \ ../userprog/noff.h exception.o: ../userprog/exception.cc /usr/include/stdc-predef.h \ ../lib/copyright.h ../threads/main.h ../lib/debug.h ../lib/utility.h \ ../lib/sysdep.h /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h \ ../threads/kernel.h ../threads/thread.h ../machine/machine.h \ ../machine/translate.h ../userprog/addrspace.h ../filesys/filesys.h \ ../filesys/openfile.h ../threads/scheduler.h ../lib/list.h \ ../lib/list.cc ../machine/interrupt.h ../machine/callback.h \ ../machine/stats.h ../threads/alarm.h ../machine/timer.h \ ../userprog/syscall.h ../userprog/errno.h ../userprog/ksyscall.h synchconsole.o: ../userprog/synchconsole.cc /usr/include/stdc-predef.h \ ../lib/copyright.h ../userprog/synchconsole.h ../lib/utility.h \ ../machine/callback.h ../machine/console.h ../threads/synch.h \ ../threads/thread.h ../lib/sysdep.h /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h \ ../machine/machine.h ../machine/translate.h ../userprog/addrspace.h \ ../filesys/filesys.h ../filesys/openfile.h ../lib/list.h ../lib/debug.h \ ../lib/list.cc ../threads/main.h ../threads/kernel.h \ ../threads/scheduler.h ../machine/interrupt.h ../machine/stats.h \ ../threads/alarm.h ../machine/timer.h directory.o: ../filesys/directory.cc /usr/include/stdc-predef.h \ ../lib/copyright.h ../lib/utility.h ../filesys/filehdr.h \ ../machine/disk.h ../machine/callback.h ../filesys/pbitmap.h \ ../lib/bitmap.h ../filesys/openfile.h ../lib/sysdep.h \ /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h \ ../filesys/directory.h filehdr.o: ../filesys/filehdr.cc /usr/include/stdc-predef.h \ ../lib/copyright.h ../filesys/filehdr.h ../machine/disk.h \ ../lib/utility.h ../machine/callback.h ../filesys/pbitmap.h \ ../lib/bitmap.h ../filesys/openfile.h ../lib/sysdep.h \ /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h \ ../lib/debug.h ../filesys/synchdisk.h ../threads/synch.h \ ../threads/thread.h ../machine/machine.h ../machine/translate.h \ ../userprog/addrspace.h ../filesys/filesys.h ../lib/list.h \ ../lib/list.cc ../threads/main.h ../threads/kernel.h \ ../threads/scheduler.h ../machine/interrupt.h ../machine/stats.h \ ../threads/alarm.h ../machine/timer.h filesys.o: ../filesys/filesys.cc /usr/include/stdc-predef.h pbitmap.o: ../filesys/pbitmap.cc /usr/include/stdc-predef.h \ ../lib/copyright.h ../filesys/pbitmap.h ../lib/bitmap.h ../lib/utility.h \ ../filesys/openfile.h ../lib/sysdep.h /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h openfile.o: ../filesys/openfile.cc /usr/include/stdc-predef.h synchdisk.o: ../filesys/synchdisk.cc /usr/include/stdc-predef.h \ ../lib/copyright.h ../filesys/synchdisk.h ../machine/disk.h \ ../lib/utility.h ../machine/callback.h ../threads/synch.h \ ../threads/thread.h ../lib/sysdep.h /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h \ ../machine/machine.h ../machine/translate.h ../userprog/addrspace.h \ ../filesys/filesys.h ../filesys/openfile.h ../lib/list.h ../lib/debug.h \ ../lib/list.cc ../threads/main.h ../threads/kernel.h \ ../threads/scheduler.h ../machine/interrupt.h ../machine/stats.h \ ../threads/alarm.h ../machine/timer.h post.o: ../network/post.cc /usr/include/stdc-predef.h ../lib/copyright.h \ ../network/post.h ../lib/utility.h ../machine/callback.h \ ../machine/network.h ../threads/synchlist.h ../lib/list.h ../lib/debug.h \ ../lib/sysdep.h /usr/include/c++/5/iostream \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/bits/wordsize.h \ /usr/include/x86_64-linux-gnu/gnu/stubs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \ /usr/include/c++/5/ostream /usr/include/c++/5/ios \ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \ /usr/include/x86_64-linux-gnu/bits/wchar.h \ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \ /usr/include/c++/5/exception \ /usr/include/c++/5/bits/atomic_lockfree_defines.h \ /usr/include/c++/5/bits/char_traits.h \ /usr/include/c++/5/bits/stl_algobase.h \ /usr/include/c++/5/bits/functexcept.h \ /usr/include/c++/5/bits/exception_defines.h \ /usr/include/c++/5/bits/cpp_type_traits.h \ /usr/include/c++/5/ext/type_traits.h \ /usr/include/c++/5/ext/numeric_traits.h \ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \ /usr/include/c++/5/bits/concept_check.h \ /usr/include/c++/5/bits/stl_iterator_base_types.h \ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \ /usr/include/c++/5/bits/ptr_traits.h \ /usr/include/c++/5/bits/predefined_ops.h \ /usr/include/c++/5/bits/localefwd.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \ /usr/include/c++/5/clocale /usr/include/locale.h \ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \ /usr/include/x86_64-linux-gnu/bits/endian.h \ /usr/include/x86_64-linux-gnu/bits/byteswap.h \ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \ /usr/include/x86_64-linux-gnu/bits/sched.h \ /usr/include/x86_64-linux-gnu/bits/time.h \ /usr/include/x86_64-linux-gnu/bits/timex.h \ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \ /usr/include/x86_64-linux-gnu/bits/setjmp.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \ /usr/include/c++/5/bits/allocator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \ /usr/include/c++/5/bits/ostream_insert.h \ /usr/include/c++/5/bits/cxxabi_forced.h \ /usr/include/c++/5/bits/stl_function.h \ /usr/include/c++/5/backward/binders.h \ /usr/include/c++/5/bits/range_access.h \ /usr/include/c++/5/bits/basic_string.h \ /usr/include/c++/5/ext/alloc_traits.h \ /usr/include/c++/5/bits/basic_string.tcc \ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \ /usr/include/c++/5/bits/basic_ios.h \ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \ /usr/include/wctype.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \ /usr/include/c++/5/bits/streambuf_iterator.h \ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \ /usr/include/c++/5/bits/locale_facets.tcc \ /usr/include/c++/5/bits/basic_ios.tcc \ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \ /usr/include/c++/5/bits/istream.tcc /usr/include/stdlib.h \ /usr/include/x86_64-linux-gnu/bits/waitflags.h \ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \ /usr/include/x86_64-linux-gnu/sys/types.h \ /usr/include/x86_64-linux-gnu/sys/select.h \ /usr/include/x86_64-linux-gnu/bits/select.h \ /usr/include/x86_64-linux-gnu/bits/sigset.h \ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h /usr/include/libio.h \ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/string.h \ ../lib/list.cc ../threads/synch.h ../threads/thread.h \ ../machine/machine.h ../machine/translate.h ../userprog/addrspace.h \ ../filesys/filesys.h ../filesys/openfile.h ../threads/main.h \ ../threads/kernel.h ../threads/scheduler.h ../machine/interrupt.h \ ../machine/stats.h ../threads/alarm.h ../machine/timer.h \ ../threads/synchlist.cc # DEPENDENCIES MUST END AT END OF FILE # IF YOU PUT STUFF HERE IT WILL GO AWAY # see make depend above

project4/nachos/code/build.linux/console.o

project4/nachos/code/build.linux/post.o

project4/nachos/code/build.linux/sysdep.o

project4/nachos/code/build.linux/filesys.o

project4/nachos/code/build.linux/debug.o

project4/nachos/code/build.linux/alarm.o

project4/nachos/code/build.linux/synch.o

project4/nachos/code/build.linux/libtest.o

project4/nachos/code/build.linux/machine.o

project4/nachos/code/build.linux/Makefile

# Copyright (c) 1992-1996 The Regents of the University of California. # All rights reserved. See copyright.h for copyright notice and limitation # of liability and disclaimer of warranty provisions. # # This is a GNU Makefile. It must be used with the GNU make program. # At UW, the GNU make program is /software/gnu/bin/make. # In many other places it is known as "gmake". # You may wish to include /software/gnu/bin/ early in your command # search path, so that you will be using GNU make when you type "make". # # About this Makefile: # -------------------- # # This Makefile is used to build the Nachos system, which includes # the MIPS machine simulation and a simple operating system. # # There is a separate Makefile, in the "test" directory, that is # used to build the Nachos test programs (which run on the # simulated machine). # # There are several "build" directories, one for each type # of machine in the MFCF computing environment # (build.solaris, build.sunos, and build.ultrix), as well # as a build directory for Linux (build.linux) and a generic # build directory (build.other) for those who wish to try # building Nachos on other platforms. # # This Makefile appears to be located in all of the build directories. # If you edit it in one directory, the copies in all of the other # directories appear to change as well. This is the desired behaviour, # since this file is machine independent. (The file actually lives # in build.solaris, with symbolic links from the other build directories.) # # The platform-dependent parts of make's instructions are located # in the file Makefile.dep. # There is a different Makefile.dep in each build directory. # # If you are in the MFCF environment, you should not have to edit # the Makefile.dep files by hand. Any changes to the make instructions # can be made in this file (see the instructions below) - they will # apply no matter where you build Nachos. # If you are not in the MFCF environment, e.g., if you are trying # to build Nachos on Linux at home, you will probably need # to edit Makefile.dep (in the appropriate build directory) to # customize the make procedure to your environment. # # How to build Nachos for the first time: # --------------------------------------- # # (1) Make sure than you are in the build directory for the # type of machine you are logged in to (the "host" machine): # # host type examples build directory # ----------- ----------- ---------------- # # sparc/SunOS cayley,napier, build.sunos # (SunOS 4.1.3) descartes # # sparc/Solaris picard.math, build.solaris # (SunOS 5.x) hermite.math, # markov.math, # hypatia.math, # hume.math # # mips/ULTRIX cantor.math build.ultrix # (ULTRIX 4.2) noether.math # # If you are not sure what type of machine you are on, # try the command "uname -a". # # (2) Type "make depend" # - this computes file dependencies and records them # at the end of the file Makefile.dep in # your build directory. Have a look... # # (3) Type "make nachos" (or just "make"). # - make echos the commands it is executing, so that # you can observe its progress. When the # build is finished, you should have an # executable "nachos" in the build directory. # # (4) There is no 4th step. You are done. Try running "./nachos -u". # # # How to Re-build Nachos after you have changed the code: #-------------------------------------------------------- # # - The Nachos source code is located in the code subdirectories: # threads, userprog, filesys, network, and lib. You may # change the files in any of these directories, and you can # add new files and/or remove files. The "machine" subdirectory # contains the hardware simulation (which is also part of # Nachos. You may look at it, but # you may not change it, except as noted in machine/machine.h # - When you want to re-make Nachos, always do it in the # "build" directory that is appropriate for the machine # type that you are running on. # DO NOT TRY TO MAKE NACHOS IN THE SOURCE CODE DIRECTORIES. # # - IF all you have done is changed C++ code in existing files # (since the last time you made Nachos in this build directory), # THEN all you need to do to re-make Nachos is to type # # "make nachos" # # in the build directory. # # - IF you have done any of the following since the last build in # this directory: # added new .cc files or new .h files # added or deleted #include's from existing files # THEN # you must do # "make depend" # followed by # "make nachos" # # in the build directory. # # Note that is is always safe to do "make depend" followed by # "make nachos", so if you are not sure what changes you have # made, do "make depend". # # - IF you have added new files (.cc or .h) since the last build, # you should edit this Makefile before running "make depend" # and "make nachos". # For new .h files, simply update the appropriate "_H" list below. # For example, if you create a file called # "bigfile.h" in the filesys subdirectory, you should add # "../filesys/bigfile.h" to FILESYS_H, which is defined below # For new .cc files, update the appropriate "_C" and "_O" lists. # For example, if you create a file called "filetable.cc" in # the directory "userprog", you should add # "../userprog/filetable.cc" to USERPROG_C, # and you should add "filetable.o" to USERPROG_O. # Note that the entry in the "_C" list includes the subdirectory # name, while the entry on the "_O" list does not. # # Some Important Notes: # --------------------- # # * You can clean up all of the .o and other files left behind # by make by typeing "make clean" in the build directory. # * You can clean up .o and other files, as well as the nachos # executable, DISK, core, SOCKET, and other files by typing # make "distclean" # # These are good ways to save space, but the next build that # you do after cleaning will take longer than usual, since # much of the stuff you cleaned will need to be rebuilt. # # * When you build Nachos on an ULTRIX machine (in build.ultrix), # you will get lots of warning messages like this: # # openfile.o: does not have gp tables for all it's sectons # # from the loader. Ignore them. Or better yet, figure out # how to make them go away. # # The Most Important Note: # ----------------------- # # * If "make" is behaving strangely and you cannot figure out # why, you should REBUILD the program FROM SCRATCH. # Yes, it is slow. # But, there are lots of little things that can go wrong, especially # with all of these different types of machines available. # Rebuilding from scratch at least gives you a known starting # place. To rebuild from scratch, go to the appropriate # build directory and do: # # make distclean # make depend # make nachos # ################################################################ # READ THIS: CONFIGURING NACHOS # # Change DEFINES (below) to # DEFINES = -DUSE_TLB -DFILESYS_STUB # if you want the simulated machine to use its TLB # # If you want to use the real Nachos file system (based on # the simulated disk), rather than the stub, remove # the -DFILESYS_STUB from DEFINES. # # There is a a fix to the MIPS simulator to enable it to properly # handle unaligned data access. This fix is enabled by the addition # of "-DSIM_FIX" to the DEFINES. This should be enabled by default # and eventually will not require the symbol definition ################################################################ DEFINES = -DFILESYS_STUB -DRDATA -DSIM_FIX ##################################################################### # # You might want to play with the CFLAGS, but if you use -O it may # break the thread system. You might want to use -fno-inline if # you need to call some inline functions from the debugger. CFLAGS = -g -Wall $(INCPATH) $(DEFINES) $(HOSTCFLAGS) -DCHANGED -m32 LDFLAGS = -m32 CPP_AS_FLAGS= -m32 ##################################################################### CPP=/lib/cpp CC = g++ LD = g++ AS = as RM = /bin/rm INCPATH = -I../network -I../filesys -I../userprog -I../threads -I../machine -I../lib -I- PROGRAM = nachos # # Edit these lists as if you add files to the source directories. # See the instructions at the top of the file for more information. # LIB_H = ../lib/bitmap.h\ ../lib/copyright.h\ ../lib/debug.h\ ../lib/hash.h\ ../lib/libtest.h\ ../lib/list.h\ ../lib/sysdep.h\ ../lib/utility.h LIB_C = ../lib/bitmap.cc\ ../lib/debug.cc\ ../lib/hash.cc\ ../lib/libtest.cc\ ../lib/list.cc\ ../lib/sysdep.cc LIB_O = bitmap.o debug.o libtest.o sysdep.o MACHINE_H = ../machine/callback.h\ ../machine/interrupt.h\ ../machine/stats.h\ ../machine/timer.h\ ../machine/console.h\ ../machine/machine.h\ ../machine/mipssim.h\ ../machine/translate.h\ ../machine/network.h\ ../machine/disk.h MACHINE_C = ../machine/interrupt.cc\ ../machine/stats.cc\ ../machine/timer.cc\ ../machine/console.cc\ ../machine/machine.cc\ ../machine/mipssim.cc\ ../machine/translate.cc\ ../machine/network.cc\ ../machine/disk.cc MACHINE_O = interrupt.o stats.o timer.o console.o machine.o mipssim.o\ translate.o network.o disk.o THREAD_H = ../threads/alarm.h\ ../threads/kernel.h\ ../threads/main.h\ ../threads/scheduler.h\ ../threads/switch.h\ ../threads/synch.h\ ../threads/synchlist.h\ ../threads/thread.h THREAD_C = ../threads/alarm.cc\ ../threads/kernel.cc\ ../threads/main.cc\ ../threads/scheduler.cc\ ../threads/synch.cc\ ../threads/synchlist.cc\ ../threads/thread.cc\ ../threads/threadtest.cc THREAD_O = alarm.o kernel.o main.o scheduler.o synch.o thread.o threadtest.o USERPROG_H = ../userprog/addrspace.h\ ../userprog/syscall.h\ ../userprog/synchconsole.h\ ../userprog/noff.h USERPROG_C = ../userprog/addrspace.cc\ ../userprog/exception.cc\ ../userprog/synchconsole.cc USERPROG_O = addrspace.o exception.o synchconsole.o FILESYS_H =../filesys/directory.h \ ../filesys/filehdr.h\ ../filesys/filesys.h \ ../filesys/openfile.h\ ../filesys/pbitmap.h\ ../filesys/synchdisk.h FILESYS_C =../filesys/directory.cc\ ../filesys/filehdr.cc\ ../filesys/filesys.cc\ ../filesys/pbitmap.cc\ ../filesys/openfile.cc\ ../filesys/synchdisk.cc FILESYS_O =directory.o filehdr.o filesys.o pbitmap.o openfile.o synchdisk.o NETWORK_H = ../network/post.h NETWORK_C = ../network/post.cc NETWORK_O = post.o ################################################################## # You probably don't want to change anything below this point in # the file unless you are comfortable with GNU make and know what # you are doing... ################################################################## THREAD_S = ../threads/switch.s HFILES = $(LIB_H) $(MACHINE_H) $(THREAD_H) $(USERPROG_H) $(FILESYS_H) $(NETWORK_H) CFILES = $(LIB_C) $(MACHINE_C) $(THREAD_C) $(USERPROG_C) $(FILESYS_C) $(NETWORK_C) C_OFILES = $(LIB_O) $(MACHINE_O) $(THREAD_O) $(USERPROG_O) $(FILESYS_O) $(NETWORK_O) S_OFILES = switch.o OFILES = $(C_OFILES) $(S_OFILES) $(PROGRAM): $(OFILES) $(LD) $(OFILES) $(LDFLAGS) -o $(PROGRAM) $(C_OFILES): %.o: $(CC) $(CFLAGS) -c $< switch.o: ../threads/switch.S $(CC) $(CPP_AS_FLAGS) -P $(INCPATH) $(HOSTCFLAGS) -c ../threads/switch.S depend: $(CFILES) $(HFILES) $(CC) $(INCPATH) $(DEFINES) $(HOSTCFLAGS) -DCHANGED -M $(CFILES) > makedep @echo '/^# DO NOT DELETE THIS LINE/+1,$$d' >eddep @echo '$$r makedep' >>eddep @echo 'w' >>eddep @echo 'q' >>eddep ed - Makefile.dep < eddep rm eddep makedep @echo '# DEPENDENCIES MUST END AT END OF FILE' >> Makefile.dep @echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >> Makefile.dep @echo '# see make depend above' >> Makefile.dep clean: $(RM) -f $(OFILES) nachos DISK_0 distclean: clean $(RM) -f $(PROGRAM) $(RM) -f DISK_? $(RM) -f core $(RM) -f SOCKET_? @echo '/^# DO NOT DELETE THIS LINE/+1,$$d' >eddep @echo 'w' >>eddep @echo 'q' >>eddep ed - Makefile.dep < eddep rm eddep @echo '# DEPENDENCIES MUST END AT END OF FILE' >> Makefile.dep @echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >> Makefile.dep @echo '# see make depend above' >> Makefile.dep include Makefile.dep

project4/nachos/code/build.linux/translate.o

project4/nachos/code/build.linux/DISK_0

project4/nachos/code/build.linux/synchconsole.o

project4/nachos/code/build.linux/threadtest.o

project4/nachos/code/build.linux/scheduler.o

project4/nachos/code/build.linux/disk.o

project4/nachos/code/build.linux/timer.o

project4/nachos/code/build.linux/thread.o

project4/nachos/code/build.linux/directory.o

project4/nachos/code/build.linux/addrspace.o

project4/nachos/code/build.linux/network.o

project4/nachos/code/build.linux/openfile.o

project4/nachos/code/build.linux/kernel.o

project4/nachos/code/build.linux/interrupt.o

project4/nachos/code/build.linux/synchdisk.o

project4/nachos/code/build.linux/mipssim.o

project4/nachos/code/build.linux/exception.o

project4/nachos/code/build.linux/bitmap.o

project4/nachos/code/build.linux/nachos

project4/nachos/code/build.linux/switch.o

project4/nachos/code/build.linux/stats.o

project4/nachos/code/build.linux/pbitmap.o

project4/nachos/code/build.cygwin/Makefile.dep

################################################################## # Machine Dependencies - this file is included automatically # into the main Makefile # # This file contains definitions below for x86 running Linux # It has *not* been tested! ################################################################## HOSTCFLAGS = -Dx86 -DLINUX -DCYGWIN #----------------------------------------------------------------- # Do not put anything below this point - it will be destroyed by # "make depend" # # DO NOT DELETE THIS LINE -- make depend uses it # DEPENDENCIES MUST END AT END OF FILE bitmap.o: ../lib/bitmap.cc ../lib/copyright.h ../lib/debug.h \ ../lib/utility.h ../lib/sysdep.h /usr/include/g++-3/iostream.h \ /usr/include/g++-3/streambuf.h /usr/include/g++-3/libio.h \ /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h ../lib/bitmap.h debug.o: ../lib/debug.cc ../lib/copyright.h ../lib/utility.h \ ../lib/debug.h ../lib/sysdep.h /usr/include/g++-3/iostream.h \ /usr/include/g++-3/streambuf.h /usr/include/g++-3/libio.h \ /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h hash.o: ../lib/hash.cc ../lib/copyright.h libtest.o: ../lib/libtest.cc ../lib/copyright.h ../lib/libtest.h \ ../lib/bitmap.h ../lib/utility.h ../lib/list.h ../lib/debug.h \ ../lib/sysdep.h /usr/include/g++-3/iostream.h \ /usr/include/g++-3/streambuf.h /usr/include/g++-3/libio.h \ /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h ../lib/list.cc ../lib/hash.h ../lib/hash.cc list.o: ../lib/list.cc ../lib/copyright.h sysdep.o: ../lib/sysdep.cc ../lib/copyright.h ../lib/debug.h \ ../lib/utility.h ../lib/sysdep.h /usr/include/g++-3/iostream.h \ /usr/include/g++-3/streambuf.h /usr/include/g++-3/libio.h \ /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h /usr/include/unistd.h /usr/include/sys/unistd.h \ /usr/include/getopt.h /usr/include/sys/time.h \ /usr/include/sys/select.h /usr/include/time.h \ /usr/include/machine/time.h /usr/include/sys/file.h \ /usr/include/fcntl.h /usr/include/sys/fcntl.h /usr/include/sys/stat.h \ /usr/include/cygwin/stat.h /usr/include/sys/socket.h \ /usr/include/features.h /usr/include/cygwin/socket.h \ /usr/include/asm/socket.h /usr/include/cygwin/if.h \ /usr/include/cygwin/sockios.h /usr/include/cygwin/uio.h \ /usr/include/sys/un.h /usr/include/signal.h /usr/include/sys/signal.h interrupt.o: ../machine/interrupt.cc ../lib/copyright.h \ ../machine/interrupt.h ../lib/list.h ../lib/debug.h ../lib/utility.h \ ../lib/sysdep.h /usr/include/g++-3/iostream.h \ /usr/include/g++-3/streambuf.h /usr/include/g++-3/libio.h \ /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h ../lib/list.cc ../machine/callback.h \ ../threads/main.h ../threads/kernel.h ../threads/thread.h \ ../machine/machine.h ../machine/translate.h ../userprog/addrspace.h \ ../filesys/filesys.h ../filesys/openfile.h ../threads/scheduler.h \ ../machine/stats.h ../threads/alarm.h ../machine/timer.h stats.o: ../machine/stats.cc ../lib/copyright.h ../lib/debug.h \ ../lib/utility.h ../lib/sysdep.h /usr/include/g++-3/iostream.h \ /usr/include/g++-3/streambuf.h /usr/include/g++-3/libio.h \ /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h ../machine/stats.h timer.o: ../machine/timer.cc ../lib/copyright.h ../machine/timer.h \ ../lib/utility.h ../machine/callback.h ../threads/main.h \ ../lib/debug.h ../lib/sysdep.h /usr/include/g++-3/iostream.h \ /usr/include/g++-3/streambuf.h /usr/include/g++-3/libio.h \ /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h ../threads/kernel.h ../threads/thread.h \ ../machine/machine.h ../machine/translate.h ../userprog/addrspace.h \ ../filesys/filesys.h ../filesys/openfile.h ../threads/scheduler.h \ ../lib/list.h ../lib/list.cc ../machine/interrupt.h \ ../machine/stats.h ../threads/alarm.h console.o: ../machine/console.cc ../lib/copyright.h \ ../machine/console.h ../lib/utility.h ../machine/callback.h \ ../threads/main.h ../lib/debug.h ../lib/sysdep.h \ /usr/include/g++-3/iostream.h /usr/include/g++-3/streambuf.h \ /usr/include/g++-3/libio.h /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h ../threads/kernel.h ../threads/thread.h \ ../machine/machine.h ../machine/translate.h ../userprog/addrspace.h \ ../filesys/filesys.h ../filesys/openfile.h ../threads/scheduler.h \ ../lib/list.h ../lib/list.cc ../machine/interrupt.h \ ../machine/stats.h ../threads/alarm.h ../machine/timer.h machine.o: ../machine/machine.cc ../lib/copyright.h \ ../machine/machine.h ../lib/utility.h ../machine/translate.h \ ../threads/main.h ../lib/debug.h ../lib/sysdep.h \ /usr/include/g++-3/iostream.h /usr/include/g++-3/streambuf.h \ /usr/include/g++-3/libio.h /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h ../threads/kernel.h ../threads/thread.h \ ../userprog/addrspace.h ../filesys/filesys.h ../filesys/openfile.h \ ../threads/scheduler.h ../lib/list.h ../lib/list.cc \ ../machine/interrupt.h ../machine/callback.h ../machine/stats.h \ ../threads/alarm.h ../machine/timer.h mipssim.o: ../machine/mipssim.cc ../lib/copyright.h ../lib/debug.h \ ../lib/utility.h ../lib/sysdep.h /usr/include/g++-3/iostream.h \ /usr/include/g++-3/streambuf.h /usr/include/g++-3/libio.h \ /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h ../machine/machine.h ../machine/translate.h \ ../machine/mipssim.h ../threads/main.h ../threads/kernel.h \ ../threads/thread.h ../userprog/addrspace.h ../filesys/filesys.h \ ../filesys/openfile.h ../threads/scheduler.h ../lib/list.h \ ../lib/list.cc ../machine/interrupt.h ../machine/callback.h \ ../machine/stats.h ../threads/alarm.h ../machine/timer.h translate.o: ../machine/translate.cc ../lib/copyright.h \ ../threads/main.h ../lib/debug.h ../lib/utility.h ../lib/sysdep.h \ /usr/include/g++-3/iostream.h /usr/include/g++-3/streambuf.h \ /usr/include/g++-3/libio.h /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h ../threads/kernel.h ../threads/thread.h \ ../machine/machine.h ../machine/translate.h ../userprog/addrspace.h \ ../filesys/filesys.h ../filesys/openfile.h ../threads/scheduler.h \ ../lib/list.h ../lib/list.cc ../machine/interrupt.h \ ../machine/callback.h ../machine/stats.h ../threads/alarm.h \ ../machine/timer.h network.o: ../machine/network.cc ../lib/copyright.h \ ../machine/network.h ../lib/utility.h ../machine/callback.h \ ../threads/main.h ../lib/debug.h ../lib/sysdep.h \ /usr/include/g++-3/iostream.h /usr/include/g++-3/streambuf.h \ /usr/include/g++-3/libio.h /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h ../threads/kernel.h ../threads/thread.h \ ../machine/machine.h ../machine/translate.h ../userprog/addrspace.h \ ../filesys/filesys.h ../filesys/openfile.h ../threads/scheduler.h \ ../lib/list.h ../lib/list.cc ../machine/interrupt.h \ ../machine/stats.h ../threads/alarm.h ../machine/timer.h disk.o: ../machine/disk.cc ../lib/copyright.h ../machine/disk.h \ ../lib/utility.h ../machine/callback.h ../lib/debug.h ../lib/sysdep.h \ /usr/include/g++-3/iostream.h /usr/include/g++-3/streambuf.h \ /usr/include/g++-3/libio.h /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h ../threads/main.h ../threads/kernel.h \ ../threads/thread.h ../machine/machine.h ../machine/translate.h \ ../userprog/addrspace.h ../filesys/filesys.h ../filesys/openfile.h \ ../threads/scheduler.h ../lib/list.h ../lib/list.cc \ ../machine/interrupt.h ../machine/stats.h ../threads/alarm.h \ ../machine/timer.h alarm.o: ../threads/alarm.cc ../lib/copyright.h ../threads/alarm.h \ ../lib/utility.h ../machine/callback.h ../machine/timer.h \ ../threads/main.h ../lib/debug.h ../lib/sysdep.h \ /usr/include/g++-3/iostream.h /usr/include/g++-3/streambuf.h \ /usr/include/g++-3/libio.h /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h ../threads/kernel.h ../threads/thread.h \ ../machine/machine.h ../machine/translate.h ../userprog/addrspace.h \ ../filesys/filesys.h ../filesys/openfile.h ../threads/scheduler.h \ ../lib/list.h ../lib/list.cc ../machine/interrupt.h \ ../machine/stats.h kernel.o: ../threads/kernel.cc ../lib/copyright.h ../lib/debug.h \ ../lib/utility.h ../lib/sysdep.h /usr/include/g++-3/iostream.h \ /usr/include/g++-3/streambuf.h /usr/include/g++-3/libio.h \ /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h ../threads/main.h ../threads/kernel.h \ ../threads/thread.h ../machine/machine.h ../machine/translate.h \ ../userprog/addrspace.h ../filesys/filesys.h ../filesys/openfile.h \ ../threads/scheduler.h ../lib/list.h ../lib/list.cc \ ../machine/interrupt.h ../machine/callback.h ../machine/stats.h \ ../threads/alarm.h ../machine/timer.h ../threads/synch.h \ ../threads/synchlist.h ../threads/synchlist.cc ../lib/libtest.h \ ../userprog/synchconsole.h ../machine/console.h \ ../filesys/synchdisk.h ../machine/disk.h ../network/post.h \ ../machine/network.h main.o: ../threads/main.cc ../lib/copyright.h ../threads/main.h \ ../lib/debug.h ../lib/utility.h ../lib/sysdep.h \ /usr/include/g++-3/iostream.h /usr/include/g++-3/streambuf.h \ /usr/include/g++-3/libio.h /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h ../threads/kernel.h ../threads/thread.h \ ../machine/machine.h ../machine/translate.h ../userprog/addrspace.h \ ../filesys/filesys.h ../filesys/openfile.h ../threads/scheduler.h \ ../lib/list.h ../lib/list.cc ../machine/interrupt.h \ ../machine/callback.h ../machine/stats.h ../threads/alarm.h \ ../machine/timer.h scheduler.o: ../threads/scheduler.cc ../lib/copyright.h ../lib/debug.h \ ../lib/utility.h ../lib/sysdep.h /usr/include/g++-3/iostream.h \ /usr/include/g++-3/streambuf.h /usr/include/g++-3/libio.h \ /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h ../threads/scheduler.h ../lib/list.h \ ../lib/list.cc ../threads/thread.h ../machine/machine.h \ ../machine/translate.h ../userprog/addrspace.h ../filesys/filesys.h \ ../filesys/openfile.h ../threads/main.h ../threads/kernel.h \ ../machine/interrupt.h ../machine/callback.h ../machine/stats.h \ ../threads/alarm.h ../machine/timer.h synch.o: ../threads/synch.cc ../lib/copyright.h ../threads/synch.h \ ../threads/thread.h ../lib/utility.h ../lib/sysdep.h \ /usr/include/g++-3/iostream.h /usr/include/g++-3/streambuf.h \ /usr/include/g++-3/libio.h /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h ../machine/machine.h ../machine/translate.h \ ../userprog/addrspace.h ../filesys/filesys.h ../filesys/openfile.h \ ../lib/list.h ../lib/debug.h ../lib/list.cc ../threads/main.h \ ../threads/kernel.h ../threads/scheduler.h ../machine/interrupt.h \ ../machine/callback.h ../machine/stats.h ../threads/alarm.h \ ../machine/timer.h synchlist.o: ../threads/synchlist.cc ../lib/copyright.h \ ../threads/synchlist.h ../lib/list.h ../lib/debug.h ../lib/utility.h \ ../lib/sysdep.h /usr/include/g++-3/iostream.h \ /usr/include/g++-3/streambuf.h /usr/include/g++-3/libio.h \ /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h ../lib/list.cc ../threads/synch.h \ ../threads/thread.h ../machine/machine.h ../machine/translate.h \ ../userprog/addrspace.h ../filesys/filesys.h ../filesys/openfile.h \ ../threads/main.h ../threads/kernel.h ../threads/scheduler.h \ ../machine/interrupt.h ../machine/callback.h ../machine/stats.h \ ../threads/alarm.h ../machine/timer.h ../threads/synchlist.cc thread.o: ../threads/thread.cc ../lib/copyright.h ../threads/thread.h \ ../lib/utility.h ../lib/sysdep.h /usr/include/g++-3/iostream.h \ /usr/include/g++-3/streambuf.h /usr/include/g++-3/libio.h \ /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h ../machine/machine.h ../machine/translate.h \ ../userprog/addrspace.h ../filesys/filesys.h ../filesys/openfile.h \ ../threads/switch.h ../threads/synch.h ../lib/list.h ../lib/debug.h \ ../lib/list.cc ../threads/main.h ../threads/kernel.h \ ../threads/scheduler.h ../machine/interrupt.h ../machine/callback.h \ ../machine/stats.h ../threads/alarm.h ../machine/timer.h addrspace.o: ../userprog/addrspace.cc ../lib/copyright.h \ ../threads/main.h ../lib/debug.h ../lib/utility.h ../lib/sysdep.h \ /usr/include/g++-3/iostream.h /usr/include/g++-3/streambuf.h \ /usr/include/g++-3/libio.h /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h ../threads/kernel.h ../threads/thread.h \ ../machine/machine.h ../machine/translate.h ../userprog/addrspace.h \ ../filesys/filesys.h ../filesys/openfile.h ../threads/scheduler.h \ ../lib/list.h ../lib/list.cc ../machine/interrupt.h \ ../machine/callback.h ../machine/stats.h ../threads/alarm.h \ ../machine/timer.h ../userprog/noff.h exception.o: ../userprog/exception.cc ../lib/copyright.h \ ../threads/main.h ../lib/debug.h ../lib/utility.h ../lib/sysdep.h \ /usr/include/g++-3/iostream.h /usr/include/g++-3/streambuf.h \ /usr/include/g++-3/libio.h /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h ../threads/kernel.h ../threads/thread.h \ ../machine/machine.h ../machine/translate.h ../userprog/addrspace.h \ ../filesys/filesys.h ../filesys/openfile.h ../threads/scheduler.h \ ../lib/list.h ../lib/list.cc ../machine/interrupt.h \ ../machine/callback.h ../machine/stats.h ../threads/alarm.h \ ../machine/timer.h ../userprog/syscall.h ../userprog/errno.h \ ../userprog/ksyscall.h synchconsole.o: ../userprog/synchconsole.cc ../lib/copyright.h \ ../userprog/synchconsole.h ../lib/utility.h ../machine/callback.h \ ../machine/console.h ../threads/synch.h ../threads/thread.h \ ../lib/sysdep.h /usr/include/g++-3/iostream.h \ /usr/include/g++-3/streambuf.h /usr/include/g++-3/libio.h \ /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h ../machine/machine.h ../machine/translate.h \ ../userprog/addrspace.h ../filesys/filesys.h ../filesys/openfile.h \ ../lib/list.h ../lib/debug.h ../lib/list.cc ../threads/main.h \ ../threads/kernel.h ../threads/scheduler.h ../machine/interrupt.h \ ../machine/stats.h ../threads/alarm.h ../machine/timer.h directory.o: ../filesys/directory.cc ../lib/copyright.h \ ../lib/utility.h ../filesys/filehdr.h ../machine/disk.h \ ../machine/callback.h ../filesys/pbitmap.h ../lib/bitmap.h \ ../filesys/openfile.h ../lib/sysdep.h /usr/include/g++-3/iostream.h \ /usr/include/g++-3/streambuf.h /usr/include/g++-3/libio.h \ /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h ../filesys/directory.h filehdr.o: ../filesys/filehdr.cc ../lib/copyright.h \ ../filesys/filehdr.h ../machine/disk.h ../lib/utility.h \ ../machine/callback.h ../filesys/pbitmap.h ../lib/bitmap.h \ ../filesys/openfile.h ../lib/sysdep.h /usr/include/g++-3/iostream.h \ /usr/include/g++-3/streambuf.h /usr/include/g++-3/libio.h \ /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h ../lib/debug.h ../filesys/synchdisk.h \ ../threads/synch.h ../threads/thread.h ../machine/machine.h \ ../machine/translate.h ../userprog/addrspace.h ../filesys/filesys.h \ ../lib/list.h ../lib/list.cc ../threads/main.h ../threads/kernel.h \ ../threads/scheduler.h ../machine/interrupt.h ../machine/stats.h \ ../threads/alarm.h ../machine/timer.h filesys.o: ../filesys/filesys.cc pbitmap.o: ../filesys/pbitmap.cc ../lib/copyright.h \ ../filesys/pbitmap.h ../lib/bitmap.h ../lib/utility.h \ ../filesys/openfile.h ../lib/sysdep.h /usr/include/g++-3/iostream.h \ /usr/include/g++-3/streambuf.h /usr/include/g++-3/libio.h \ /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h openfile.o: ../filesys/openfile.cc synchdisk.o: ../filesys/synchdisk.cc ../lib/copyright.h \ ../filesys/synchdisk.h ../machine/disk.h ../lib/utility.h \ ../machine/callback.h ../threads/synch.h ../threads/thread.h \ ../lib/sysdep.h /usr/include/g++-3/iostream.h \ /usr/include/g++-3/streambuf.h /usr/include/g++-3/libio.h \ /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h ../machine/machine.h ../machine/translate.h \ ../userprog/addrspace.h ../filesys/filesys.h ../filesys/openfile.h \ ../lib/list.h ../lib/debug.h ../lib/list.cc ../threads/main.h \ ../threads/kernel.h ../threads/scheduler.h ../machine/interrupt.h \ ../machine/stats.h ../threads/alarm.h ../machine/timer.h post.o: ../network/post.cc ../lib/copyright.h ../network/post.h \ ../lib/utility.h ../machine/callback.h ../machine/network.h \ ../threads/synchlist.h ../lib/list.h ../lib/debug.h ../lib/sysdep.h \ /usr/include/g++-3/iostream.h /usr/include/g++-3/streambuf.h \ /usr/include/g++-3/libio.h /usr/include/_G_config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \ /usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \ /usr/include/sys/config.h /usr/include/sys/reent.h \ /usr/include/sys/_types.h /usr/include/machine/stdlib.h \ /usr/include/alloca.h /usr/include/stdio.h \ /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \ /usr/include/string.h ../lib/list.cc ../threads/synch.h \ ../threads/thread.h ../machine/machine.h ../machine/translate.h \ ../userprog/addrspace.h ../filesys/filesys.h ../filesys/openfile.h \ ../threads/main.h ../threads/kernel.h ../threads/scheduler.h \ ../machine/interrupt.h ../machine/stats.h ../threads/alarm.h \ ../machine/timer.h ../threads/synchlist.cc # DEPENDENCIES MUST END AT END OF FILE # IF YOU PUT STUFF HERE IT WILL GO AWAY # see make depend above

project4/nachos/code/build.cygwin/Makefile

# Copyright (c) 1992-1996 The Regents of the University of California. # All rights reserved. See copyright.h for copyright notice and limitation # of liability and disclaimer of warranty provisions. # # This is a GNU Makefile. It must be used with the GNU make program. # At UW, the GNU make program is /software/gnu/bin/make. # In many other places it is known as "gmake". # You may wish to include /software/gnu/bin/ early in your command # search path, so that you will be using GNU make when you type "make". # # About this Makefile: # -------------------- # # This Makefile is used to build the Nachos system, which includes # the MIPS machine simulation and a simple operating system. # # There is a separate Makefile, in the "test" directory, that is # used to build the Nachos test programs (which run on the # simulated machine). # # There are several "build" directories, one for each type # of machine in the MFCF computing environment # (build.solaris, build.sunos, and build.ultrix), as well # as a build directory for Linux (build.linux) and a generic # build directory (build.other) for those who wish to try # building Nachos on other platforms. # # This Makefile appears to be located in all of the build directories. # If you edit it in one directory, the copies in all of the other # directories appear to change as well. This is the desired behaviour, # since this file is machine independent. (The file actually lives # in build.solaris, with symbolic links from the other build directories.) # # The platform-dependent parts of make's instructions are located # in the file Makefile.dep. # There is a different Makefile.dep in each build directory. # # If you are in the MFCF environment, you should not have to edit # the Makefile.dep files by hand. Any changes to the make instructions # can be made in this file (see the instructions below) - they will # apply no matter where you build Nachos. # If you are not in the MFCF environment, e.g., if you are trying # to build Nachos on Linux at home, you will probably need # to edit Makefile.dep (in the appropriate build directory) to # customize the make procedure to your environment. # # How to build Nachos for the first time: # --------------------------------------- # # (1) Make sure than you are in the build directory for the # type of machine you are logged in to (the "host" machine): # # host type examples build directory # ----------- ----------- ---------------- # # sparc/SunOS cayley,napier, build.sunos # (SunOS 4.1.3) descartes # # sparc/Solaris picard.math, build.solaris # (SunOS 5.x) hermite.math, # markov.math, # hypatia.math, # hume.math # # mips/ULTRIX cantor.math build.ultrix # (ULTRIX 4.2) noether.math # # If you are not sure what type of machine you are on, # try the command "uname -a". # # (2) Type "make depend" # - this computes file dependencies and records them # at the end of the file Makefile.dep in # your build directory. Have a look... # # (3) Type "make nachos" (or just "make"). # - make echos the commands it is executing, so that # you can observe its progress. When the # build is finished, you should have an # executable "nachos" in the build directory. # # (4) There is no 4th step. You are done. Try running "./nachos -u". # # # How to Re-build Nachos after you have changed the code: #-------------------------------------------------------- # # - The Nachos source code is located in the code subdirectories: # threads, userprog, filesys, network, and lib. You may # change the files in any of these directories, and you can # add new files and/or remove files. The "machine" subdirectory # contains the hardware simulation (which is also part of # Nachos. You may look at it, but # you may not change it, except as noted in machine/machine.h # - When you want to re-make Nachos, always do it in the # "build" directory that is appropriate for the machine # type that you are running on. # DO NOT TRY TO MAKE NACHOS IN THE SOURCE CODE DIRECTORIES. # # - IF all you have done is changed C++ code in existing files # (since the last time you made Nachos in this build directory), # THEN all you need to do to re-make Nachos is to type # # "make nachos" # # in the build directory. # # - IF you have done any of the following since the last build in # this directory: # added new .cc files or new .h files # added or deleted #include's from existing files # THEN # you must do # "make depend" # followed by # "make nachos" # # in the build directory. # # Note that is is always safe to do "make depend" followed by # "make nachos", so if you are not sure what changes you have # made, do "make depend". # # - IF you have added new files (.cc or .h) since the last build, # you should edit this Makefile before running "make depend" # and "make nachos". # For new .h files, simply update the appropriate "_H" list below. # For example, if you create a file called # "bigfile.h" in the filesys subdirectory, you should add # "../filesys/bigfile.h" to FILESYS_H, which is defined below # For new .cc files, update the appropriate "_C" and "_O" lists. # For example, if you create a file called "filetable.cc" in # the directory "userprog", you should add # "../userprog/filetable.cc" to USERPROG_C, # and you should add "filetable.o" to USERPROG_O. # Note that the entry in the "_C" list includes the subdirectory # name, while the entry on the "_O" list does not. # # Some Important Notes: # --------------------- # # * You can clean up all of the .o and other files left behind # by make by typeing "make clean" in the build directory. # * You can clean up .o and other files, as well as the nachos # executable, DISK, core, SOCKET, and other files by typing # make "distclean" # # These are good ways to save space, but the next build that # you do after cleaning will take longer than usual, since # much of the stuff you cleaned will need to be rebuilt. # # * When you build Nachos on an ULTRIX machine (in build.ultrix), # you will get lots of warning messages like this: # # openfile.o: does not have gp tables for all it's sectons # # from the loader. Ignore them. Or better yet, figure out # how to make them go away. # # The Most Important Note: # ----------------------- # # * If "make" is behaving strangely and you cannot figure out # why, you should REBUILD the program FROM SCRATCH. # Yes, it is slow. # But, there are lots of little things that can go wrong, especially # with all of these different types of machines available. # Rebuilding from scratch at least gives you a known starting # place. To rebuild from scratch, go to the appropriate # build directory and do: # # make distclean # make depend # make nachos # ################################################################ # READ THIS: CONFIGURING NACHOS # # Change DEFINES (below) to # DEFINES = -DUSE_TLB -DFILESYS_STUB # if you want the simulated machine to use its TLB # # If you want to use the real Nachos file system (based on # the simulated disk), rather than the stub, remove # the -DFILESYS_STUB from DEFINES. # # There is a a fix to the MIPS simulator to enable it to properly # handle unaligned data access. This fix is enabled by the addition # of "-DSIM_FIX" to the DEFINES. This should be enabled by default # and eventually will not require the symbol definition ################################################################ DEFINES = -DFILESYS_STUB -DRDATA -DSIM_FIX ##################################################################### # # You might want to play with the CFLAGS, but if you use -O it may # break the thread system. You might want to use -fno-inline if # you need to call some inline functions from the debugger. CFLAGS = -g -Wall -fwritable-strings $(INCPATH) $(DEFINES) $(HOSTCFLAGS) -DCHANGED LDFLAGS = ##################################################################### CPP= cpp CC = g++ LD = g++ AS = as RM = rm INCPATH = -I../network -I../filesys -I../userprog -I../threads -I../machine -I../lib PROGRAM = nachos # # Edit these lists as if you add files to the source directories. # See the instructions at the top of the file for more information. # LIB_H = ../lib/bitmap.h\ ../lib/copyright.h\ ../lib/debug.h\ ../lib/hash.h\ ../lib/libtest.h\ ../lib/list.h\ ../lib/sysdep.h\ ../lib/utility.h LIB_C = ../lib/bitmap.cc\ ../lib/debug.cc\ ../lib/hash.cc\ ../lib/libtest.cc\ ../lib/list.cc\ ../lib/sysdep.cc LIB_O = bitmap.o debug.o libtest.o sysdep.o MACHINE_H = ../machine/callback.h\ ../machine/interrupt.h\ ../machine/stats.h\ ../machine/timer.h\ ../machine/console.h\ ../machine/machine.h\ ../machine/mipssim.h\ ../machine/translate.h\ ../machine/network.h\ ../machine/disk.h MACHINE_C = ../machine/interrupt.cc\ ../machine/stats.cc\ ../machine/timer.cc\ ../machine/console.cc\ ../machine/machine.cc\ ../machine/mipssim.cc\ ../machine/translate.cc\ ../machine/network.cc\ ../machine/disk.cc MACHINE_O = interrupt.o stats.o timer.o console.o machine.o mipssim.o\ translate.o network.o disk.o THREAD_H = ../threads/alarm.h\ ../threads/kernel.h\ ../threads/main.h\ ../threads/scheduler.h\ ../threads/switch.h\ ../threads/synch.h\ ../threads/synchlist.h\ ../threads/thread.h THREAD_C = ../threads/alarm.cc\ ../threads/kernel.cc\ ../threads/main.cc\ ../threads/scheduler.cc\ ../threads/synch.cc\ ../threads/synchlist.cc\ ../threads/thread.cc THREAD_O = alarm.o kernel.o main.o scheduler.o synch.o thread.o USERPROG_H = ../userprog/addrspace.h\ ../userprog/syscall.h\ ../userprog/synchconsole.h\ ../userprog/noff.h USERPROG_C = ../userprog/addrspace.cc\ ../userprog/exception.cc\ ../userprog/synchconsole.cc USERPROG_O = addrspace.o exception.o synchconsole.o FILESYS_H =../filesys/directory.h \ ../filesys/filehdr.h\ ../filesys/filesys.h \ ../filesys/openfile.h\ ../filesys/pbitmap.h\ ../filesys/synchdisk.h FILESYS_C =../filesys/directory.cc\ ../filesys/filehdr.cc\ ../filesys/filesys.cc\ ../filesys/pbitmap.cc\ ../filesys/openfile.cc\ ../filesys/synchdisk.cc\ FILESYS_O =directory.o filehdr.o filesys.o pbitmap.o openfile.o synchdisk.o NETWORK_H = ../network/post.h NETWORK_C = ../network/post.cc NETWORK_O = post.o ################################################################## # You probably don't want to change anything below this point in # the file unless you are comfortable with GNU make and know what # you are doing... ################################################################## THREAD_S = ../threads/switch.s HFILES = $(LIB_H) $(MACHINE_H) $(THREAD_H) $(USERPROG_H) $(FILESYS_H) $(NETWORK_H) CFILES = $(LIB_C) $(MACHINE_C) $(THREAD_C) $(USERPROG_C) $(FILESYS_C) $(NETWORK_C) C_OFILES = $(LIB_O) $(MACHINE_O) $(THREAD_O) $(USERPROG_O) $(FILESYS_O) $(NETWORK_O) S_OFILES = switch.o OFILES = $(C_OFILES) $(S_OFILES) $(PROGRAM): $(OFILES) $(LD) $(OFILES) $(LDFLAGS) -o $(PROGRAM) $(C_OFILES): %.o: $(CC) $(CFLAGS) -c $< switch.o: ../threads/switch.s $(CPP) $(CPP_AS_FLAGS) -P $(INCPATH) $(HOSTCFLAGS) ../threads/switch.s > swtch.s $(AS) -o switch.o swtch.s depend: $(CFILES) $(HFILES) $(CC) $(INCPATH) $(DEFINES) $(HOSTCFLAGS) -DCHANGED -M $(CFILES) > makedep @echo '/^# DO NOT DELETE THIS LINE/+2,$$d' >eddep @echo '$$r makedep' >>eddep @echo 'w' >>eddep @echo 'q' >>eddep ed - Makefile.dep < eddep rm eddep makedep @echo '# DEPENDENCIES MUST END AT END OF FILE' >> Makefile.dep @echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >> Makefile.dep @echo '# see make depend above' >> Makefile.dep clean: $(RM) -f $(OFILES) $(RM) -f swtch.s $(RM) -f *.s *.ii distclean: clean $(RM) -f $(PROGRAM) $(RM) -f $(PROGRAM).exe $(RM) -f DISK_? $(RM) -f core $(RM) -f SOCKET_? include Makefile.dep

project4/nachos/COPYRIGHT

Copyright (c) 1992-1993 The Regents of the University of California. All rights reserved. Permission to use, copy, modify, and distribute this software and its documentation for any purpose, without fee, and without written agreement is hereby granted, provided that the above copyright notice and the following two paragraphs appear in all copies of this software. IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

project4/nachos/c++example/inheritstack.h

// inheritstack.h // Data structures for a "stack" -- a Last-In-First-Out list of integers. // // We define two separate implementations of stacks, to // illustrate C++ inheritance. // // Copyright (c) 1992,1993,1995 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef INHERITSTACK_H // to prevent recursive includes #define INHERITSTACK_H #include "copyright.h" #include "list.h" // The following defines an "abstract" stack of integers. // This class is abstract because no one is allowed to create // instances of it; instead, you make instances of the derived // classes that inherit from it. class Stack { public: virtual ~Stack(); // Destructor virtual void Push(int value) = 0; // Push an integer on the stack virtual int Pop() = 0; // Pop an integer off the stack virtual bool Full() = 0; // Returns TRUE if the stack is full virtual bool Empty() = 0; // Returns TRUE if the stack is empty void SelfTest(int numToPush); // Test whether the implementation works. // Note that the test routine is shared among // all derived classes because it shouldn't // matter to the test code which version we're using! protected: Stack(); // Constructor is protected to prevent anyone but // derived classes from calling constructor. }; // The following defines an implementation of Stack using arrays. // This is the same as the original implementation in stack.h, // except we don't need a SelfTest() because that's defined above by Stack! class ArrayStack : public Stack { public: ArrayStack(int sz); // Constructor: initialize variables, allocate space. ~ArrayStack(); // Destructor: deallocate space allocated above. void Push(int value); // Push an integer on the stack int Pop(); // Pop an integer off the stack bool Full(); // Returns TRUE if the stack is full bool Empty(); // Returns TRUE if the stack is empty private: int size; // The maximum capacity of the stack. int top; // Index of the next position to be used. int *stack; // A pointer to an array that holds the contents. }; // The following defines an implementation of Stack using lists. // // Note that a list implementation can't overflow, so we don't // need to pass a maximum size into the constructor. class ListStack : public Stack { public: ListStack(); // Constructor: initialize variables, allocate space. ~ListStack(); // Destructor: deallocate space allocated above. void Push(int value); // Push an integer on the stack int Pop(); // Pop an integer off the stack bool Full(); // Always return FALSE, this implementation never overflows bool Empty(); // Returns TRUE if the stack is empty private: List *stack; }; #endif INHERITSTACK_H

project4/nachos/c++example/Makefile

PREFIX=decstation-ultrix- # add crosscompiler prefix here i.e. decstation-ultrix- INCLUDEDIR= # add path to include directories for crosscompiler environment here: # don't forget the -I tag before the directory # i.e: -I/usr/lcoal/nachosxdev/include -I/usr/local/nachosxdev/include/g++-3 all: stack inheritstack templatestack stack: stack.h stack.cc $(PREFIX)g++ $(INCLUDEDIR) -o stack stack.cc inheritstack: inheritstack.h inheritstack.cc list.h list.cc $(PREFIX)g++ $(INCLUDEDIR) -o inheritstack inheritstack.cc list.cc templatestack: templatestack.h templatestack.cc $(PREFIX)g++ $(INCLUDEDIR) -o templatestack templatestack.cc

project4/nachos/c++example/inheritstack.cc

project4/nachos/c++example/inheritstack.cc

// inheritstack.cc
//  Routines for two implementions of a LIFO stack of integers, 
//  one as an array, the other as a list.
//  
// Copyright (c) 1992,1993,1995 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.


extern   "C"   {
#include   < assert . h >

#define  ASSERT ( expression )   assert ( expression )
}

const   bool  FALSE  =   false ;
const   bool  TRUE  =   true ;

#include   < iostream . h >
#include   "copyright.h"
#include   "list.h"
#include   "inheritstack.h"

//----------------------------------------------------------------------
// Stack::Stack, Stack::~Stack
//  constructor and destructor for the Stack class; no data
//  to initialize!
//----------------------------------------------------------------------

Stack :: Stack ()   {}
Stack ::~ Stack ()   {}


// IMPLEMENTATION #1: AS AN ARRAY

//----------------------------------------------------------------------
// ArrayStack::ArrayStack
//  The constructor for the ArrayStack class.
//
//  "sz" -- maximum number of elements on the ArrayStack at any time
//----------------------------------------------------------------------

ArrayStack :: ArrayStack ( int  sz )   :   Stack ()   {

    ASSERT ( sz  >=   1 );

     // Initialize the data members of the stack object.
    size  =  sz ;
    top  =   0 ;
    stack  =   new   int [ size ];     // allocate an array of integers.
}

//----------------------------------------------------------------------
// ArrayStack::~ArrayStack
//  The destructor for the ArrayStack class.  Just get rid of the array we
//  allocated in the constructor.
//----------------------------------------------------------------------

ArrayStack ::~ ArrayStack ()   {

     delete   []  stack ;
}

//----------------------------------------------------------------------
// ArrayStack::Push
//  Put an integer on the top of the stack; error on overflow.
//
//  "value" -- the value to put on the stack
//----------------------------------------------------------------------

void
ArrayStack :: Push ( int   value )   {
    ASSERT ( ! Full ());
    
    stack [ top ++ ]   =   value ;
}

//----------------------------------------------------------------------
// ArrayStack::Pop
//  Remove an integer from the top of the stack, returning its value.
//  Error if the stack is empty.
//----------------------------------------------------------------------

int
ArrayStack :: Pop ()   {

    ASSERT ( ! Empty ());
    
     return   ( stack [ -- top ]);
}

//----------------------------------------------------------------------
// ArrayStack::Full
//  Return TRUE if the stack has no more room.
//----------------------------------------------------------------------

bool
ArrayStack :: Full ()   {
     return   ( top  ==  size );
}

//----------------------------------------------------------------------
// ArrayStack::Empty
//  Return TRUE if the stack has nothing on it.
//----------------------------------------------------------------------

bool
ArrayStack :: Empty ()   {
     return   ( top  ==   0 );
}


// IMPLEMENTATION #2: AS A LIST

//----------------------------------------------------------------------
// ListStack::ListStack
//  The constructor for the ListStack class.
//----------------------------------------------------------------------

ListStack :: ListStack ()   :   Stack ()   {

    stack  =   new   List ;      // allocate an empty list of integers.
}

//----------------------------------------------------------------------
// ListStack::~ListStack
//  The destructor for the ListStack class.  Just get rid of the list we
//  allocated in the constructor.
//----------------------------------------------------------------------

ListStack ::~ ListStack ()   {

     delete  stack ;
}

//----------------------------------------------------------------------
// ListStack::Push
//  Put an integer on the top of the stack.
//
//  "value" -- the value to put on the stack
//----------------------------------------------------------------------

void
ListStack :: Push ( int   value )   {
    stack -> Prepend ( value );
}

//----------------------------------------------------------------------
// ListStack::Pop
//  Remove an integer from the top of the stack, returning its value.
//  Error if the stack is empty.
//----------------------------------------------------------------------

int
ListStack :: Pop ()   {

    ASSERT ( ! Empty ());
    
     return  stack -> Remove ();
}

//----------------------------------------------------------------------
// ListStack::Full
//  Return FALSE, because a liststack can never overflow
//----------------------------------------------------------------------

bool
ListStack :: Full ()   {
     return  FALSE ;
}

//----------------------------------------------------------------------
// ListStack::Empty
//  Return TRUE if the stack has nothing on it.
//----------------------------------------------------------------------

bool
ListStack :: Empty ()   {
     return  stack -> Empty ();
}

//----------------------------------------------------------------------
// Stack::SelfTest
//  Test our stack implementation by pushing 10 numbers onto the 
//  stack, and then print them as it pops them off.
//
//  Note this code is generic between the two versions --
//  it doesn't matter whether this is an ArrayStack or a ListStack!
//
//  "numToPush" is the number of items to put on the stack in the 
//  selftest.
//----------------------------------------------------------------------

void
Stack :: SelfTest ( int  numToPush )   {
     int  count  =   17 ;
    
     // Put a bunch of stuff in the stack...
     for   ( int  i  =   0 ;  i  <  numToPush ;  i ++ )   {
    ASSERT ( ! Full ());
    cout  <<   "pushing "   <<  count  <<   "\n" ;
     Push ( count ++ );
     }
    
     // ... and take it out again.
     while   ( ! Empty ())   {
    cout  <<   "popping "   <<   Pop ()   <<   "\n" ;
     }
}

//----------------------------------------------------------------------
// main
//  Run the test code for the stack implementation.
//----------------------------------------------------------------------

int
main ()   {
     Stack   * s1  =   new   ArrayStack ( 10 );     // Constructor with an argument.
     Stack   * s2  =   new   ListStack ();  

    cout  <<   "Testing ArrayStack\n" ;
    s1 -> SelfTest ( 10 );

    cout  <<   "Testing ListStack\n" ;
    s2 -> SelfTest ( 10 );

     delete  s1 ;           // always delete what you allocate
     delete  s2 ;           // always delete what you allocate
     return   0 ;
}

project4/nachos/c++example/stack.cc

project4/nachos/c++example/stack.cc

// stack.cc
//  Routines to implement a LIFO stack of integers.
//  
//  The stack is represented as an array; we return an error
//  if the caller tries to push more things onto the stack than we have
//  room for.
//
// Copyright (c) 1992,1993,1995 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.


extern   "C"   {
#include   < assert . h >

#define  ASSERT ( expression )   assert ( expression )
}

#include   < iostream . h >
#include   "copyright.h"
#include   "stack.h"

//----------------------------------------------------------------------
// Stack::Stack
//  The constructor for the Stack class.  Note that it doesn't have a
//  return type.
//
//  "sz" -- maximum number of elements on the Stack at any time
//----------------------------------------------------------------------

Stack :: Stack ( int  sz )   {

    ASSERT ( sz  >=   1 );

     // Initialize the data members of the stack object.
    size  =  sz ;
    top  =   0 ;
    stack  =   new   int [ size ];     // allocate an array of integers.
}

//----------------------------------------------------------------------
// Stack::~Stack
//  The destructor for the Stack class.  Just get rid of the array we
//  allocated in the constructor.
//----------------------------------------------------------------------

Stack ::~ Stack ()   {

     delete   []  stack ;
}

//----------------------------------------------------------------------
// Stack::Push
//  Put an integer on the top of the stack; error on overflow.
//
//  "value" -- the value to put on the stack
//----------------------------------------------------------------------

void
Stack :: Push ( int   value )   {
    ASSERT ( ! Full ());
    
    stack [ top ++ ]   =   value ;
}

//----------------------------------------------------------------------
// Stack::Pop
//  Remove an integer from the top of the stack, returning its value.
//  Error if the stack is empty.
//----------------------------------------------------------------------

int
Stack :: Pop ()   {

    ASSERT ( ! Empty ());
    
     return   ( stack [ -- top ]);
}

//----------------------------------------------------------------------
// Stack::Full
//  Return TRUE if the stack has no more room.
//----------------------------------------------------------------------

bool
Stack :: Full ()   {
     return   ( top  ==  size );
}

//----------------------------------------------------------------------
// Stack::Empty
//  Return TRUE if the stack has nothing on it.
//----------------------------------------------------------------------

bool
Stack :: Empty ()   {
     return   ( top  ==   0 );
}

//----------------------------------------------------------------------
// Stack::SelfTest
//  Test our stack implementation by pushing 10 numbers onto the 
//  stack, and then print them as it pops them off.
//----------------------------------------------------------------------

void
Stack :: SelfTest ()   {
     int  count  =   17 ;
    
     // Put a bunch of stuff in the stack...
     while   ( ! Full ())   {
    cout  <<   "pushing "   <<  count  <<   "\n" ;
     Push ( count ++ );
     }
    
     // ... and take it out again.
     while   ( ! Empty ())   {
    cout  <<   "popping "   <<   Pop ()   <<   "\n" ;
     }
}

//----------------------------------------------------------------------
// main
//  Run the test code for the stack implementation.
//----------------------------------------------------------------------

int
main ()   {
     Stack   * stack  =   new   Stack ( 10 );     // Constructor with an argument.

    stack -> SelfTest ();

     delete  stack ;            // always delete what you allocate
     return   0 ;
}

project4/nachos/c++example/copyright.h

#ifndef COPYRIGHT_H #define COPYRIGHT_H /* Copyright (c) 1992,1993,1995 The Regents of the University of California. All rights reserved. Permission to use, copy, modify, and distribute this software and its documentation for any purpose, without fee, and without written agreement is hereby granted, provided that the above copyright notice and the following two paragraphs appear in all copies of this software. IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */ static char *copyright = "Copyright (c) 1992,1993,1995 The Regents of the University of California. All rights reserved."; #endif /* COPYRIGHT_H */

project4/nachos/c++example/c++.ps

project4/nachos/c++example/list.h

// list.h // Data structures to manage LISP-like lists. // // Copyright (c) 1992,1993,1995 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef LIST_H #define LIST_H #include "copyright.h" class ListElement; // The following class defines a "list" -- a singly linked list of // list elements, each of which contains an integer. class List { public: List(); // initialize the list ~List(); // de-allocate the list void Prepend(int value); // Put item at the beginning of the list int Remove(); // Take item off the front of the list bool Empty(); // is the list empty? void SelfTest(); private: ListElement *first; // Head of the list, NULL if list is empty ListElement *last; // Last element of list }; #endif // LIST_H

project4/nachos/c++example/templatestack.h

// templatestack.h // Data structures for a stack" -- a Last-In-First-Out list -- // of arbitrary things. // // Copyright (c) 1992,1993,1995 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef TEMPLATESTACK_H // to prevent recursive includes #define TEMPLATESTACK_H #include "copyright.h" // The following defines the Stack class. The functions are // implemented in the file templatestack.cc. // // T is the type of the thing we want to put on the stack. template <class T> class Stack { public: Stack(int sz); // Constructor ~Stack(); // Destructor void Push(T value); // Push a T on the stack T Pop(); // Pop a T off the stack bool Full(); // Returns TRUE if the stack is full bool Empty(); // Returns TRUE if the stack is empty void SelfTest(T start); // Test whether the implementation works. private: int size; // The maximum capacity of the stack. int top; // Index of the next position to be used. T *stack; // A pointer to an array that holds the contents. }; #endif // TEMPLATESTACK_H

project4/nachos/c++example/c++.tex

\documentstyle[12pt,fullpage]{article} \newcommand{\putfig}[3]% {\begin{figure}% \centerline{% \psfig{figure=#1.ps,width=#3}}% \caption{#2}% \label{fig:#1}% \end{figure}} \input{psfig} \begin{document} \begin{figure*}[t] \begin{center} {\LARGE\bf A Quick Introduction to C++} \vspace{3.0ex} {\Large Tom Anderson} \end{center} \end{figure*} \renewcommand{\thefootnote}{\fnsymbol{footnote}} \footnotetext{This article is based on an earlier version written by Wayne Christopher.} \renewcommand{\thefootnote}{} \renewcommand{\thefootnote}{\arabic{footnote}} \begin{quote} ``If programming in Pascal is like being put in a straightjacket, then programming in C is like playing with knives, and programming in C++ is like juggling chainsaws.'' \\ \hbox{} \hfill Anonymous. \end{quote} \section{Introduction} This note introduces some simple C++ concepts and outlines a subset of C++ that is easier to learn and use than the full language. Although we originally wrote this note for explaining the C++ used in the Nachos project, I believe it is useful to anyone learning C++. I assume that you are already somewhat familiar with C concepts like procedures, for loops, and pointers; these are pretty easy to pick up from reading Kernighan and Ritchie's ``The C Programming Language.'' I should admit up front that I am quite opinionated about C++, if that isn't obvious already. I know several C++ purists (an oxymoron perhaps?) who violently disagree with some of the prescriptions contained here; most of the objections are of the form, ``How could you have possibly left out feature X?'' However, I've found from teaching C++ to nearly 1000 undergrads over the past several years that the subset of C++ described here is pretty easy to learn, taking only a day or so for most students to get started. The basic premise of this note is that while object-oriented programming is a useful way to simplify programs, C++ is a wildly over-complicated language, with a host of features that only very, very rarely find a legitimate use. It's not too far off the mark to say that C++ includes every programming language feature ever imagined, and more. The natural tendency when faced with a new language feature is to try to use it, but in C++ this approach leads to disaster. Thus, we need to carefully distinguish between (i) those concepts that are fundamental (e.g., classes, member functions, constructors) -- ones that everyone should know and use, (ii) those that are sometimes but rarely useful (e.g., single inheritance, templates) -- ones that beginner programmers should be able to recognize (in case they run across them) but avoid using in their own programs, at least for a while, and (iii) those that are just a bad idea and should be avoided like the plague (e.g., multiple inheritance, exceptions, overloading, references, etc). Of course, all the items in this last category have their proponents, and I will admit that, like the hated goto, it is possible to construct cases when the program would be simpler using a goto or multiple inheritance. However, it is my belief that most programmers will never encounter such cases, and even if you do, you will be much more likely to misuse the feature than properly apply it. For example, I seriously doubt an undergraduate would need any of the features listed under (iii) for any course project (at least at Berkeley this is true). And if you find yourself wanting to use a feature like multiple inheritance, then, my advice is to fully implement your program both with and without the feature, and choose whichever is simpler. Sure, this takes more effort, but pretty soon you'll know from experience when a feature is useful and when it isn't, and you'll be able to skip the dual implementation. A really good way to learn a language is to read clear programs in that language. I have tried to make the Nachos code as readable as possible; it is written in the subset of C++ described in this note. It is a good idea to look over the first assignment as you read this introduction. Of course, your TA's will answer any questions you may have. You should not need a book on C++ to do the Nachos assignments, but if you are curious, there is a large selection of C++ books at Cody's and other technical bookstores. (My wife quips that C++ was invented to make researchers at Bell Labs rich from writing ``How to Program in C++'' books.) Most new software development these days is being done in C++, so it is a pretty good bet you'll run across it in the future. I use Stroustrup's "The C++ Programming Language" as a reference manual, although other books may be more readable. I would also recommend Scott Meyer's ``Effective C++'' for people just beginning to learn the language, and Coplien's ``Advanced C++'' once you've been programming in C++ for a couple years and are familiar with the language basics. Also, C++ is continually evolving, so be careful to buy books that describe the latest version (currently 3.0, I think!). \section{C in C++} To a large extent, C++ is a superset of C, and most carefully written ANSI C will compile as C++. There are a few major caveats though: \begin{enumerate} \item All functions must be declared before they are used, rather than defaulting to type {\tt int}. \item All function declarations and definition headers must use new-style declarations, e.g., \begin{verbatim} extern int foo(int a, char* b); \end{verbatim} The form {\tt extern int foo();} means that {\tt foo} takes {\it no} arguments, rather than arguments of an unspecified type and number. In fact, some advise using a C++ compiler even on normal C code, because it will catch errors like misused functions that a normal C compiler will let slide. \item If you need to link C object files together with C++, when you declare the C functions for the C++ files, they must be done like this: \begin{verbatim} extern "C" int foo(int a, char* b); \end{verbatim} Otherwise the C++ compiler will alter the name in a strange manner. \item There are a number of new keywords, which you may not use as identifiers --- some common ones are {\tt new}, {\tt delete}, {\tt const}, and {\tt class}. \end{enumerate} \section{Basic Concepts} Before giving examples of C++ features, I will first go over some of the basic concepts of object-oriented languages. If this discussion at first seems a bit obscure, it will become clearer when we get to some examples. \begin{enumerate} \item {\bf Classes and objects}. A class is similar to a C {\em structure}, except that the definition of the data structure, {\em and} all of the functions that operate on the data structure are grouped together in one place. An {\em object} is an instance of a class (an instance of the data structure); objects share the same functions with other objects of the same class, but each object (each instance) has its own copy of the data structure. A class thus defines two aspects of the objects: the {\em data} they contain, and the {\em behavior} they have. \item {\bf Member functions}. These are functions which are considered part of the object and are declared in the class definition. They are often referred to as {\em methods} of the class. In addition to member functions, a class's behavior is also defined by: \begin{enumerate} \item What to do when you create a new object (the {\bf constructor} for that object) -- in other words, initialize the object's data. \item What to do when you delete an object (the {\bf destructor} for that object). \end{enumerate} \item {\bf Private vs. public members}. A public member of a class is one that can be read or written by anybody, in the case of a data member, or called by anybody, in the case of a member function. A private member can only be read, written, or called by a member function of that class. \end{enumerate} Classes are used for two main reasons: (1) it makes it much easier to organize your programs if you can group together data with the functions that manipulate that data, and (2) the use of private members makes it possible to do {\em information hiding}, so that you can be more confident about the way information flows in your programs. \subsection{Classes} C++ classes are similar to C structures in many ways. In fact, a C++ struct is really a class that has only public data members. In the following explanation of how classes work, we will use a stack class as an example. \begin{enumerate} \item {\bf Member functions.} Here is a (partial) example of a class with a member function and some data members: \begin{verbatim} class Stack { public: void Push(int value); // Push an integer, checking for overflow. int top; // Index of the top of the stack. int stack[10]; // The elements of the stack. }; void Stack::Push(int value) { ASSERT(top < 10); // stack should never overflow stack[top++] = value; } \end{verbatim} This class has two data members, {\tt top} and {\tt stack}, and one member function, {\tt Push}. The notation {\em class}::{\em function} denotes the {\em function} member of the class {\em class}. (In the style we use, most function names are capitalized.) The function is defined beneath it. As an aside, note that we use a call to {\tt ASSERT} to check that the stack hasn't overflowed; ASSERT drops into the debugger if the condition is false. It is an extremely good idea for you to use ASSERT statements liberally throughout your code to document assumptions made by your implementation. Better to catch errors automatically via ASSERTs than to let them go by and have your program overwrite random locations. In actual usage, the definition of {\tt class Stack} would typically go in the file {\tt stack.h} and the definitions of the member functions, like {\tt Stack::Push}, would go in the file {\tt stack.cc}. If we have a pointer to a {\tt Stack} object called {\tt s}, we can access the {\tt top} element as {\tt s->top}, just as in C. However, in C++ we can also call the member function using the following syntax: \begin{verbatim} s->Push(17); \end{verbatim} Of course, as in C, {\tt s} must point to a valid {\tt Stack} object. Inside a member function, one may refer to the members of the class by their names alone. In other words, the class definition creates a scope that includes the member (function and data) definitions. Note that if you are inside a member function, you can get a pointer to the object you were called on by using the variable {\tt this}. If you want to call another member function on the same object, you do not need to use the {\tt this} pointer, however. Let's extend the Stack example to illustrate this by adding a {\tt Full()} function. \begin{verbatim} class Stack { public: void Push(int value); // Push an integer, checking for overflow. bool Full(); // Returns TRUE if the stack is full, FALSE otherwise. int top; // Index of the lowest unused position. int stack[10]; // A pointer to an array that holds the contents. }; \end{verbatim} \newpage \begin{verbatim} bool Stack::Full() { return (top == 10); } \end{verbatim} Now we can rewrite {\tt Push} this way: \begin{verbatim} void Stack::Push(int value) { ASSERT(!Full()); stack[top++] = value; } \end{verbatim} We could have also written the ASSERT: \begin{verbatim} ASSERT(!(this->Full()); \end{verbatim} but in a member function, the \verb+this->+ is implicit. The purpose of member functions is to encapsulate the functionality of a type of object along with the data that the object contains. A member function does not take up space in an object of the class. \item {\bf Private members.} One can declare some members of a class to be {\it private}, which are hidden to all but the member functions of that class, and some to be {\it public}, which are visible and accessible to everybody. Both data and function members can be either public or private. In our stack example, note that once we have the {\tt Full()} function, we really don't need to look at the {\tt top} or {\tt stack} members outside of the class -- in fact, we'd rather that users of the Stack abstraction {\em not} know about its internal implementation, in case we change it. Thus we can rewrite the class as follows: \begin{verbatim} class Stack { public: void Push(int value); // Push an integer, checking for overflow. bool Full(); // Returns TRUE if the stack is full, FALSE otherwise. private: int top; // Index of the top of the stack. int stack[10]; // The elements of the stack. }; \end{verbatim} Before, given a pointer to a {\tt Stack} object, say {\tt s}, any part of the program could access {\tt s->top}, in potentially bad ways. Now, since the {\tt top} member is private, only a member function, such as {\tt Full()}, can access it. If any other part of the program attempts to use {\tt s->top} the compiler will report an error. You can have alternating {\tt public:} and {\tt private:} sections in a class. Before you specify either of these, class members are private, thus the above example could have been written: \begin{verbatim} class Stack { int top; // Index of the top of the stack. int stack[10]; // The elements of the stack. public: void Push(int value); // Push an integer, checking for overflow. bool Full(); // Returns TRUE if the stack is full, FALSE otherwise. }; \end{verbatim} Which form you prefer is a matter of style, but it's usually best to be explicit, so that it is obvious what is intended. In Nachos, we make everything explicit. What is not a matter of style: {\bf all data members of a class should be private.} All operations on data should be via that class' member functions. Keeping data private adds to the modularity of the system, since you can redefine how the data members are stored without changing how you access them. \item {\bf Constructors and the operator new.} In C, in order to create a new object of type {\tt Stack}, one might write: \begin{verbatim} struct Stack *s = (struct Stack *) malloc(sizeof (struct Stack)); InitStack(s, 17); \end{verbatim} The {\tt InitStack()} function might take the second argument as the size of the stack to create, and use {\tt malloc()} again to get an array of 17 integers. The way this is done in C++ is as follows: \begin{verbatim} Stack *s = new Stack(17); \end{verbatim} The {\tt new} function takes the place of {\tt malloc()}. To specify how the object should be initialized, one declares a {\it constructor} function as a member of the class, with the name of the function being the same as the class name: \begin{verbatim} class Stack { public: Stack(int sz); // Constructor: initialize variables, allocate space. void Push(int value); // Push an integer, checking for overflow. bool Full(); // Returns TRUE if the stack is full, FALSE otherwise. private: int size; // The maximum capacity of the stack. int top; // Index of the lowest unused position. int* stack; // A pointer to an array that holds the contents. }; Stack::Stack(int sz) { size = sz; top = 0; stack = new int[size]; // Let's get an array of integers. } \end{verbatim} There are a few things going on here, so we will describe them one at a time. The {\tt new} operator automatically creates (i.e. allocates) the object and then calls the constructor function for the new object. This same sequence happens even if, for instance, you declare an object as an automatic variable inside a function or block -- the compiler allocates space for the object on the stack, and calls the constructor function on it. In this example, we create two stacks of different sizes, one by declaring it as an automatic variable, and one by using {\tt new}. \begin{verbatim} void test() { Stack s1(17); Stack* s2 = new Stack(23); } \end{verbatim} Note there are two ways of providing arguments to constructors: with {\tt new}, you put the argument list after the class name, and with automatic or global variables, you put them after the variable name. It is crucial that you {\bf always} define a constructor for every class you define, and that the constructor initialize {\bf every} data member of the class. If you don't define your own constructor, the compiler will automatically define one for you, and believe me, it won't do what you want (``the unhelpful compiler''). The data members will be initialized to random, unrepeatable values, and while your program may work anyway, it might not the next time you recompile (or vice versa!). As with normal C variables, variables declared inside a function are deallocated automatically when the function returns; for example, the {\tt s1} object is deallocated when {\tt test} returns. Data allocated with {\tt new} (such as {\tt s2}) is stored on the heap, however, and remains after the function returns; heap data must be explicitly disposed of using {\tt delete}, described below. The {\tt new} operator can also be used to allocate arrays, illustrated above in allocating an array of {\tt ints}, of dimension {\tt size}: \begin{verbatim} stack = new int[size]; \end{verbatim} Note that you can use {\tt new} and {\tt delete} (described below) with built-in types like {\tt int} and {\tt char} as well as with class objects like {\tt Stack}. \item {\bf Destructors and the operator delete.} Just as {\tt new} is the replacement for {\tt malloc()}, the replacement for {\tt free()} is {\tt delete}. To get rid of the {\tt Stack} object we allocated above with {\tt new}, one can do: \begin{verbatim} delete s2; \end{verbatim} This will deallocate the object, but first it will call the {\it destructor} for the {\tt Stack} class, if there is one. This destructor is a member function of {\tt Stack} called {\tt {\verb^~^}Stack()}: \begin{verbatim} class Stack { public: Stack(int sz); // Constructor: initialize variables, allocate space. ~Stack(); // Destructor: deallocate space allocated above. void Push(int value); // Push an integer, checking for overflow. bool Full(); // Returns TRUE if the stack is full, FALSE otherwise. private: int size; // The maximum capacity of the stack. int top; // Index of the lowest unused position. int* stack; // A pointer to an array that holds the contents. }; Stack::~Stack() { delete [] stack; // delete an array of integers } \end{verbatim} The destructor has the job of deallocating the data the constructor allocated. Many classes won't need destructors, and some will use them to close files and otherwise clean up after themselves. The destructor for an object is called when the object is deallocated. If the object was created with {\tt new}, then you must call {\tt delete} on the object, or else the object will continue to occupy space until the program is over -- this is called ``a memory leak.'' Memory leaks are bad things -- although virtual memory is supposed to be unlimited, you can in fact run out of it -- and so you should be careful to {\bf always} delete what you allocate. Of course, it is even worse to call {\tt delete} too early -- {\tt delete} calls the destructor and puts the space back on the heap for later re-use. If you are still using the object, you will get random and non-repeatable results that will be very difficult to debug. In my experience, using data that has already been deleted is major source of hard-to-locate bugs in student (and professional) programs, so hey, be careful out there! If the object is an automatic, allocated on the execution stack of a function, the destructor will be called and the space deallocated when the function returns; in the {\tt test()} example above, {\tt s1} will be deallocated when {\tt test()} returns, without you having to do anything. In Nachos, we always explicitly allocate and deallocate objects with {\tt new} and {\tt delete}, to make it clear when the constructor and destructor is being called. For example, if an object contains another object as a member variable, we use {\tt new} to explicitly allocated and initialize the member variable, instead of implicitly allocating it as part of the containing object. C++ has strange, non-intuitive rules for the order in which the constructors and destructors are called when you implicitly allocate and deallocate objects. In practice, although simpler, explicit allocation is slightly slower and it makes it more likely that you will forget to deallocate an object (a bad thing!), and so some would disagree with this approach. When you deallocate an array, you have to tell the compiler that you are deallocating an array, as opposed to a single element in the array. Hence to delete the array of integers in {\tt Stack::{\verb^~^}Stack}: \begin{verbatim} delete [] stack; \end{verbatim} \end{enumerate} \subsection{Other Basic C++ Features} Here are a few other C++ features that are useful to know. \begin{enumerate} \item When you define a {\tt class Stack}, the name {\tt Stack} becomes usable as a type name as if created with {\tt typedef}. The same is true for {\tt enum}s. \item You can define functions inside of a {\tt class} definition, whereupon they become {\it inline functions}, which are expanded in the body of the function where they are used. The rule of thumb to follow is to only consider inlining one-line functions, and even then do so rarely. As an example, we could make the {\tt Full} routine an inline. \begin{verbatim} class Stack { ... bool Full() { return (top == size); }; ... }; \end{verbatim} There are two motivations for inlines: convenience and performance. If overused, inlines can make your code more confusing, because the implementation for an object is no longer in one place, but spread between the {\tt .h} and {\tt .c} files. Inlines can sometimes speed up your code (by avoiding the overhead of a procedure call), but that shouldn't be your principal concern as a student (rather, at least to begin with, you should be most concerned with writing code that is simple and bug free). Not to mention that inlining sometimes slows down a program, since the object code for the function is duplicated wherever the function is called, potentially hurting cache performance. \item Inside a function body, you can declare some variables, execute some statements, and then declare more variables. This can make code a lot more readable. In fact, you can even write things like: \begin{verbatim} for (int i = 0; i < 10; i++) ; \end{verbatim} Depending on your compiler, however, the variable {\tt i} may still visible after the end of the {\tt for} loop, however, which is not what one might expect or desire. \item Comments can begin with the characters \verb+//+ and extend to the end of the line. These are usually more handy than the \verb+/* */+ style of comments. \item C++ provides some new opportunities to use the {\tt const} keyword from ANSI C. The basic idea of {\tt const} is to provide extra information to the compiler about how a variable or function is used, to allow it to flag an error if it is being used improperly. You should always look for ways to get the compiler to catch bugs for you. After all, which takes less time? Fixing a compiler-flagged error, or chasing down the same bug using gdb? For example, you can declare that a member function only reads the member data, and never modifies the object: \begin{verbatim} class Stack { ... bool Full() const; // Full() never modifies member data ... }; \end{verbatim} As in C, you can use {\tt const} to declare that a variable is never modified: \begin{verbatim} const int InitialHashTableSize = 8; \end{verbatim} This is {\em much} better than using {\tt \#define} for constants, since the above is type-checked. \item Input/output in C++ can be done with the {\tt >>} and {\tt <<} operators and the objects {\tt cin} and {\tt cout}. For example, to write to {\tt stdout}: \begin{verbatim} cout << "Hello world! This is section " << 3 << "!"; \end{verbatim} This is equivalent to the normal C code \begin{verbatim} fprintf(stdout, "Hello world! This is section %d!\n", 3); \end{verbatim} except that the C++ version is type-safe; with {\tt printf}, the compiler won't complain if you try to print a floating point number as an integer. In fact, you can use traditional {\tt printf} in a C++ program, but you will get bizarre behavior if you try to use both {\tt printf} and {\tt <<} on the same stream. Reading from {\tt stdin} works the same way as writing to {\tt stdout}, except using the shift right operator instead of shift left. In order to read two integers from {\tt stdin}: \begin{verbatim} int field1, field2; cin >> field1 >> field2; // equivalent to fscanf(stdin, "%d %d", &field1, &field2); // note that field1 and field2 are implicitly modified \end{verbatim} In fact, {\tt cin} and {\tt cout} are implemented as normal C++ objects, using operator overloading and reference parameters, but (fortunately!) you don't need to understand either of those to be able to do I/O in C++. \end{enumerate} \section{Advanced Concepts in C++: Dangerous but Occasionally Useful} There are a few C++ features, namely (single) inheritance and templates, which are easily abused, but can dramatically simplify an implementation if used properly. I describe the basic idea behind these ``dangerous but useful'' features here, in case you run across them. Feel free to skip this section -- it's long, complex, and you can understand 99\% of the code in Nachos without reading this section. Up to this point, there really hasn't been any fundamental difference between programming in C and in C++. In fact, most experienced C programmers organize their functions into modules that relate to a single data structure (a "class"), and often even use a naming convention which mimics C++, for example, naming routines {\tt StackFull()} and {\tt StackPush()}. However, the features I'm about to describe {\em do} require a paradigm shift -- there is no simple translation from them into a normal C program. The benefit will be that, in some circumstances, you will be able to write generic code that works with multiple kinds of objects. Nevertheless, I would advise a beginning C++ programmer against trying to use these features, because you will almost certainly misuse them. It's possible (even easy!) to write completely inscrutable code using inheritance and/or templates. Although you might find it amusing to write code that is impossible for your graders to understand, I assure you they won't find it amusing at all, and will return the favor when they assign grades. In industry, a high premium is placed on keeping code simple and readable. It's easy to write new code, but the real cost comes when you try to keep it working, even as you add new features to it. Nachos contains a few examples of the correct use of inheritance and templates, but realize that Nachos does {\em not} use them everywhere. In fact, if you get confused by this section, don't worry, you don't need to use any of these features in order to do the Nachos assignments. I omit a whole bunch of details; if you find yourself making widespread use of inheritance or templates, you should consult a C++ reference manual for the real scoop. This is meant to be just enough to get you started, and to help you identify when it would be appropriate to use these features and thus learn more about them! \subsection{Inheritance} Inheritance captures the idea that certain classes of objects are related to each other in useful ways. For example, lists and sorted lists have quite similar behavior -- they both allow the user to insert, delete, and find elements that are on the list. There are two benefits to using inheritance: \begin{enumerate} \item You can write generic code that doesn't care exactly which kind of object it is manipulating. For example, inheritance is widely used in windowing systems. Everything on the screen (windows, scroll bars, titles, icons) is its own object, but they all share a set of member functions in common, such as a routine {\tt Repaint} to redraw the object onto the screen. This way, the code to repaint the entire screen can simply call the {\tt Repaint} function on every object on the screen. The code that calls {\tt Repaint} doesn't need to know which kinds of objects are on the screen, as long as each implements {\tt Repaint}. \item You can share pieces of an implementation between two objects. For example, if you were to implement both lists and sorted lists in C, you'd probably find yourself repeating code in both places -- in fact, you might be really tempted to only implement sorted lists, so that you only had to debug one version. Inheritance provides a way to re-use code between nearly similar classes. For example, given an implementation of a list class, in C++ you can implement sorted lists by replacing the insert member function -- the other functions, delete, isFull, print, all remain the same. \end{enumerate} \subsubsection{Shared Behavior} Let me use our Stack example to illustrate the first of these. Our Stack implementation above could have been implemented with linked lists, instead of an array. Any code using a Stack shouldn't care which implementation is being used, except that the linked list implementation can't overflow. (In fact, we could also change the array implementation to handle overflow by automatically resizing the array as items are pushed on the stack.) To allow the two implementations to coexist, we first define an {\em abstract} Stack, containing just the public member functions, but no data. \begin{verbatim} class Stack { public: Stack(); virtual ~Stack(); // deallocate the stack virtual void Push(int value) = 0; // Push an integer, checking for overflow. virtual bool Full() = 0; // Is the stack is full? }; // For g++, need these even though no data to initialize. Stack::Stack {} Stack::~Stack() {} \end{verbatim} The {\tt Stack} definition is called a {\em base class} or sometimes a {\em superclass}. We can then define two different {\em derived classes}, sometimes called {\em subclasses} which inherit behavior from the base class. (Of course, inheritance is recursive -- a derived class can in turn be a base class for yet another derived class, and so on.) Note that I have prepended the functions in the base class is prepended with the keyword {\tt virtual}, to signify that they can be redefined by each of the two derived classes. The virtual functions are initialized to zero, to tell the compiler that those functions must be defined by the derived classes. Here's how we could declare the array-based and list-based implementations of {\tt Stack}. The syntax {\tt : public Stack} signifies that both {\tt ArrayStack} and {\tt ListStack} are kinds of {\tt Stacks}, and share the same behavior as the base class. \begin{verbatim} class ArrayStack : public Stack { // the same as in Section 2 public: ArrayStack(int sz); // Constructor: initialize variables, allocate space. ~ArrayStack(); // Destructor: deallocate space allocated above. void Push(int value); // Push an integer, checking for overflow. bool Full(); // Returns TRUE if the stack is full, FALSE otherwise. private: int size; // The maximum capacity of the stack. int top; // Index of the lowest unused position. int *stack; // A pointer to an array that holds the contents. }; class ListStack : public Stack { public: ListStack(); ~ListStack(); void Push(int value); bool Full(); private: List *list; // list of items pushed on the stack }; ListStack::ListStack() { list = new List; } ListStack::~ListStack() { delete list; } \end{verbatim} \newpage \begin{verbatim} void ListStack::Push(int value) { list->Prepend(value); } bool ListStack::Full() { return FALSE; // this stack never overflows! } \end{verbatim} The neat concept here is that I can assign pointers to instances of {\tt ListStack} or {\tt ArrayStack} to a variable of type {\tt Stack}, and then use them as if they were of the base type. \begin{verbatim} Stack *s1 = new ListStack; Stack *s2 = new ArrayStack(17); if (!stack->Full()) s1->Push(5); if (!s2->Full()) s2->Push(6); delete s1; delete s2; \end{verbatim} The compiler automatically invokes {\tt ListStack} operations for {\tt s1}, and {\tt ArrayStack} operations for {\tt s2}; this is done by creating a procedure table for each object, where derived objects override the default entries in the table defined by the base class. To the code above, it invokes the operations {\tt Full}, {\tt Push}, and {\tt delete} by indirection through the procedure table, so that the code doesn't need to know which kind of object it is. In this example, since I never create an instance of the abstract class {\tt Stack}, I do not need to {\em implement} its functions. This might seem a bit strange, but remember that the derived classes are the various implementations of Stack, and Stack serves only to reflect the shared behavior between the different implementations. Also note that the destructor for {\tt Stack} is a virtual function but the constructor is not. Clearly, when I create an object, I have to know which kind of object it is, whether {\tt ArrayStack} or {\tt ListStack}. The compiler makes sure that no one creates an instance of the abstract {\tt Stack} by mistake -- you cannot instantiate any class whose virtual functions are not completely defined (in other words, if any of its functions are set to zero in the class definition). But when I deallocate an object, I may no longer know its exact type. In the above code, I want to call the destructor for the derived object, even though the code only knows that I am deleting an object of class {\tt Stack}. If the destructor were not virtual, then the compiler would invoke {\tt Stack}'s destructor, which is not at all what I want. This is an easy mistake to make (I made it in the first draft of this article!) -- if you don't define a destructor for the abstract class, the compiler will define one for you implicitly (and by the way, it won't be virtual, since you have a {\em really} unhelpful compiler). The result for the above code would be a memory leak, and who knows how you would figure that out! \subsubsection{Shared Implementation} What about sharing code, the other reason for inheritance? In C++, it is possible to use member functions of a base class in its derived class. (You can also share data between a base class and derived classes, but this is a bad idea for reasons I'll discuss later.) Suppose that I wanted to add a new member function, {\tt NumberPushed()}, to both implementations of {\tt Stack}. The {\tt ArrayStack} class already keeps count of the number of items on the stack, so I could duplicate that code in {\tt ListStack}. Ideally, I'd like to be able to use the same code in both places. With inheritance, we can move the counter into the {\tt Stack} class, and then invoke the base class operations from the derived class to update the counter. \begin{verbatim} class Stack { public: virtual ~Stack(); // deallocate data virtual void Push(int value); // Push an integer, checking for overflow. virtual bool Full() = 0; // return TRUE if full int NumPushed(); // how many are currently on the stack? protected: Stack(); // initialize data private: int numPushed; }; Stack::Stack() { numPushed = 0; } void Stack::Push(int value) { numPushed++; } int Stack::NumPushed() { return numPushed; } \end{verbatim} We can then modify both {\tt ArrayStack} and {\tt ListStack} to make use the new behavior of {\tt Stack}. I'll only list one of them here: \begin{verbatim} class ArrayStack : public Stack { public: ArrayStack(int sz); ~ArrayStack(); void Push(int value); bool Full(); private: int size; // The maximum capacity of the stack. int *stack; // A pointer to an array that holds the contents. }; ArrayStack::ArrayStack(int sz) : Stack() { size = sz; stack = new int[size]; // Let's get an array of integers. } void ArrayStack::Push(int value) { ASSERT(!Full()); stack[NumPushed()] = value; Stack::Push(); // invoke base class to increment numPushed } \end{verbatim} There are a few things to note: \begin{enumerate} \item The constructor for {\tt ArrayStack} needs to invoke the constructor for {\tt Stack}, in order to initialize {\tt numPushed}. It does that by adding {\tt : Stack()} to the first line in the constructor: \begin{verbatim} ArrayStack::ArrayStack(int sz) : Stack() \end{verbatim} The same thing applies to destructors. There are special rules for which get called first -- the constructor/destructor for the base class or the constructor/destructor for the derived class. All I should say is, it's a bad idea to rely on whatever the rule is -- more generally, it is a bad idea to write code which requires the reader to consult a manual to tell whether or not the code works! \item I introduced a new keyword, {\tt protected}, in the new definition of {\tt Stack}. For a base class, {\tt protected} signifies that those member data and functions are accessible to classes derived (recursively) from this class, but inaccessible to other classes. In other words, protected data is {\tt public} to derived classes, and {\tt private} to everyone else. For example, we need {\tt Stack}'s constructor to be callable by {\tt ArrayStack} and {\tt ListStack}, but we don't want anyone else to create instances of {\tt Stack}. Hence, we make {\tt Stack}'s constructor a protected function. In this case, this is not strictly necessary since the compiler will complain if anyone tries to create an instance of {\tt Stack} because {\tt Stack} still has an undefined virtual functions, {\tt Push}. By defining {\tt Stack::Stack} as {\tt protected}, you are safe even if someone comes along later and defines {\tt Stack::Push}. Note however that I made {\tt Stack}'s data member {\tt private}, not {\tt protected}. Although there is some debate on this point, as a rule of thumb you should never allow one class to see directly access the data in another, even among classes related by inheritance. Otherwise, if you ever change the implementation of the base class, you will have to examine and change all the implementations of the derived classes, violating modularity. \item The interface for a derived class automatically includes all functions defined for its base class, without having to explicitly list them in the derived class. Although we didn't define {\tt NumPushed()} in {\tt ArrayStack}, we can still call it for those objects: \begin{verbatim} ArrayStack *s = new ArrayStack(17); ASSERT(s->NumPushed() == 0); // should be initialized to 0 \end{verbatim} \item Conversely, even though we have defined a routine {\tt Stack::Push()}, because it is declared as {\tt virtual}, if we invoke {\tt Push()} on an {\tt ArrayStack} object, we will get {\tt ArrayStack}'s version of {\tt Push}: \begin{verbatim} Stack *s = new ArrayStack(17); if (!s->Full()) // ArrayStack::Full s->Push(5); // ArrayStack::Push \end{verbatim} \item {\tt Stack::NumPushed()} is not {\tt virtual}. That means that it cannot be re-defined by {\tt Stack}'s derived classes. Some people believe that you should mark {\em all} functions in a base class as {\tt virtual}; that way, if you later want to implement a derived class that redefines a function, you don't have to modify the base class to do so. \item Member functions in a derived class can explicitly invoke public or protected functions in the base class, by the full name of the function, {\tt Base::Function()}, as in: \begin{verbatim} void ArrayStack::Push(int value) { ... Stack::Push(); // invoke base class to increment numPushed } \end{verbatim} Of course, if we just called {\tt Push()} here (without prepending {\tt Stack::}, the compiler would think we were referring to {\tt ArrayStack}'s {\tt Push()}, and so that would recurse, which is not exactly what we had in mind here. \end{enumerate} Whew! Inheritance in C++ involves lots and lots of details. But it's real downside is that it tends to spread implementation details across multiple files -- if you have a deep inheritance tree, it can take some serious digging to figure out what code actually executes when a member function is invoked. So the question to ask yourself before using inheritance is: what's your goal? Is it to write your programs with the fewest number of characters possible? If so, inheritance is really useful, but so is changing all of your function and variable names to be one letter long -- "a", "b", "c" -- and once you run out of lower case ones, start using upper case, then two character variable names: "XX XY XZ Ya ..." (I'm joking here.) Needless to say, it is really easy to write unreadable code using inheritance. So when is it a good idea to use inheritance and when should it be avoided? My rule of thumb is to only use it for representing {\em shared behavior} between objects, and to never use it for representing {\em shared implementation}. With C++, you can use inheritance for both concepts, but only the first will lead to truly simpler implementations. To illustrate the difference between shared behavior and shared implementation, suppose you had a whole bunch of different kinds of objects that you needed to put on lists. For example, almost everything in an operating system goes on a list of some sort: buffers, threads, users, terminals, etc. A very common approach to this problem (particularly among people new to object-oriented programming) is to make every object inherit from a single base class {\em Object}, which contains the forward and backward pointers for the list. But what if some object needs to go on multiple lists? The whole scheme breaks down, and it's because we tried to use inheritance to share implementation (the code for the forward and backward pointers) instead of to share behavior. A much cleaner (although slightly slower) approach would be to define a list implementation that allocated forward/backward pointers for each object that gets put on a list. In sum, if two classes share at least some of the same member function signatures -- that is, the same behavior, {\em and} if there's code that only relies on the shared behavior, then there {\em may} be a benefit to using inheritance. In Nachos, locks don't inherit from semaphores, even though locks are implemented using semaphores. The operations on semaphores and locks are different. Instead, inheritance is only used for various kinds of lists (sorted, keyed, etc.), and for different implementations of the physical disk abstraction, to reflect whether the disk has a track buffer, etc. A disk is used the same way whether or not it has a track buffer; the only difference is in its performance characteristics. \subsection{Templates} Templates are another useful but dangerous concept in C++. With templates, you can parameterize a class definition with a {\em type}, to allow you to write generic type-independent code. For example, our {\tt Stack} implementation above only worked for pushing and popping {\em integers}; what if we wanted a stack of characters, or floats, or pointers, or some arbitrary data structure? In C++, this is pretty easy to do using templates: \begin{verbatim} template <class T> class Stack { public: Stack(int sz); // Constructor: initialize variables, allocate space. ~Stack(); // Destructor: deallocate space allocated above. void Push(T value); // Push an integer, checking for overflow. bool Full(); // Returns TRUE if the stack is full, FALSE otherwise. private: int size; // The maximum capacity of the stack. int top; // Index of the lowest unused position. T *stack; // A pointer to an array that holds the contents. }; \end{verbatim} To define a template, we prepend the keyword {\tt template} to the class definition, and we put the parameterized type for the template in angle brackets. If we need to parameterize the implementation with two or more types, it works just like an argument list: {\tt template <class T, class S>}. We can use the type parameters elsewhere in the definition, just like they were normal types. When we provide the implementation for each of the member functions in the class, we also have to declare them as templates, and again, once we do that, we can use the type parameters just like normal types: \begin{verbatim} // template version of Stack::Stack template <class T> Stack<T>::Stack(int sz) { size = sz; top = 0; stack = new T[size]; // Let's get an array of type T } // template version of Stack::Push template <class T> void Stack<T>::Push(T value) { ASSERT(!Full()); stack[top++] = value; } \end{verbatim} Creating an object of a template class is similar to creating a normal object: \begin{verbatim} void test() { Stack<int> s1(17); Stack<char> *s2 = new Stack<char>(23); s1.Push(5); s2->Push('z'); delete s2; } \end{verbatim} Everything operates as if we defined two classes, one called {\tt Stack<int>} -- a stack of integers, and one called {\tt Stack<char>} -- a stack of characters. {\tt s1} behaves just like an instance of the first; {\tt s2} behaves just like an instance of the second. In fact, that is exactly how templates are typically implemented -- you get a complete {\em copy} of the code for the template for each different instantiated type. In the above example, we'd get one copy of the code for {\tt ints} and one copy for {\tt chars}. So what's wrong with templates? You've all been taught to make your code modular so that it can be re-usable, so {\em everything} should be a template, right? Wrong. The principal problem with templates is that they can be {\em very} difficult to debug -- templates are easy to use if they work, but finding a bug in them can be difficult. In part this is because current generation C++ debuggers don't really understand templates very well. Nevertheless, it is easier to debug a template than two nearly identical implementations that differ only in their types. So the best advice is -- don't make a class into a template unless there really is a near term use for the template. And if you do need to implement a template, implement and debug a non-template version first. Once that is working, it won't be hard to convert it to a template. Then all you have to worry about code explosion -- e.g., your program's object code is now megabytes because of the 15 copies of the hash table/list/... routines, one for each kind of thing you want to put in a hash table/list/... (Remember, you have an unhelpful compiler!) \section{Features To Avoid Like the Plague} Despite the length of this note, there are numerous features in C++ that I haven't explained. I'm sure each feature has its advocates, but despite programming in C and C++ for over 15 years, I haven't found a compelling reason to use them in any code that I've written (outside of a programming language class!) Indeed, there is a compelling reason to avoid using these features -- they are easy to misuse, resulting in programs that are harder to read and understand instead of easier to understand. In most cases, the features are also redundant -- there are other ways of accomplishing the same end. Why have two ways of doing the same thing? Why not stick with the simpler one? I do not use any of the following features in Nachos. If you use them, {\it caveat hacker}. \begin{enumerate} \item {\bf Multiple inheritance.} It is possible in C++ to define a class as inheriting behavior from multiple classes (for instance, a dog is both an animal and a furry thing). But if programs using single inheritance can be difficult to untangle, programs with multiple inheritance can get really confusing. \item {\bf References.} Reference variables are rather hard to understand in general; they play the same role as pointers, with slightly different syntax (unfortunately, I'm not joking!) Their most common use is to declare some parameters to a function as {\it reference parameters}, as in Pascal. A call-by-reference parameter can be modified by the calling function, without the callee having to pass a pointer. The effect is that parameters look (to the caller) like they are called by value (and therefore can't change), but in fact can be transparently modified by the called function. Obviously, this can be a source of obscure bugs, not to mention that the semantics of references in C++ are in general not obvious. \item {\bf Operator overloading.} C++ lets you redefine the meanings of the operators (such as {\tt +} and \verb+>>+) for class objects. This is dangerous at best ("exactly which implementation of '+' does this refer to?"), and when used in non-intuitive ways, a source of great confusion, made worse by the fact that C++ does implicit type conversion, which can affect which operator is invoked. Unfortunately, C++'s I/O facilities make heavy use of operator overloading and references, so you can't completely escape them, but think twice before you redefine '+' to mean ``concatenate these two strings''. \item {\bf Function overloading.} You can also define different functions in a class with the same name but different argument types. This is also dangerous (since it's easy to slip up and get the unintended version), and we never use it. We will also avoid using default arguments (for the same reason). Note that it can be a good idea to use the same name for functions in different classes, provided they use the same arguments and behave the same way -- a good example of this is that most Nachos objects have a {\tt Print()} method. \item {\bf Standard template library.} An ANSI standard has emerged for a library of routines implementing such things as lists, hash tables, etc., called the standard template library. Using such a library should make programming much simpler if the data structure you need is already provided in the library. Alas, the standard template library pushes the envelope of legal C++, and so virtually no compilers (including g++) can support it today. Not to mention that it uses (big surprise!) references, operator overloading, and function overloading. \item {\bf Exceptions.} There are two ways to return an error from a procedure. One is simple -- just define the procedure to return an error code if it isn't able to do it's job. For example, the standard library routine {\tt malloc} returns NULL if there is no available memory. However, lots of programmers are lazy and don't check error codes. So what's the solution? You might think it would be to get programmers who aren't lazy, but no, the C++ solution is to add a programming language construct! A procedure can return an error by ``raising an exception'' which effectively causes a {\tt goto} back up the execution stack to the last place the programmer put an exception handler. You would think this is too bizarre to be true, but unfortunately, I'm not making this up. \end{enumerate} While I'm at it, there are a number of features of C that you also should avoid, because they lead to bugs and make your code less easy to understand. See Maguire's "Writing Solid Code" for a more complete discussion of this issue. All of these features are legal C; what's legal isn't necessarily good. \begin{enumerate} \item Pointer arithmetic. Runaway pointers are a principal source of hard-to-find bugs in C programs, because the symptom of this happening can be mangled data structures in a completely different part of the program. Depending on exactly which objects are allocated on the heap in which order, pointer bugs can appear and disappear, seemingly at random. For example, {\tt printf} sometimes allocates memory on the heap, which can change the addresses returned by all future calls to {\tt new}. Thus, adding a {\tt printf} can change things so that a pointer which used to (by happenstance) mangle a critical data structure (such as the middle of a thread's execution stack), now overwrites memory that may not even be used. The best way to avoid runaway pointers is (no surprise) to be {\em very} careful when using pointers. Instead of iterating through an array with pointer arithmetic, use a separate index variable, and assert that the index is never larger than the size of the array. Optimizing compilers have gotten very good, so that the generated machine code is likely to be the same in either case. Even if you don't use pointer arithmetic, it's still easy (easy is bad in this context!) to have an off-by-one errror that causes your program to step beyond the end of an array. How do you fix this? Define a class to contain the array {\em and its length}; before allowing any access to the array, you can then check whether the access is legal or in error. \item Casts from integers to pointers and back. Another source of runaway pointers is that C and C++ allow you to convert integers to pointers, and back again. Needless to say, using a random integer value as a pointer is likely to result in unpredictable symptoms that will be very hard to track down. In addition, on some 64 bit machines, such as the Alpha, it is no longer the case that the size of an integer is the same as the the size of a pointer. If you cast between pointers and integers, you are also writing highly non-portable code. \item Using bit shift in place of a multiply or divide. This is a clarity issue. If you are doing arithmetic, use arithmetic operators; if you are doing bit manipulation, use bitwise operators. If I am trying to multiply by 8, which is easier to understand, {\tt x << 3} or {\tt x * 8}? In the 70's, when C was being developed, the former would yield more efficient machine code, but today's compilers generate the same code in both cases, so readability should be your primary concern. \item Assignment inside conditional. Many programmers have the attitude that simplicity equals saving as many keystrokes as possible. The result can be to hide bugs that would otherwise be obvious. For example: \begin{verbatim} if (x = y) { ... \end{verbatim} Was the intent really {\tt x == y}? After all, it's pretty easy to mistakenly leave off the extra equals sign. By never using assignment within a conditional, you can tell by code inspection whether you've made a mistake. \item Using {\tt \#define} when you could use {\tt enum}. When a variable can hold one of a small number of values, the original C practice was to use {\tt \#define} to set up symbolic names for each of the values. {\tt enum} does this in a type-safe way -- it allows the compiler to verify that the variable is only assigned one of the enumerated values, and none other. Again, the advantage is to eliminate a class of errors from your program, making it quicker to debug. \end{enumerate} \newpage \section{Style Guidelines} Even if you follow the approach I've outlined above, it is still as easy to write unreadable and undebuggable code in C++ as it is in C, and perhaps easier, given the more powerful features the language provides. For the Nachos project, and in general, we suggest you adhere to the following guidelines (and tell us if you catch us breaking them): \begin{enumerate} \item Words in a name are separated SmallTalk-style (i.e., capital letters at the start of each new word). All class names and member function names begin with a capital letter, except for member functions of the form {\tt getSomething()} and {\tt setSomething()}, where {\tt Something} is a data element of the class (i.e., accessor functions). Note that you would want to provide such functions only when the data should be visible to the outside world, but you want to force all accesses to go through one function. This is often a good idea, since you might at some later time decide to compute the data instead of storing it, for example. \item All global functions should be capitalized, except for {\tt main} and library functions, which are kept lower-case for historical reasons. \item Minimize the use of global variables. If you find yourself using a lot of them, try and group some together in a class in a natural way or pass them as arguments to the functions that need them if you can. \item Minimize the use of global functions (as opposed to member functions). If you write a function that operates on some object, consider making it a member function of that object. \item For every class or set of related classes, create a separate {\tt .h} file and {\tt .cc} file. The {\tt .h} file acts as the {\it interface} to the class, and the {\tt .cc} file acts as the {\it implementation} (a given {\tt .cc} file should {\tt include} it's respective {\tt .h} file). If using a particular {\tt .h} file requires another {\tt .h} file to be included (e.g., {\tt synch.h} needs class definitions from {\tt thread.h}) you should include the dependency in the {\tt .h} file, so that the user of your class doesn't have to track down all the dependencies himself. To protect against multiple inclusion, bracket each {\tt .h} file with something like: \begin{verbatim} #ifndef STACK_H #define STACK_H class Stack { ... }; #endif \end{verbatim} Sometimes this will not be enough, and you will have a circular dependency. For example, you might have a {\tt .h} file that uses a definition from one {\tt .h} file, but also defines something needed by that {\tt .h} file. In this case, you will have to do something ad-hoc. One thing to realize is that you don't always have to completely define a class before it is used. If you only use a pointer to class {\tt Stack} and do not access any member functions or data from the class, you can write, in lieu of including {\tt stack.h}: \begin{verbatim} class Stack; \end{verbatim} This will tell the compiler all it needs to know to deal with the pointer. In a few cases this won't work, and you will have to move stuff around or alter your definitions. \item Use {\tt ASSERT} statements liberally to check that your program is behaving properly. An assertion is a condition that if FALSE signifies that there is a bug in the program; {\tt ASSERT} tests an expression and aborts if the condition is false. We used {\tt ASSERT} above in {\tt Stack::Push()} to check that the stack wasn't full. The idea is to catch errors as early as possible, when they are easier to locate, instead of waiting until there is a user-visible symptom of the error (such as a segmentation fault, after memory has been trashed by a rogue pointer). Assertions are particularly useful at the beginnings and ends of procedures, to check that the procedure was called with the right arguments, and that the procedure did what it is supposed to. For example, at the beginning of List::Insert, you could assert that the item being inserted isn't already on the list, and at the end of the procedure, you could assert that the item is now on the list. If speed is a concern, ASSERTs can be defined to make the check in the debug version of your program, and to be a no-op in the production version. But many people run with ASSERTs enabled even in production. \item Write a module test for every module in your program. Many programmers have the notion that testing code means running the entire program on some sample input; if it doesn't crash, that means it's working, right? Wrong. You have no way of knowing how much code was exercised for the test. Let me urge you to be methodical about testing. Before you put a new module into a bigger system, make sure the module works as advertised by testing it standalone. If you do this for every module, then when you put the modules together, instead of {\em hoping} that everything will work, you will {\em know} it will work. Perhaps more importantly, module tests provide an opportunity to find as many bugs as possible in a localized context. Which is easier: finding a bug in a 100 line program, or in a 10000 line program? \end{enumerate} \section{Compiling and Debugging} The Makefiles we will give you works only with the GNU version of make, called ``gmake''. You may want to put ``alias make gmake'' in your .cshrc file. You should use {\bf gdb} to debug your program rather than {\bf dbx}. Dbx doesn't know how to decipher C++ names, so you will see function names like \verb+Run__9SchedulerP6Thread+. On the other hand, in GDB (but not DBX) when you do a stack backtrace when in a forked thread (in homework 1), after printing out the correct frames at the top of the stack, the debugger will sometimes go into a loop printing the lower-most frame ({\tt ThreadRoot}), and you have to type control-C when it says ``more?''. If you understand assembly language and can fix this, please let me know. \section{Example: A Stack of Integers} We've provided the complete, working code for the stack example. You should read through it and play around with it to make sure you understand the features of C++ described in this paper. To compile the simple stack test, type {\tt make all} -- this will compile the simple stack test ({\tt stack.cc}), the inherited stack test ({\tt inheritstack.cc}), and the template version of stacks ({\tt templatestack.cc}). \section{Epilogue} I've argued in this note that you should avoid using certain C++ and C features. But you're probably thinking I must be leaving something out -- if someone put the feature in the language, there must be a good reason, right? I believe that every programmer should strive to write code whose behavior would be immediately obvious to a reader; if you find yourself writing code that would require someone reading the code to thumb through a manual in order to understand it, you are almost certainly being way too subtle. There's probably a much simpler and more obvious way to accomplish the same end. Maybe the code will be a little longer that way, but in the real world, it's whether the code works and how simple it is for someone else to modify, that matters a whole lot more than how many characters you had to type. A final thought to remember: \begin{quote} ``There are two ways of constructing a software design: one way is to make it so simple that there are {\em obviously} no deficiencies and the other way is to make it so complicated that there are no {\em obvious} deficiencies.'' \\ \hbox{} \hfill C. A. R. Hoare, ``The Emperor's Old Clothes'', CACM Feb. 1981 \end{quote} \section{Further Reading} \begin{itemize} \item[] James Coplien, ``Advanced C++'', Addison-Wesley. This book is only for experts, but it has some good ideas in it, so keep it in mind once you've been programming in C++ for a few years. \item[] James Gosling. ``The Java Language.'' Online at ``http://java.sun.com/'' Java is a safe subset of C++. It's main application is the safe extension of Web browsers by allowing you to download Java code as part of clicking on a link to interpret and display the document. Safety is key here, since after all, you don't want to click on a Web link and have it download code that will crash your browser. Java was defined independently of this document, but interestingly, it enforces a very similar style (for example, no multiple inheritance and no operator overloading). \item[] C.A.R. Hoare, ``The Emperor's Old Clothes.'' {\em Communications of the ACM}, Vol. 24, No. 2, February 1981, pp. 75-83. Tony Hoare's Turing Award lecture. How do you build software that really works? Attitude is everything -- you need a healthy respect for how hard it is to build working software. It might seem that addding this whiz-bang feature is only ``a small matter of code'', but that's the path to late, buggy products that don't work. \item[] Brian Kernighan and Dennis Ritchie, ``The C Programming Language'', Prentice-Hall. The original C book -- a very easy read. But the language has evolved since it was first designed, and this book doesn't describe all of C's newest features. But still the best place for a beginner to start, even when learning C++. \item[] Steve Maguire, ``Writing Solid Code'', Microsoft Press. How to write bug-free software; I think this should be required reading for all software engineers. This really {\em will} change your life -- if you don't follow the recommendations in this book, you'll probably never write code that completely works, and you'll spend your entire life struggling with hard to find bugs. There is a better way! Contrary to the programming language types, this doesn't involve proving the correctness of your programs, whatever that means. Instead, Maguire has a set of practical engineering solutions to writing solid code. \item[] Steve Maguire, ``Debugging the Development Process'', Microsoft Press. Maguire's follow up book on how to lead an effective team, and by the way, how to be an effective engineer. Maguire's background is that he is a turnaround artist for Microsoft -- he gets assigned to floundering teams, and figures out how to make them effective. After you've pulled a few all-nighters to get that last bug out of your course project, you're probably wondering why in heck you're studying computer science anyway. This book will explain how to write programs that work, {\em and} still have a life! \item[] Scott Meyers, ``Effective C++''. This book describes how 50 easy ways to make mistakes C++; if you avoid these, you will be a lot more likely to write C++ code that works. \item[] Bjarne Stroustrup, ``The C++ Programming Language'', Addison-Wesley. This should be the definite reference manual, but it isn't. You probably thought I was joking when I said the C++ language was continually evolving. I bought the second edition of this book three years ago, and it is already out of date. Fortunately, it's still OK for the subset of C++ that I use. \end{itemize} \end{document}

project4/nachos/c++example/stack.h

// stack.h // Data structures for a "stack" -- a Last-In-First-Out list of integers. // // Copyright (c) 1992,1993,1995 The Regents of the University of California. // All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions. #ifndef STACK_H // to prevent recursive includes #define STACK_H #include "copyright.h" // The following defines the Stack class. The functions are // implemented in the file stack.cc. // // The constructor (initializer) for the Stack is passed the number // of elements (integers) in the stack. class Stack { public: Stack(int sz); // Constructor: initialize variables, allocate space. ~Stack(); // Destructor: deallocate space allocated above. void Push(int value); // Push an integer on the stack, checking for overflow int Pop(); // Pop an integer off the stack, checking for underflow. bool Full(); // Returns TRUE if the stack is full, FALSE otherwise. bool Empty(); // Returns TRUE if the stack is empty, FALSE otherwise. void SelfTest(); // Test whether the implementation works. private: int size; // The maximum capacity of the stack. int top; // Index of the next position to be used. int *stack; // A pointer to an array that holds the contents. }; #endif // STACK_H

project4/nachos/c++example/templatestack.cc

project4/nachos/c++example/templatestack.cc

// templatestack.cc
//  Routines to implement a LIFO stack of arbitrary things.
//  
//  The stack is represented as an array; we return an error
//  if the caller tries to push more things onto the stack than we have
//  room for.
//
// Copyright (c) 1992,1993,1995 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.


extern   "C"   {
#include   < assert . h >

#define  ASSERT ( expression )   assert ( expression )
}

#include   < iostream . h >
#include   "copyright.h"
#include   "templatestack.h"

//----------------------------------------------------------------------
// Stack<T>::Stack
//  The constructor for the Stack class.  Note that it doesn't have a
//  return type.
//
//  "sz" -- maximum number of elements on the Stack at any time
//----------------------------------------------------------------------

template   < class  T >
Stack < T >:: Stack ( int  sz )   {

    ASSERT ( sz  >=   1 );

     // Initialize the data members of the stack object.
    size  =  sz ;
    top  =   0 ;
    stack  =   new  T [ size ];     // allocate an array of integers.
}

//----------------------------------------------------------------------
// Stack<T>::~Stack
//  The destructor for the Stack class.  Just get rid of the array we
//  allocated in the constructor.
//----------------------------------------------------------------------

template   < class  T >
Stack < T >::~ Stack ()   {

     delete   []  stack ;
}

//----------------------------------------------------------------------
// Stack<T>::Push
//  Put a T on the top of the stack; error on overflow.
//
//  "value" -- the value to put on the stack
//----------------------------------------------------------------------


template   < class  T >
void
Stack < T >:: Push ( value )   {
    ASSERT ( ! Full ());
    
    stack [ top ++ ]   =   value ;
}

//----------------------------------------------------------------------
// Stack<T>::Pop
//  Remove a T from the top of the stack, returning its value.
//  Error if the stack is empty.
//----------------------------------------------------------------------

template   < class  T >
T
Stack < T >:: Pop ()   {

    ASSERT ( ! Empty ());
    
     return   ( stack [ -- top ]);
}

//----------------------------------------------------------------------
// Stack<T>::Full
//  Return TRUE if the stack has no more room.
//----------------------------------------------------------------------

template   < class  T >
bool
Stack < T >:: Full ()   {
     return   ( top  ==  size );
}

//----------------------------------------------------------------------
// Stack<T>::Empty
//  Return TRUE if the stack has nothing on it.
//----------------------------------------------------------------------

template   < class  T >
bool
Stack < T >:: Empty ()   {
     return   ( top  ==   0 );
}

//----------------------------------------------------------------------
// Stack<T>::SelfTest
//  Test our stack implementation by pushing 10 T's onto the 
//  stack, and then print them as it pops them off.
//----------------------------------------------------------------------

template   < class  T >
void
Stack < T >:: SelfTest ( T start )   {
    T count  =  start ;
    
     // Put a bunch of stuff in the stack...
     while   ( ! Full ())   {
    cout  <<   "pushing "   <<  count  <<   "\n" ;
     Push ( count ++ );
     }
    
     // ... and take it out again.
     while   ( ! Empty ())   {
    cout  <<   "popping "   <<   Pop ()   <<   "\n" ;
     }
}

//----------------------------------------------------------------------
// main
//  Run the test code for the stack implementation.
//----------------------------------------------------------------------

int
main ()   {
     Stack < int >   * s1  =   new   Stack < int > ( 10 );    
     Stack < char >   * s2  =   new   Stack < char > ( 10 );    

    cout  <<   "Testing Stack<int>\n" ;
    s1 -> SelfTest ( 17 );

    cout  <<   "Testing Stack<char>\n" ;
    s2 -> SelfTest ( 'a' );

     delete  s1 ;           // always delete what you allocate
     delete  s2 ;           // always delete what you allocate
     return   0 ;
}

project4/nachos/c++example/list.cc

project4/nachos/c++example/list.cc

// list.cc 
//      Routines to manage a singly-linked list of integers. 
//
//  A "ListElement" is allocated for each item to be put on the
//  list; it is de-allocated when the item is removed. This means
//      we don't need to keep a "next" pointer in every object we
//      want to put on a list.
// 
// Copyright (c) 1992,1993,1995 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.


extern   "C"   {
#include   < assert . h >

#define  ASSERT ( expression )   assert ( expression )
}

#include   "copyright.h"
#include   "list.h"

const   int  NULL  =   0 ;


// The following class defines a "list element" -- which is
// used to keep track of one item on a list.  It is equivalent to a
// LISP cell, with a "car" ("next") pointing to the next element on the list,
// and a "cdr" ("item") containing the item on the list.
//
// Class defined in list.cc, because only the List class can be allocating
// and accessing ListElements.

class   ListElement   {
    public :
      ListElement ( int   value )   {  item  =   value ;  next  =  NULL ;};
                         // constructor for list element

      ListElement   * next ;       // next element on list, 
                 // NULL if this is the last
      int  item ;                    // value of this element
};



//----------------------------------------------------------------------
// List::List
//  Initialize a list, empty to start with.
//  Elements can now be added to the list.
//----------------------------------------------------------------------

List :: List ()   {  

    first  =  last  =  NULL ;  
}


//----------------------------------------------------------------------
// List::~List
//  Prepare a list for deallocation.  If the list still contains any 
//  ListElements, de-allocate them.
//----------------------------------------------------------------------

List ::~ List ()   {  
   
     while   ( ! Empty ())
     ( void )   Remove ();       // delete all the list elements
}


//----------------------------------------------------------------------
// List::Prepend
//      Put an integer on the front of the list.
//      
//  Allocate a ListElement to keep track of the integer.
//      If the list is empty, then this will be the only element.
//  Otherwise, put it at the beginning.
//
//  "value" is the integer to be put on the list.
//----------------------------------------------------------------------

void
List :: Prepend ( int   value )   {
     ListElement   * element  =   new   ListElement ( value );

     if   ( Empty ())   {        // list is empty
    first  =  element ;
    last  =  element ;
     }   else   {              // else put it before first
    element -> next  =  first ;
    first  =  element ;
     }
}

//----------------------------------------------------------------------
// List::Remove
//      Remove the first integer from the front of the list.
//  Error if nothing on the list.
// 
// Returns:
//  The removed integer.
//----------------------------------------------------------------------

int
List :: Remove ()   {
     ListElement   * element  =  first ;
     int   value ;

    ASSERT ( ! Empty ());

    element  =  first ;
     value   =  first -> item ;

     if   ( first  ==  last )   {      // list had one item, now has none 
        first  =  NULL ;
    last  =  NULL ;
     }   else   {
        first  =  element -> next ;
     }

     delete  element ;       // deallocate list element -- no longer needed
     return   value ;
}

//----------------------------------------------------------------------
// List::Empty
//      Returns TRUE if the list is empty (has no items).
//----------------------------------------------------------------------

bool
List :: Empty ()   {  
     return   ( first  ==  NULL );
}