Initial version

This commit is contained in:
Yorick Barbanneau 2021-10-11 22:27:00 +02:00
commit 6f405265a5
102 changed files with 14486 additions and 0 deletions

23
code/network/Makefile Normal file
View file

@ -0,0 +1,23 @@
# NOTE: this is a GNU Makefile. You must use "gmake" rather than "make".
#
# Makefile for the network assignment
# Defines set up assuming this assignment is done last
# If not, use the "bare bones" defines below.
#
# Copyright (c) 1992 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.
DEFINES = -DUSER_PROGRAM -DVM -DFILESYS_NEEDED -DFILESYS -DNETWORK
INCPATH = -I../network -I../bin -I../filesys -I../vm -I../userprog -I../threads -I../machine
C_OFILES = $(THREAD_O) $(USERPROG_O) $(VM_O) $(FILESYS_O) $(NETWORK_O)
# bare bones version
# DEFINES =-DTHREADS -DNETWORK
# INCPATH = -I../network -I../threads -I../machine
# C_OFILES = $(THREAD_O) $(NETWORK_O)
include ../Makefile.common
include ../Makefile.dep

59
code/network/README Normal file
View file

@ -0,0 +1,59 @@
From: cs162@po.EECS.Berkeley.EDU (Class Master)
Subject: Answer to problems running assignment 5
Some people have been having problems running assignment 5.
Unfortunately, the way the network gets initialized, if things
don't get done in exactly the right order, you can get an error
in sending the first packet to the socket.
I have modified synch.h and synch.cc in code/, and re-compiled
the contents of code/network. I was then able to run the
test case successfully, at least one out of two times. See below.
So, be careful out there!
tom
-----------
po.EECS.Berkeley.EDU:network>!19
./nachos -m 0 -o 1 > & log & ; ./nachos -m 1 -o 0 > & log2 &
[1] 10882
[2] 10883
po.EECS.Berkeley.EDU:network>
[2] Illegal instruction ./nachos -m 1 -o 0 >& log2 (core dumped)
[1] Illegal instruction ./nachos -m 0 -o 1 >& log (core dumped)
po.EECS.Berkeley.EDU:network>rm -f log* SOCKET*
po.EECS.Berkeley.EDU:network>!19
./nachos -m 0 -o 1 > & log & ; ./nachos -m 1 -o 0 > & log2 &
[1] 10895
[2] 10896
po.EECS.Berkeley.EDU:network>
[1] Done ./nachos -m 0 -o 1 >& log
[2] Done ./nachos -m 1 -o 0 >& log2
more log
Got "Hello there!" from 1, box 1
Got "Got it!" from 1, box 1
Machine halting!
Ticks: total 57080, idle 56810, system 270, user 0
Disk I/O: reads 2, writes 0
Console I/O: reads 0, writes 0
Paging: faults 0
Network I/O: packets received 2, sent 2
Cleaning up...
po.EECS.Berkeley.EDU:network>more log2
Got "Hello there!" from 0, box 1
Got "Got it!" from 0, box 1
Machine halting!
Ticks: total 58530, idle 58260, system 270, user 0
Disk I/O: reads 2, writes 0
Console I/O: reads 0, writes 0
Paging: faults 0
Network I/O: packets received 2, sent 2
Cleaning up...

72
code/network/nettest.cc Normal file
View file

