280 lines
7.6 KiB
Java
280 lines
7.6 KiB
Java
// PART OF THE MACHINE SIMULATION. DO NOT CHANGE.
|
|
|
|
package nachos.ag;
|
|
|
|
import nachos.machine.*;
|
|
import nachos.security.*;
|
|
import nachos.threads.*;
|
|
|
|
import java.util.Hashtable;
|
|
import java.util.StringTokenizer;
|
|
|
|
/**
|
|
* The default autograder. Loads the kernel, and then tests it using
|
|
* <tt>Kernel.selfTest()</tt>.
|
|
*/
|
|
public class AutoGrader {
|
|
/**
|
|
* Allocate a new autograder.
|
|
*/
|
|
public AutoGrader() {
|
|
}
|
|
|
|
/**
|
|
* Start this autograder. Extract the <tt>-#</tt> arguments, call
|
|
* <tt>init()</tt>, load and initialize the kernel, and call
|
|
* <tt>run()</tt>.
|
|
*
|
|
* @param privilege encapsulates privileged access to the Nachos
|
|
* machine.
|
|
*/
|
|
public void start(Privilege privilege) {
|
|
Lib.assertTrue(this.privilege == null,
|
|
"start() called multiple times");
|
|
this.privilege = privilege;
|
|
|
|
String[] args = Machine.getCommandLineArguments();
|
|
|
|
extractArguments(args);
|
|
|
|
System.out.print(" grader");
|
|
|
|
init();
|
|
|
|
System.out.print("\n");
|
|
|
|
kernel =
|
|
(Kernel) Lib.constructObject(Config.getString("Kernel.kernel"));
|
|
kernel.initialize(args);
|
|
|
|
run();
|
|
}
|
|
|
|
private void extractArguments(String[] args) {
|
|
String testArgsString = Config.getString("AutoGrader.testArgs");
|
|
if (testArgsString == null) {
|
|
testArgsString = "";
|
|
}
|
|
|
|
for (int i=0; i<args.length; ) {
|
|
String arg = args[i++];
|
|
if (arg.length() > 0 && arg.charAt(0) == '-') {
|
|
if (arg.equals("-#")) {
|
|
Lib.assertTrue(i < args.length,
|
|
"-# switch missing argument");
|
|
testArgsString = args[i++];
|
|
}
|
|
}
|
|
}
|
|
|
|
StringTokenizer st = new StringTokenizer(testArgsString, ",\n\t\f\r");
|
|
|
|
while (st.hasMoreTokens()) {
|
|
StringTokenizer pair = new StringTokenizer(st.nextToken(), "=");
|
|
|
|
Lib.assertTrue(pair.hasMoreTokens(),
|
|
"test argument missing key");
|
|
String key = pair.nextToken();
|
|
|
|
Lib.assertTrue(pair.hasMoreTokens(),
|
|
"test argument missing value");
|
|
String value = pair.nextToken();
|
|
|
|
testArgs.put(key, value);
|
|
}
|
|
}
|
|
|
|
String getStringArgument(String key) {
|
|
String value = (String) testArgs.get(key);
|
|
Lib.assertTrue(value != null,
|
|
"getStringArgument(" + key + ") failed to find key");
|
|
return value;
|
|
}
|
|
|
|
int getIntegerArgument(String key) {
|
|
try {
|
|
return Integer.parseInt(getStringArgument(key));
|
|
}
|
|
catch (NumberFormatException e) {
|
|
Lib.assertNotReached("getIntegerArgument(" + key + ") failed: " +
|
|
"value is not an integer");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
boolean getBooleanArgument(String key) {
|
|
String value = getStringArgument(key);
|
|
|
|
if (value.equals("1") || value.toLowerCase().equals("true")) {
|
|
return true;
|
|
}
|
|
else if (value.equals("0") || value.toLowerCase().equals("false")) {
|
|
return false;
|
|
}
|
|
else {
|
|
Lib.assertNotReached("getBooleanArgument(" + key + ") failed: " +
|
|
"value is not a boolean");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
long getTime() {
|
|
return privilege.stats.totalTicks;
|
|
}
|
|
|
|
void targetLevel(int targetLevel) {
|
|
this.targetLevel = targetLevel;
|
|
}
|
|
|
|
void level(int level) {
|
|
this.level++;
|
|
Lib.assertTrue(level == this.level,
|
|
"level() advanced more than one step: test jumped ahead");
|
|
|
|
if (level == targetLevel)
|
|
done();
|
|
}
|
|
|
|
private int level = 0, targetLevel = 0;
|
|
|
|
void done() {
|
|
System.out.print("\nsuccess\n");
|
|
privilege.exit(162);
|
|
}
|
|
|
|
private Hashtable<String, String> testArgs =
|
|
new Hashtable<String, String>();
|
|
|
|
void init() {
|
|
}
|
|
|
|
void run() {
|
|
kernel.selfTest();
|
|
kernel.run();
|
|
kernel.terminate();
|
|
}
|
|
|
|
Privilege privilege = null;
|
|
Kernel kernel;
|
|
|
|
/**
|
|
* Notify the autograder that the specified thread is the idle thread.
|
|
* <tt>KThread.createIdleThread()</tt> <i>must</i> call this method before
|
|
* forking the idle thread.
|
|
*
|
|
* @param idleThread the idle thread.
|
|
*/
|
|
public void setIdleThread(KThread idleThread) {
|
|
}
|
|
|
|
/**
|
|
* Notify the autograder that the specified thread has moved to the ready
|
|
* state. <tt>KThread.ready()</tt> <i>must</i> call this method before
|
|
* returning.
|
|
*
|
|
* @param thread the thread that has been added to the ready set.
|
|
*/
|
|
public void readyThread(KThread thread) {
|
|
}
|
|
|
|
/**
|
|
* Notify the autograder that the specified thread is now running.
|
|
* <tt>KThread.restoreState()</tt> <i>must</i> call this method before
|
|
* returning.
|
|
*
|
|
* @param thread the thread that is now running.
|
|
*/
|
|
public void runningThread(KThread thread) {
|
|
privilege.tcb.associateThread(thread);
|
|
currentThread = thread;
|
|
}
|
|
|
|
/**
|
|
* Notify the autograder that the current thread has finished.
|
|
* <tt>KThread.finish()</tt> <i>must</i> call this method before putting
|
|
* the thread to sleep and scheduling its TCB to be destroyed.
|
|
*/
|
|
public void finishingCurrentThread() {
|
|
privilege.tcb.authorizeDestroy(currentThread);
|
|
}
|
|
|
|
/**
|
|
* Notify the autograder that a timer interrupt occurred and was handled by
|
|
* software if a timer interrupt handler was installed. Called by the
|
|
* hardware timer.
|
|
*
|
|
* @param privilege proves the authenticity of this call.
|
|
* @param time the actual time at which the timer interrupt was
|
|
* issued.
|
|
*/
|
|
public void timerInterrupt(Privilege privilege, long time) {
|
|
Lib.assertTrue(privilege == this.privilege,
|
|
"security violation");
|
|
}
|
|
|
|
/**
|
|
* Notify the autograder that a user program executed a syscall
|
|
* instruction.
|
|
*
|
|
* @param privilege proves the authenticity of this call.
|
|
* @return <tt>true</tt> if the kernel exception handler should be called.
|
|
*/
|
|
public boolean exceptionHandler(Privilege privilege) {
|
|
Lib.assertTrue(privilege == this.privilege,
|
|
"security violation");
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Notify the autograder that <tt>Processor.run()</tt> was invoked. This
|
|
* can be used to simulate user programs.
|
|
*
|
|
* @param privilege proves the authenticity of this call.
|
|
*/
|
|
public void runProcessor(Privilege privilege) {
|
|
Lib.assertTrue(privilege == this.privilege,
|
|
"security violation");
|
|
}
|
|
|
|
/**
|
|
* Notify the autograder that a COFF loader is being constructed for the
|
|
* specified file. The autograder can use this to provide its own COFF
|
|
* loader, or return <tt>null</tt> to use the default loader.
|
|
*
|
|
* @param file the executable file being loaded.
|
|
* @return a loader to use in loading the file, or <tt>null</tt> to use
|
|
* the default.
|
|
*/
|
|
public Coff createLoader(OpenFile file) {
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Request permission to send a packet. The autograder can use this to drop
|
|
* packets very selectively.
|
|
*
|
|
* @param privilege proves the authenticity of this call.
|
|
* @return <tt>true</tt> if the packet should be sent.
|
|
*/
|
|
public boolean canSendPacket(Privilege privilege) {
|
|
Lib.assertTrue(privilege == this.privilege,
|
|
"security violation");
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Request permission to receive a packet. The autograder can use this to
|
|
* drop packets very selectively.
|
|
*
|
|
* @param privilege proves the authenticity of this call.
|
|
* @return <tt>true</tt> if the packet should be delivered to the kernel.
|
|
*/
|
|
public boolean canReceivePacket(Privilege privilege) {
|
|
Lib.assertTrue(privilege == this.privilege,
|
|
"security violation");
|
|
return true;
|
|
}
|
|
|
|
private KThread currentThread;
|
|
}
|