p1/userprog/SynchConsole.java

148 lines
3.6 KiB
Java

package nachos.userprog;
import nachos.machine.*;
import nachos.threads.*;
import nachos.userprog.*;
/**
* Provides a simple, synchronized interface to the machine's console. The
* interface can also be accessed through <tt>OpenFile</tt> objects.
*/
public class SynchConsole {
/**
* Allocate a new <tt>SynchConsole</tt>.
*
* @param console the underlying serial console to use.
*/
public SynchConsole(SerialConsole console) {
this.console = console;
Runnable receiveHandler = new Runnable() {
public void run() { receiveInterrupt(); }
};
Runnable sendHandler = new Runnable() {
public void run() { sendInterrupt(); }
};
console.setInterruptHandlers(receiveHandler, sendHandler);
}
/**
* Return the next unsigned byte received (in the range <tt>0</tt> through
* <tt>255</tt>). If a byte has not arrived at, blocks until a byte
* arrives, or returns immediately, depending on the value of <i>block</i>.
*
* @param block <tt>true</tt> if <tt>readByte()</tt> should wait for a
* byte if none is available.
* @return the next byte read, or -1 if <tt>block</tt> was <tt>false</tt>
* and no byte was available.
*/
public int readByte(boolean block) {
int value;
boolean intStatus = Machine.interrupt().disable();
readLock.acquire();
if (block || charAvailable) {
charAvailable = false;
readWait.P();
value = console.readByte();
Lib.assertTrue(value != -1);
}
else {
value = -1;
}
readLock.release();
Machine.interrupt().restore(intStatus);
return value;
}
/**
* Return an <tt>OpenFile</tt> that can be used to read this as a file.
*
* @return a file that can read this console.
*/
public OpenFile openForReading() {
return new File(true, false);
}
private void receiveInterrupt() {
charAvailable = true;
readWait.V();
}
/**
* Send a byte. Blocks until the send is complete.
*
* @param value the byte to be sent (the upper 24 bits are ignored).
*/
public void writeByte(int value) {
writeLock.acquire();
console.writeByte(value);
writeWait.P();
writeLock.release();
}
/**
* Return an <tt>OpenFile</tt> that can be used to write this as a file.
*
* @return a file that can write this console.
*/
public OpenFile openForWriting() {
return new File(false, true);
}
private void sendInterrupt() {
writeWait.V();
}
private boolean charAvailable = false;
private SerialConsole console;
private Lock readLock = new Lock();
private Lock writeLock = new Lock();
private Semaphore readWait = new Semaphore(0);
private Semaphore writeWait = new Semaphore(0);
private class File extends OpenFile {
File(boolean canRead, boolean canWrite) {
super(null, "SynchConsole");
this.canRead = canRead;
this.canWrite = canWrite;
}
public void close() {
canRead = canWrite = false;
}
public int read(byte[] buf, int offset, int length) {
if (!canRead)
return 0;
int i;
for (i=0; i<length; i++) {
int value = SynchConsole.this.readByte(false);
if (value == -1)
break;
buf[offset+i] = (byte) value;
}
return i;
}
public int write(byte[] buf, int offset, int length) {
if (!canWrite)
return 0;
for (int i=0; i<length; i++)
SynchConsole.this.writeByte(buf[offset+i]);
return length;
}
private boolean canRead, canWrite;
}
}