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:
191
code/lib/bitmap.cc
Normal file
191
code/lib/bitmap.cc
Normal 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
59
code/lib/bitmap.h
Normal 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
24
code/lib/copyright.h
Normal 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
45
code/lib/debug.cc
Normal 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
96
code/lib/debug.h
Normal 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
360
code/lib/hash.cc
Normal 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
123
code/lib/hash.h
Normal 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
85
code/lib/libtest.cc
Normal 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
15
code/lib/libtest.h
Normal 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
408
code/lib/list.cc
Normal 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
142
code/lib/list.h
Normal 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
571
code/lib/sysdep.cc
Normal 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
75
code/lib/sysdep.h
Normal 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
38
code/lib/utility.h
Normal 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
|
||||
Reference in New Issue
Block a user