Compare commits

...

5 Commits

Author SHA1 Message Date
ginger88895 07650b1863 Done 2019-04-05 20:37:34 +08:00
ginger88895 e1080b73d8 Finished all parts with naive testing 2019-04-05 05:17:24 +08:00
ginger88895 23447866ce Format 2019-04-04 16:12:24 +08:00
ginger88895 f9b6cce80b Removed dump file 2019-04-03 00:16:01 +08:00
ginger88895 b699a736cc Finished Part 4 with naive testing 2019-04-03 00:14:39 +08:00
26 changed files with 20485 additions and 170 deletions

19822
proj1/dump Normal file

File diff suppressed because it is too large Load Diff

View File

@ -6,5 +6,6 @@ Machine.bank = false
Machine.networkLink = false
ElevatorBank.allowElevatorGUI = true
NachosSecurityManager.fullySecure = false
ThreadedKernel.scheduler = nachos.threads.RoundRobinScheduler #nachos.threads.PriorityScheduler
ThreadedKernel.scheduler = nachos.threads.PriorityScheduler
#ThreadedKernel.scheduler = nachos.threads.RoundRobinScheduler
Kernel.kernel = nachos.threads.ThreadedKernel

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -7,70 +7,250 @@ public class Boat
public static void selfTest()
{
BoatGrader b = new BoatGrader();
System.out.println("\n ***Testing Boats with only 2 children***");
begin(0, 2, b);
BoatGrader b = new BoatGrader();
System.out.println("\n ***Testing Boats with only 2 children***");
begin(100, 4, b);
// System.out.println("\n ***Testing Boats with 2 children, 1 adult***");
// begin(1, 2, b);
/*
System.out.println("\n ***Testing Boats with 2 children, 1 adult***");
begin(1, 2, b);
*/
// System.out.println("\n ***Testing Boats with 3 children, 3 adults***");
// begin(3, 3, b);
/*
System.out.println("\n ***Testing Boats with 3 children, 3 adults***");
begin(3, 3, b);
*/
}
public static void begin( int adults, int children, BoatGrader b )
{
// Store the externally generated autograder in a class
// variable to be accessible by children.
bg = b;
// Store the externally generated autograder in a class
// variable to be accessible by children.
bg=b;
// Instantiate global variables here
// Create threads here. See section 3.4 of the Nachos for Java
// Walkthrough linked from the projects page.
// Instantiate global variables here
// Create threads here. See section 3.4 of the Nachos for Java
// Walkthrough linked from the projects page.
//
num_adults=adults;
num_children=children;
Runnable r = new Runnable() {
public void run() {
SampleItinerary();
}
};
KThread t = new KThread(r);
t.setName("Sample Boat Thread");
t.fork();
KThread t_adults[]=new KThread[adults];
KThread t_children[]=new KThread[children];
for(int i=0;i<adults;i++)
{
Runnable r = new Runnable()
{
public void run()
{
AdultItinerary();
}
};
t_adults[i]=new KThread(r);
t_adults[i].fork();
}
for(int i=0;i<children;i++)
{
Runnable r = new Runnable()
{
public void run()
{
ChildItinerary();
}
};
t_children[i]=new KThread(r);
t_children[i].fork();
}
while(true)
{
mainLock.acquire();
mainCond.sleep();
mainLock.release();
numLock.acquire();
if(num_adults==passed_adults&&num_children==passed_children)
return;
numLock.release();
}
}
static void AdultItinerary()
{
bg.initializeAdult(); //Required for autograder interface. Must be the first thing called.
//DO NOT PUT ANYTHING ABOVE THIS LINE.
bg.initializeAdult(); //Required for autograder interface. Must be the first thing called.
//DO NOT PUT ANYTHING ABOVE THIS LINE.
/* This is where you should put your solutions. Make calls
to the BoatGrader to show that it is synchronized. For
example:
bg.AdultRowToMolokai();
indicates that an adult has rowed the boat across to Molokai
*/
/* This is where you should put your solutions. Make calls
to the BoatGrader to show that it is synchronized. For
example:
bg.AdultRowToMolokai();
indicates that an adult has rowed the boat across to Molokai
*/
int position=0;
while(true)
{
if(position==0)
{
adult0.P();
ship0.P();
bg.AdultRowToMolokai();
numLock.acquire();
passed_adults+=1;
numLock.release();
mainLock.acquire();
mainCond.wake();
mainLock.release();
ship1.V();
adult0.V();
position=1;
condLock1.acquire();
cond1.wake();
condLock1.release();
}
else
{
adult1.P();
while(true)
{
ship1.P();
numLock.acquire();
int x=passed_children;
numLock.release();
if(x==0)
break;
else
{
ship1.V();
condLock1.acquire();
cond1.sleep();
condLock1.release();
}
}
bg.AdultRowToOahu();
numLock.acquire();
passed_adults-=1;
numLock.release();
ship0.V();
adult1.V();
position=0;
}
}
}
static void ChildItinerary()
{
bg.initializeChild(); //Required for autograder interface. Must be the first thing called.
//DO NOT PUT ANYTHING ABOVE THIS LINE.
bg.initializeChild(); //Required for autograder interface. Must be the first thing called.
//DO NOT PUT ANYTHING ABOVE THIS LINE.
int position=0;
while(true)
{
if(position==0)
{
int type=0;
child0.P();
mutex1.acquire();
type=waiting_children;
waiting_children+=1;
mutex1.release();
if(type==0)
{
diff.speak(0);
bg.ChildRowToMolokai();
}
else
{
ship0.P();
diff.listen();
bg.ChildRideToMolokai();
mutex1.acquire();
waiting_children=0;
mutex1.release();
numLock.acquire();
passed_children+=2;
numLock.release();
mainLock.acquire();
mainCond.wake();
mainLock.release();
child0.V();
child0.V();
ship1.V();
}
position=1;
}
else
{
child1.P();
ship1.P();
bg.ChildRowToOahu();
numLock.acquire();
passed_children-=1;
numLock.release();
ship0.V();
child1.V();
position=0;
}
}
}
static void SampleItinerary()
{
// Please note that this isn't a valid solution (you can't fit
// all of them on the boat). Please also note that you may not
// have a single thread calculate a solution and then just play
// it back at the autograder -- you will be caught.
System.out.println("\n ***Everyone piles on the boat and goes to Molokai***");
bg.AdultRowToMolokai();
bg.ChildRideToMolokai();
bg.AdultRideToMolokai();
bg.ChildRideToMolokai();
// Please note that this isn't a valid solution (you can't fit
// all of them on the boat). Please also note that you may not
// have a single thread calculate a solution and then just play
// it back at the autograder -- you will be caught.
System.out.println("\n ***Everyone piles on the boat and goes to Molokai***");
bg.AdultRowToMolokai();
bg.ChildRideToMolokai();
bg.AdultRideToMolokai();
bg.ChildRideToMolokai();
}
static int boatPosition=0;
static int num_adults=0;
static int num_children=0;
static int passed_adults=0;
static int passed_children=0;
static Lock mutex1=new Lock();
static int waiting_children=0;
static Lock numLock=new Lock();
static Lock boatLock=new Lock();
static Lock mainLock=new Lock();
static Condition mainCond=new Condition(mainLock);
static Lock condLock0=new Lock();
static Condition cond0=new Condition(condLock0);
static Lock condLock1=new Lock();
static Condition cond1=new Condition(condLock1);
static Semaphore child0=new Semaphore(2);
static Semaphore adult0=new Semaphore(1);
static Semaphore ship0=new Semaphore(1);
static Semaphore child1=new Semaphore(1);
static Semaphore adult1=new Semaphore(1);
static Semaphore ship1=new Semaphore(0);
static Communicator diff=new Communicator();
}

