init: init nachos hw01, should pass jenkins os_group_20_hw job but fail on os_group_20_ta job

This commit is contained in:
TA
2024-09-19 18:59:13 +08:00
commit 6ad2fa368f
267 changed files with 71977 additions and 0 deletions

191
code/lib/bitmap.cc Normal file
View File

@@ -0,0 +1,191 @@
// 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 (i = 0; i < numWords; i++) {
map[i] = 0; // initialize map to keep Purify happy
}
for (i = 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 (i = 0; i < numBits; i++) {
Mark(i);
}
ASSERT(FindAndSet() == -1); // bitmap should be full!
for (i = 0; i < numBits; i++) {
Clear(i);
}
}

59
code/lib/bitmap.h Normal file
View File

@@ -0,0 +1,59 @@
// 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

24
code/lib/copyright.h Normal file
View File

@@ -0,0 +1,24 @@
/*
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

45
code/lib/debug.cc Normal file
View File

@@ -0,0 +1,45 @@
// 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;
}
}

96
code/lib/debug.h Normal file
View File

@@ -0,0 +1,96 @@
// 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

360
code/lib/hash.cc Normal file
View File

@@ -0,0 +1,360 @@
// 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(i == 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(T *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 (i = 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 (i = 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]);
}
}
}

123
code/lib/hash.h Normal file
View File

@@ -0,0 +1,123 @@
// 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

85
code/lib/libtest.cc Normal file
View File

@@ -0,0 +1,85 @@
// 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 (x < y) return -1;
else if (x == 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;
}

15
code/lib/libtest.h Normal file
View File

@@ -0,0 +1,15 @@
// 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

408
code/lib/list.cc Normal file
View File

@@ -0,0 +1,408 @@
// 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(T *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 (i = 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 (i = 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(T *p, int numEntries)
{
int i;
T *q = new T[numEntries];
List<T>::SelfTest(p, numEntries);
for (i = 0; i < numEntries; i++)
{
Insert(p[i]);
ASSERT(this->IsInList(p[i]));
}
SanityCheck();
// should be able to get out everything we put in
for (i = 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 (i = 0; i < (numEntries - 1); i++)
{
ASSERT(compare(q[i], q[i + 1]) <= 0);
}
SanityCheck();
delete q;
}

142
code/lib/list.h Normal file
View File

@@ -0,0 +1,142 @@
// 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

571
code/lib/sysdep.cc Normal file
View File

@@ -0,0 +1,571 @@
// 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.
}

75
code/lib/sysdep.h Normal file
View File

@@ -0,0 +1,75 @@
// 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

38
code/lib/utility.h Normal file
View File

@@ -0,0 +1,38 @@
// 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