@ -0,0 +1,72 @@
// nettest.cc
// Test out message delivery between two "Nachos" machines,
// using the Post Office to coordinate delivery.
//
// Two caveats:
// 1. Two copies of Nachos must be running, with machine ID's 0 and 1:
// ./nachos -m 0 -o 1 &
// ./nachos -m 1 -o 0 &
//
// 2. You need an implementation of condition variables,
// which is *not* provided as part of the baseline threads
// implementation. The Post Office won't work without
// a correct implementation of condition variables.
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#include "copyright.h"
#include "system.h"
#include "network.h"
#include "post.h"
#include "interrupt.h"
// Test out message delivery, by doing the following:
// 1. send a message to the machine with ID "farAddr", at mail box #0
// 2. wait for the other machine's message to arrive (in our mailbox #0)
// 3. send an acknowledgment for the other machine's message
// 4. wait for an acknowledgement from the other machine to our
// original message
void
MailTest(int farAddr)
{
PacketHeader outPktHdr, inPktHdr;
MailHeader outMailHdr, inMailHdr;
const char *data = "Hello there!";
const char *ack = "Got it!";
char buffer[MaxMailSize];
// construct packet, mail header for original message
// To: destination machine, mailbox 0
// From: our machine, reply to: mailbox 1
outPktHdr.to = farAddr;
outMailHdr.to = 0;
outMailHdr.from = 1;
outMailHdr.length = strlen(data) + 1;
// Send the first message
postOffice->Send(outPktHdr, outMailHdr, data);
// Wait for the first message from the other machine
postOffice->Receive(0, &inPktHdr, &inMailHdr, buffer);
printf("Got \"%s\" from %d, box %d\n",buffer,inPktHdr.from,inMailHdr.from);
fflush(stdout);
// Send acknowledgement to the other machine (using "reply to" mailbox
// in the message that just arrived
outPktHdr.to = inPktHdr.from;
outMailHdr.to = inMailHdr.from;
outMailHdr.length = strlen(ack) + 1;
postOffice->Send(outPktHdr, outMailHdr, ack);
// Wait for the ack from the other machine to the first message we sent.
postOffice->Receive(1, &inPktHdr, &inMailHdr, buffer);
printf("Got \"%s\" from %d, box %d\n",buffer,inPktHdr.from,inMailHdr.from);
fflush(stdout);
// Then we're done!
interrupt->Powerdown();
}

347
code/network/post.cc Normal file
View file