View File

@ -9,11 +9,13 @@ import nachos.machine.*;
* be a time when both a speaker and a listener are waiting, because the two
* threads can be paired off at this point.
*/
public class Communicator {
public class Communicator
{
/**
* Allocate a new communicator.
*/
public Communicator() {
public Communicator()
{
}
/**
@ -26,7 +28,26 @@ public class Communicator {
*
* @param word the integer to transfer.
*/
public void speak(int word) {
public void speak(int word)
{
condLock.acquire();
if(protect==1) condProtect.sleep();
speakers++;
protect=1;
if(listeners==0)
{
condSpeaker.sleep();
message=word;
condPaired.wake();
}
else
{
message=word;
listeners--;
speakers--;
condListener.wake();
}
condLock.release();
}
/**
@ -35,7 +56,34 @@ public class Communicator {
*
* @return the integer transferred.
*/
public int listen() {
return 0;
public int listen()
{
int ret=0;
condLock.acquire();
listeners++;
if(speakers==0) condListener.sleep();
else
{
speakers--;
listeners--;
condSpeaker.wake();
condPaired.sleep();
}
ret=message;
protect=0;
condProtect.wake();
condLock.release();
return ret;
}
private int speakers=0;
private int listeners=0;
private int protect=0;
private int message=0;
private Lock condLock=new Lock();
private Condition condProtect=new Condition(condLock);
private Condition condSpeaker=new Condition(condLock);
private Condition condListener=new Condition(condLock);
private Condition condPaired=new Condition(condLock);
}

View File

@ -1,6 +1,7 @@
package nachos.threads;
import nachos.machine.*;
import java.util.Random;
/**
* A KThread is a thread that can be used to execute Nachos kernel code. Nachos
@ -500,6 +501,92 @@ public class KThread {
private int duration;
}
private static class ComTest implements Runnable
{
ComTest(int id,Communicator com)
{
this.id=id;
this.com=com;
}
public void run()
{
if(id<=48)
{
Random rand=new Random();
while(true)
{
int x=rand.nextInt(100);
System.out.println("Thread "+id+" speaking: "+x);
com.speak(x);
System.out.println("Thread "+id+" finished speaking: "+x);
ThreadedKernel.alarm.waitUntil(10000000);
//System.out.println("Thread "+id+" slept for "+(after-before)+" ticks");
}
}
else
{
while(true)
{
System.out.println("Thread "+id+" listening");
int x=com.listen();
System.out.println("Thread "+id+" received "+x);
ThreadedKernel.alarm.waitUntil(10000000);
//System.out.println("Thread "+id+" slept for "+(after-before)+" ticks");
}
}
}
private int id;
private Communicator com;
}
private static class DonationTest implements Runnable
{
DonationTest(int id,int priority,Lock myLock)
{
this.id=id;
this.priority=priority;
this.myLock=myLock;
}
public void setThread(KThread thread)
{
this.thread=thread;
}
public void setOther(KThread other)
{
this.other=other;
}
public void run()
{
boolean intStatus=Machine.interrupt().disable();
ThreadedKernel.scheduler.setPriority(thread,priority);
Machine.interrupt().restore(intStatus);
while(true)
{
ThreadedKernel.alarm.waitUntil(1);
myLock.acquire();
intStatus=Machine.interrupt().disable();
System.out.println("Effective priority for thread "+thread+" is "+ThreadedKernel.scheduler.getEffectivePriority(thread));
//System.out.println("Effective priority for thread "+other+" is "+ThreadedKernel.scheduler.getEffectivePriority(other));
Machine.interrupt().restore(intStatus);
KThread.yield();
myLock.release();
intStatus=Machine.interrupt().disable();
ThreadedKernel.scheduler.setPriority(thread,priority);
Machine.interrupt().restore(intStatus);
}
}
private int id;
private Lock myLock;
private int priority;
private KThread thread;
private KThread other;
}
/**
* Tests whether this module is working.
*/
@ -511,6 +598,9 @@ public class KThread {
//Test for KThread2.join()
/*
KThread t1=new KThread(new PingTest(1,null)).setName("forked thread");
boolean intStatus=Machine.interrupt().disable();
ThreadedKernel.scheduler.setPriority(t1,0);
Machine.interrupt().restore(intStatus);
t1.fork();
new PingTest(0,t1).run();
*/
@ -525,11 +615,37 @@ public class KThread {
*/
//Test for waitUntil
/*
new KThread(new AlarmTest(1,10000000)).fork();
new KThread(new AlarmTest(2,10000000)).fork();
new KThread(new AlarmTest(3,10000000)).fork();
new KThread(new AlarmTest(4,10000000)).fork();
new AlarmTest(0,50000000).run();
*/
//Test for Communicator
/*
Communicator com=new Communicator();
for(int i=1;i<50;i++) new KThread(new ComTest(i,com)).fork();
new ComTest(0,com).run();
*/
//Test for Donation
Lock myLock=new Lock();
DonationTest d1=new DonationTest(1,3,myLock);
KThread t1=new KThread(d1);
d1.setThread(t1);
DonationTest d2=new DonationTest(2,5,myLock);
KThread t2=new KThread(d2);
d2.setThread(t2);
d1.setOther(t2);
d2.setOther(t1);
t2.fork();
d1.run();
}
@ -574,3 +690,4 @@ public class KThread {
public Lock condLock=new Lock();
private Condition joinCondition=new Condition(condLock);
}

View File

@ -2,6 +2,7 @@ package nachos.threads;
import nachos.machine.*;
import java.lang.Math;
import java.util.TreeSet;
import java.util.HashSet;
import java.util.Iterator;
@ -26,7 +27,8 @@ import java.util.Iterator;
* A priority scheduler must partially solve the priority inversion problem; in
* particular, priority must be donated through locks, and through joins.
*/
public class PriorityScheduler extends Scheduler {
public class PriorityScheduler extends Scheduler
{
/**
* Allocate a new priority scheduler.
*/
@ -125,49 +127,156 @@ public class PriorityScheduler extends Scheduler {
/**
* A <tt>ThreadQueue</tt> that sorts threads by priority.
*/
protected class PriorityQueue extends ThreadQueue {
PriorityQueue(boolean transferPriority) {
this.transferPriority = transferPriority;
}
protected class PriorityQueue extends ThreadQueue
{
PriorityQueue(boolean transferPriority)
{
this.transferPriority = transferPriority;
this.waitingPriority=-1;
this.valid=false;
this.waitQueue=new HashSet<ThreadState>();
}
public void waitForAccess(KThread thread) {
Lib.assertTrue(Machine.interrupt().disabled());
getThreadState(thread).waitForAccess(this);
}
public void waitForAccess(KThread thread)
{
/*
System.out.println("Before wait:");
print();
*/
Lib.assertTrue(Machine.interrupt().disabled());
waitQueue.add(getThreadState(thread));
this.valid=false;
getThreadState(thread).waitForAccess(this);
/*
System.out.println("After wait:");
print();
*/
}
public void acquire(KThread thread) {
Lib.assertTrue(Machine.interrupt().disabled());
getThreadState(thread).acquire(this);
}
public void acquire(KThread thread)
{
/*
System.out.println("Before acquire:");
print();
*/
Lib.assertTrue(Machine.interrupt().disabled());
acquiringThread=getThreadState(thread);
getThreadState(thread).acquire(this);
/*
System.out.println("After acquire:");
print();
*/
}
public KThread nextThread() {
Lib.assertTrue(Machine.interrupt().disabled());
// implement me
return null;
}
public KThread nextThread()
{
/*
System.out.println("Before next:");
print();
*/
Lib.assertTrue(Machine.interrupt().disabled());
if(waitQueue.isEmpty())
{
if(transferPriority)
{
acquiringThread.acquiredQueues.remove(this);
this.valid=false;
acquiringThread.valid=false;
}
acquiringThread=null;
/*
System.out.println("After next:");
print();
*/
return null;
}
else
{
acquiringThread=pickNextThread();
if(transferPriority)
{
acquiringThread.acquiredQueues.remove(this);
this.valid=false;
acquiringThread.valid=false;
}
waitQueue.remove(acquiringThread);
acquiringThread.acquire(this);
/*
System.out.println("After next:");
print();
*/
return acquiringThread.thread;
}
}
/**
* Return the next thread that <tt>nextThread()</tt> would return,
* without modifying the state of this queue.
*
* @return the next thread that <tt>nextThread()</tt> would
* return.
*/
protected ThreadState pickNextThread() {
// implement me
return null;
}
public void print() {
Lib.assertTrue(Machine.interrupt().disabled());
// implement me (if you want)
}
/**
* Return the next thread that <tt>nextThread()</tt> would return,
* without modifying the state of this queue.
*
* @return the next thread that <tt>nextThread()</tt> would
* return.
*/
protected ThreadState pickNextThread()
{
// implement me
if(waitQueue.isEmpty())
return null;
else
{
boolean found=false;
int maxEff=0;
long minTime=0;
ThreadState next=null;
for(ThreadState x:waitQueue)
{
if(!found||x.getEffectivePriority()>maxEff||(x.getEffectivePriority()==maxEff&&x.waitTime<minTime))
{
found=true;
maxEff=x.getEffectivePriority();
minTime=x.waitTime;
next=x;
}
}
return next;
}
}
public void print()
{
Lib.assertTrue(Machine.interrupt().disabled());
if(acquiringThread!=null)
System.out.println("Acquired Thread: "+acquiringThread.thread);
else
System.out.println("Acquired Thread: null");
for(ThreadState x:waitQueue)
System.out.println(x.thread);
}
/**
* <tt>true</tt> if this queue should transfer priority from waiting
* threads to the owning thread.
*/
public boolean transferPriority;
public int getEffectivePriority()
{
/*
System.out.println("getEffectivePriority called on queue "+this);
print();
*/
if(!valid)
{
waitingPriority=-1;
for(ThreadState x:waitQueue)
waitingPriority=Math.max(waitingPriority,x.getEffectivePriority());
valid=true;
}
return waitingPriority;
}
/**
* <tt>true</tt> if this queue should transfer priority from waiting
* threads to the owning thread.
*/
public boolean transferPriority;
protected int waitingPriority;
protected boolean valid;
protected ThreadState acquiringThread=null;
protected HashSet<ThreadState> waitQueue;
}
/**
@ -177,85 +286,119 @@ public class PriorityScheduler extends Scheduler {
*
* @see nachos.threads.KThread#schedulingState
*/
protected class ThreadState {
/**
* Allocate a new <tt>ThreadState</tt> object and associate it with the
* specified thread.
*
* @param thread the thread this state belongs to.
*/
public ThreadState(KThread thread) {
this.thread = thread;
setPriority(priorityDefault);
}
protected class ThreadState
{
/**
* Allocate a new <tt>ThreadState</tt> object and associate it with the
* specified thread.
*
* @param thread the thread this state belongs to.
*/
public ThreadState(KThread thread)
{
this.thread=thread;
this.valid=false;
this.acquiredQueues=new HashSet<PriorityQueue>();
this.waitingQueues=new HashSet<PriorityQueue>();
setPriority(priorityDefault);
}
/**
* Return the priority of the associated thread.
*
* @return the priority of the associated thread.
*/
public int getPriority() {
return priority;
}
/**
* Return the priority of the associated thread.
*
* @return the priority of the associated thread.
*/
public int getPriority()
{
return priority;
}
/**
* Return the effective priority of the associated thread.
*
* @return the effective priority of the associated thread.
*/
public int getEffectivePriority() {
// implement me
return priority;
}
/**
* Return the effective priority of the associated thread.
*
* @return the effective priority of the associated thread.
*/
public int getEffectivePriority()
{
//System.out.println("getEffectivePriority called on thread "+thread);
if(!valid)
{
effectivePriority=priority;
for(PriorityQueue x:acquiredQueues)
effectivePriority=Math.max(effectivePriority,x.getEffectivePriority());
valid=true;
}
return effectivePriority;
}
/**
* Set the priority of the associated thread to the specified value.
*
* @param priority the new priority.
*/
public void setPriority(int priority) {
if (this.priority == priority)
return;
this.priority = priority;
// implement me
}
/**
* Set the priority of the associated thread to the specified value.
*
* @param priority the new priority.
*/
public void setPriority(int priority)
{
if (this.priority == priority)
return;
this.priority = priority;
this.valid=false;
for(PriorityQueue x:waitingQueues)
x.valid=false;
}
/**
* Called when <tt>waitForAccess(thread)</tt> (where <tt>thread</tt> is
* the associated thread) is invoked on the specified priority queue.
* The associated thread is therefore waiting for access to the
* resource guarded by <tt>waitQueue</tt>. This method is only called
* if the associated thread cannot immediately obtain access.
*
* @param waitQueue the queue that the associated thread is
* now waiting on.
*
* @see nachos.threads.ThreadQueue#waitForAccess
*/
public void waitForAccess(PriorityQueue waitQueue) {
// implement me
}
/**
* Called when <tt>waitForAccess(thread)</tt> (where <tt>thread</tt> is
* the associated thread) is invoked on the specified priority queue.
* The associated thread is therefore waiting for access to the
* resource guarded by <tt>waitQueue</tt>. This method is only called
* if the associated thread cannot immediately obtain access.
*
* @param waitQueue the queue that the associated thread is
* now waiting on.
*
* @see nachos.threads.ThreadQueue#waitForAccess
*/
public void waitForAccess(PriorityQueue waitQueue)
{
if(waitQueue.transferPriority)
{
waitingQueues.add(waitQueue);
waitQueue.valid=false;
}
waitTime=Machine.timer().getTime();
//System.out.println(waitTime);
// implement me
}
/**
* Called when the associated thread has acquired access to whatever is
* guarded by <tt>waitQueue</tt>. This can occur either as a result of
* <tt>acquire(thread)</tt> being invoked on <tt>waitQueue</tt> (where
* <tt>thread</tt> is the associated thread), or as a result of
* <tt>nextThread()</tt> being invoked on <tt>waitQueue</tt>.
*
* @see nachos.threads.ThreadQueue#acquire
* @see nachos.threads.ThreadQueue#nextThread
*/
public void acquire(PriorityQueue waitQueue) {
// implement me
}
/**
* Called when the associated thread has acquired access to whatever is
* guarded by <tt>waitQueue</tt>. This can occur either as a result of
* <tt>acquire(thread)</tt> being invoked on <tt>waitQueue</tt> (where
* <tt>thread</tt> is the associated thread), or as a result of
* <tt>nextThread()</tt> being invoked on <tt>waitQueue</tt>.
*
* @see nachos.threads.ThreadQueue#acquire
* @see nachos.threads.ThreadQueue#nextThread
*/
public void acquire(PriorityQueue waitQueue)
{
if(waitQueue.transferPriority)
{
acquiredQueues.add(waitQueue);
this.valid=false;
}
// implement me
}
/** The thread with which this object is associated. */
protected KThread thread;
/** The priority of the associated thread. */
protected int priority;
/** The thread with which this object is associated. */
protected KThread thread;
/** The priority of the associated thread. */
protected int priority;
protected boolean valid;
protected int effectivePriority;
protected HashSet<PriorityQueue> acquiredQueues;
protected HashSet<PriorityQueue> waitingQueues;
protected long waitTime;
}
}

View File

@ -90,7 +90,7 @@ public class Semaphore {
Semaphore ping = new Semaphore(0);
Semaphore pong = new Semaphore(0);
new KThread(new PingTest(ping, pong)).setName("ping").fork();
new KThread(new PingTest(ping, pong)).setName("ping1").fork();
for (int i=0; i<10; i++) {
ping.V();

View File

@ -45,13 +45,17 @@ public class ThreadedKernel extends Kernel {
* autograder never calls this method, so it is safe to put additional
* tests here.
*/
public void selfTest() {
KThread.selfTest();
Semaphore.selfTest();
SynchList.selfTest();
if (Machine.bank() != null) {
ElevatorBank.selfTest();
}
public void selfTest()
{
Boat.selfTest();
/*
KThread.selfTest();
Semaphore.selfTest();
SynchList.selfTest();
if (Machine.bank() != null) {
ElevatorBank.selfTest();
}
*/
}
/**