@ -0,0 +1,347 @@
// post.cc
// Routines to deliver incoming network messages to the correct
// "address" -- a mailbox, or a holding area for incoming messages.
// This module operates just like the US postal service (in other
// words, it works, but it's slow, and you can't really be sure if
// your mail really got through!).
//
// Note that once we prepend the MailHdr to the outgoing message data,
// the combination (MailHdr plus data) looks like "data" to the Network
// device.
//
// The implementation synchronizes incoming messages with threads
// waiting for those messages.
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#include "copyright.h"
#include "post.h"
#include <strings.h> /* for bzero */
//----------------------------------------------------------------------
// Mail::Mail
// Initialize a single mail message, by concatenating the headers to
// the data.
//
// "pktH" -- source, destination machine ID's
// "mailH" -- source, destination mailbox ID's
// "data" -- payload data
//----------------------------------------------------------------------
Mail::Mail(PacketHeader pktH, MailHeader mailH, const void *msgData)
{
ASSERT(mailH.length <= MaxMailSize);
pktHdr = pktH;
mailHdr = mailH;
bcopy(msgData, data, mailHdr.length);
}
//----------------------------------------------------------------------
// MailBox::MailBox
// Initialize a single mail box within the post office, so that it
// can receive incoming messages.
//
// Just initialize a list of messages, representing the mailbox.
//----------------------------------------------------------------------
MailBox::MailBox()
{
messages = new SynchList();
}
//----------------------------------------------------------------------
// MailBox::~MailBox
// De-allocate a single mail box within the post office.
//
// Just delete the mailbox, and throw away all the queued messages
// in the mailbox.
//----------------------------------------------------------------------
MailBox::~MailBox()
{
delete messages;
messages = NULL;
}
//----------------------------------------------------------------------
// PrintHeader
// Print the message header -- the destination machine ID and mailbox
// #, source machine ID and mailbox #, and message length.
//
// "pktHdr" -- source, destination machine ID's
// "mailHdr" -- source, destination mailbox ID's
//----------------------------------------------------------------------
static void
PrintHeader(PacketHeader pktHdr, MailHeader mailHdr)
{
printf("From (%d, %d) to (%d, %d) bytes %d\n",
pktHdr.from, mailHdr.from, pktHdr.to, mailHdr.to, mailHdr.length);
}
//----------------------------------------------------------------------
// MailBox::Put
// Add a message to the mailbox. If anyone is waiting for message
// arrival, wake them up!
//
// We need to reconstruct the Mail message (by concatenating the headers
// to the data), to simplify queueing the message on the SynchList.
//
// "pktHdr" -- source, destination machine ID's
// "mailHdr" -- source, destination mailbox ID's
// "data" -- payload message data
//----------------------------------------------------------------------
void
MailBox::Put(PacketHeader pktHdr, MailHeader mailHdr, const void *data)
{
Mail *mail = new Mail(pktHdr, mailHdr, data);
messages->Append((void *)mail); // put on the end of the list of
// arrived messages, and wake up
// any waiters
}
//----------------------------------------------------------------------
// MailBox::Get
// Get a message from a mailbox, parsing it into the packet header,
// mailbox header, and data.
//
// The calling thread waits if there are no messages in the mailbox.
//
// "pktHdr" -- address to put: source, destination machine ID's
// "mailHdr" -- address to put: source, destination mailbox ID's
// "data" -- address to put: payload message data
//----------------------------------------------------------------------
void
MailBox::Get(PacketHeader *pktHdr, MailHeader *mailHdr, void *data)
{
DEBUG('n', "Waiting for mail in mailbox\n");
Mail *mail = (Mail *) messages->Remove(); // remove message from list;
// will wait if list is empty
*pktHdr = mail->pktHdr;
*mailHdr = mail->mailHdr;
if (DebugIsEnabled('n')) {
printf("Got mail from mailbox: ");
PrintHeader(*pktHdr, *mailHdr);
}
bcopy(mail->data, data, mail->mailHdr.length);
// copy the message data into
// the caller's buffer
delete mail; // we've copied out the stuff we
// need, we can now discard the message
}
//----------------------------------------------------------------------
// PostalHelper, ReadAvailHandler, WriteDoneHandler
// Dummy functions because C++ can't indirectly invoke member functions
// The first is forked as part of the "postal worker thread; the
// later two are called by the network interrupt handler.
//
// "arg" -- pointer to the Post Office managing the Network
//----------------------------------------------------------------------
static void PostalHelper(void *arg)
{ PostOffice* po = (PostOffice *) arg; po->PostalDelivery(); }
static void ReadAvailHandler(void *arg)
{ PostOffice* po = (PostOffice *) arg; po->IncomingPacket(); }
static void WriteDoneHandler(void *arg)
{ PostOffice* po = (PostOffice *) arg; po->PacketSent(); }
//----------------------------------------------------------------------
// PostOffice::PostOffice
// Initialize a post office as a collection of mailboxes.
// Also initialize the network device, to allow post offices
// on different machines to deliver messages to one another.
//
// We use a separate thread "the postal worker" to wait for messages
// to arrive, and deliver them to the correct mailbox. Note that
// delivering messages to the mailboxes can't be done directly
// by the interrupt handlers, because it requires a Lock.
//
// "addr" is this machine's network ID
// "reliability" is the probability that a network packet will
// be delivered (e.g., reliability = 1 means the network never
// drops any packets; reliability = 0 means the network never
// delivers any packets)
// "nBoxes" is the number of mail boxes in this Post Office
//----------------------------------------------------------------------
PostOffice::PostOffice(NetworkAddress addr, double reliability, int nBoxes)
{
// First, initialize the synchronization with the interrupt handlers
messageAvailable = new Semaphore("message available", 0);
messageSent = new Semaphore("message sent", 0);
sendLock = new Lock("message send lock");
// Second, initialize the mailboxes
netAddr = addr;
numBoxes = nBoxes;
boxes = new MailBox[nBoxes];
// Third, initialize the network; tell it which interrupt handlers to call
network = new Network(addr, reliability, ReadAvailHandler, WriteDoneHandler, this);
// Finally, create a thread whose sole job is to wait for incoming messages,
// and put them in the right mailbox.
Thread *t = new Thread("postal worker");
t->Start(PostalHelper, this);
}
//----------------------------------------------------------------------
// PostOffice::~PostOffice
// De-allocate the post office data structures.
//----------------------------------------------------------------------
PostOffice::~PostOffice()
{
delete network;
delete [] boxes;
delete messageAvailable;
delete messageSent;
delete sendLock;
}
//----------------------------------------------------------------------
// PostOffice::PostalDelivery
// Wait for incoming messages, and put them in the right mailbox.
//
// Incoming messages have had the PacketHeader stripped off,
// but the MailHeader is still tacked on the front of the data.
//----------------------------------------------------------------------
void
PostOffice::PostalDelivery()
{
PacketHeader pktHdr;
MailHeader mailHdr;
char *buffer = new char[MaxPacketSize];
for (;;) {
// first, wait for a message
messageAvailable->P();
pktHdr = network->Receive(buffer);
mailHdr = *(MailHeader *)buffer;
if (DebugIsEnabled('n')) {
printf("Putting mail into mailbox: ");
PrintHeader(pktHdr, mailHdr);
}
// check that arriving message is legal!
ASSERT(0 <= mailHdr.to && mailHdr.to < numBoxes);
ASSERT(mailHdr.length <= MaxMailSize);
// put into mailbox
boxes[mailHdr.to].Put(pktHdr, mailHdr, buffer + sizeof(MailHeader));
}
}
//----------------------------------------------------------------------
// PostOffice::Send
// Concatenate the MailHeader to the front of the data, and pass
// the result to the Network for delivery to the destination machine.
//
// Note that the MailHeader + data looks just like normal payload
// data to the Network.
//
// "pktHdr" -- source, destination machine ID's
// "mailHdr" -- source, destination mailbox ID's
// "data" -- payload message data
//----------------------------------------------------------------------
void
PostOffice::Send(PacketHeader pktHdr, MailHeader mailHdr, const void* data)
{
char* buffer = new char[MaxPacketSize]; // space to hold concatenated
// mailHdr + data
if (DebugIsEnabled('n')) {
printf("Post send: ");
PrintHeader(pktHdr, mailHdr);
}
ASSERT(mailHdr.length <= MaxMailSize);
ASSERT(0 <= mailHdr.to && mailHdr.to < numBoxes);
// fill in pktHdr, for the Network layer
pktHdr.from = netAddr;
pktHdr.length = mailHdr.length + sizeof(MailHeader);
// concatenate MailHeader and data
bcopy(&mailHdr, buffer, sizeof(MailHeader));
bcopy(data, buffer + sizeof(MailHeader), mailHdr.length);
sendLock->Acquire(); // only one message can be sent
// to the network at any one time
network->Send(pktHdr, buffer);
messageSent->P(); // wait for interrupt to tell us
// ok to send the next message
sendLock->Release();
delete [] buffer; // we've sent the message, so
// we can delete our buffer
}
//----------------------------------------------------------------------
// PostOffice::Send
// Retrieve a message from a specific box if one is available,
// otherwise wait for a message to arrive in the box.
//
// Note that the MailHeader + data looks just like normal payload
// data to the Network.
//
//
// "box" -- mailbox ID in which to look for message
// "pktHdr" -- address to put: source, destination machine ID's
// "mailHdr" -- address to put: source, destination mailbox ID's
// "data" -- address to put: payload message data
//----------------------------------------------------------------------
void
PostOffice::Receive(int box, PacketHeader *pktHdr,
MailHeader *mailHdr, void* data)
{
ASSERT((box >= 0) && (box < numBoxes));
boxes[box].Get(pktHdr, mailHdr, data);
ASSERT(mailHdr->length <= MaxMailSize);
}
//----------------------------------------------------------------------
// PostOffice::IncomingPacket
// Interrupt handler, called when a packet arrives from the network.
//
// Signal the PostalDelivery routine that it is time to get to work!
//----------------------------------------------------------------------
void
PostOffice::IncomingPacket()
{
messageAvailable->V();
}
//----------------------------------------------------------------------
// PostOffice::PacketSent
// Interrupt handler, called when the next packet can be put onto the
// network.
//
// The name of this routine is a misnomer; if "reliability < 1",
// the packet could have been dropped by the network, so it won't get
// through.
//----------------------------------------------------------------------
void
PostOffice::PacketSent()
{
messageSent->V();
}

141
code/network/post.h Normal file
View file

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