Compare commits

...

10 Commits

Author SHA1 Message Date
72320ede22 hw4 test 2024-12-30 05:59:42 +08:00
bf78b95c9d Remove: sanitizer flag in compile and link 2024-11-02 08:11:33 +08:00
5f06249b01 Fix: Custom test CI script 2024-11-02 08:04:02 +08:00
Yi-Ting Shih
b4987f1f70 Merge branch 'ytshih/hw2' into 'main'
Ytshih/hw2

See merge request cs_os_group_20/cs_os_project_20_hw!2
2024-11-02 07:58:12 +08:00
Yi-Ting Shih
4912fe4736 Ytshih/hw2 2024-11-02 07:58:12 +08:00
ChenYen-Yen
549bc9bcdc merge update 2024-10-22 16:29:46 +08:00
ChenYen-Yen
b18dbf056f update PrintInt and change PutString to PutInt 2024-10-22 16:27:49 +08:00
5b1cd5e1cf Add: README
Fix: newline when PrintInt outputs 0
2024-10-05 04:13:43 +08:00
施羿廷
486f032cf0 Merge branch 'ytshih-hw1' into 'main'
HW1

See merge request cs_os_group_20/cs_os_project_20_hw!1
2024-10-04 19:53:08 +00:00
施羿廷
ba9ef819ba HW1 2024-10-04 19:53:08 +00:00
86 changed files with 1510 additions and 4608 deletions

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
*.o
*.coff

16
Dockerfile Normal file
View File

@@ -0,0 +1,16 @@
FROM ubuntu:22.04
RUN dpkg --add-architecture i386
RUN apt-get update && apt-get dist-upgrade
RUN apt-get -y install build-essential ed \
gcc-multilib g++-multilib lib32ncurses5-dev lib32z1 \
zlib1g:i386 libstdc++6:i386 libc6:i386 libncurses5:i386 \
libgcc1:i386 libstdc++5:i386
RUN apt-get -y install fish vim less gdb
RUN groupadd -g 60139 ytshih && useradd -g 60139 -u 60139 ytshih
WORKDIR /work
ENTRYPOINT ["/usr/bin/env"]
CMD ["fish"]

17
README.md Normal file
View File

@@ -0,0 +1,17 @@
# Intro. to OS HW1
## Docker Compose usage
Install docker and docker-compose if not installed.
1. Change uid / gid to yours in `Dockerfile` and `docker-compose.yaml`.
2. Run `docker compose build` to build Docker image.
3. Run `docker compose run test` to launch testing environment.
## Makefile
First, `cd` into `code` directory.
- `make clean` to clean previous build.
- `make` to build.
- `make run` to run tests.

17
code/Makefile Normal file
View File

@@ -0,0 +1,17 @@
.PHONY: all clean run
all:
make -C build.linux depend
make -C build.linux -j 16
make -C test -j 16
clean:
make -C build.linux distclean
make -C test distclean
run:
make -C test run
debug:
make -C test debug

Binary file not shown.

View File

@@ -200,18 +200,18 @@ DEFINES = -DFILESYS_STUB -DRDATA -DSIM_FIX
# break the thread system. You might want to use -fno-inline if
# you need to call some inline functions from the debugger.
CFLAGS = -g -Wall $(INCPATH) $(DEFINES) $(HOSTCFLAGS) -DCHANGED -m32
CFLAGS = -g -Wall $(INCPATH) $(DEFINES) $(HOSTCFLAGS) -DCHANGED -m32 -w
LDFLAGS = -m32
CPP_AS_FLAGS= -m32
#####################################################################
CPP=/lib/cpp
CC = g++ -m32 -Wno-deprecated
LD = g++ -m32 -Wno-deprecated
CC = g++ -m32
LD = g++ -m32
AS = as --32
RM = /bin/rm
INCPATH = -I../network -I../filesys -I../userprog -I../threads -I../machine -I../lib -I-
INCPATH = -iquote../network -iquote../filesys -iquote../userprog -iquote../threads -iquote../machine -iquote../lib
PROGRAM = nachos

File diff suppressed because it is too large Load Diff

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.

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.

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.

Binary file not shown.

View File

@@ -40,13 +40,15 @@
#ifdef FILESYS_STUB // Temporarily implement file system calls as
// calls to UNIX, until the real file system
// implementation is available
typedef int OpenFileId;
class FileSystem {
public:
FileSystem() { for (int i = 0; i < 20; i++) fileDescriptorTable[i] = NULL; }
bool Create(char* name) {
int fileDescriptor = OpenForWrite(name);
if (fileDescriptor == -1) return FALSE;
Close(fileDescriptor);
return TRUE;
@@ -54,11 +56,60 @@ class FileSystem {
OpenFile* Open(char* name) {
int fileDescriptor = OpenForReadWrite(name, FALSE);
if (fileDescriptor == -1) return NULL;
return new OpenFile(fileDescriptor);
}
OpenFileId OpenFiles(char* name) {
OpenFile* file = Open(name);
if (!file) return -1;
int freeIndex = -1;
for (int i = 0; i < 20; i++)
if (!fileDescriptorTable[i])
freeIndex = i;
if (freeIndex == -1)
return -1;
OpenFileId fileDescriptor = file->GetFileDescriptor();
fileDescriptorTable[freeIndex] = file;
return fileDescriptor;
}
int WriteFile(char* buffer, int size, OpenFileId fd) {
for (int i = 0; i < 20; i++) {
if (!fileDescriptorTable[i])
continue;
if (fileDescriptorTable[i]->GetFileDescriptor() == fd) {
return fileDescriptorTable[i]->Write(buffer, size);
}
}
return -1;
}
int ReadFile(char* buffer, int size, OpenFileId fd) {
for (int i = 0; i < 20; i++) {
if (!fileDescriptorTable[i])
continue;
if (fileDescriptorTable[i]->GetFileDescriptor() == fd)
return fileDescriptorTable[i]->Read(buffer, size);
}
return -1;
}
int CloseFile(OpenFileId fd) {
for (int i = 0; i < 20; i++) {
if (!fileDescriptorTable[i])
continue;
if (fileDescriptorTable[i]->GetFileDescriptor() == fd) {
delete fileDescriptorTable[i];
fileDescriptorTable[i] = NULL;
return 1;
}
}
return 0;
}
bool Remove(char* name) { return Unlink(name) == 0; }
OpenFile* fileDescriptorTable[20];

View File

@@ -27,6 +27,8 @@
#ifdef FILESYS_STUB // Temporarily implement calls to
// Nachos file system as calls to UNIX!
// See definitions listed under #else
typedef int OpenFileId;
class OpenFile {
public:
OpenFile(int f) { file = f; currentOffset = 0; } // open the file
@@ -54,6 +56,10 @@ class OpenFile {
int Length() { Lseek(file, 0, 2); return Tell(file); }
OpenFileId GetFileDescriptor() {
return file;
}
private:
int file;
int currentOffset;

View File

@@ -29,6 +29,7 @@ const char dbgFile = 'f'; // file system
const char dbgAddr = 'a'; // address spaces
const char dbgNet = 'n'; // network emulation
const char dbgSys = 'u'; // systemcall
const char dbgSche = 'z';
class Debug {
public:

View File

@@ -172,3 +172,19 @@ ConsoleOutput::PutChar(char ch)
kernel->interrupt->Schedule(this, ConsoleTime, ConsoleWriteInt);
}
//----------------------------------------------------------------------
// ConsoleOutput::PutInt()
// Write a int to the simulated display, schedule an interrupt
// to occur in the future, and return.
//----------------------------------------------------------------------
void
ConsoleOutput::PutInt(int value)
{
ASSERT(putBusy == FALSE);
char * printStr = (char*)malloc(sizeof(char) * 15);
sprintf(printStr, "%d\n", value);
WriteFile(writeFileNo, printStr, strlen(printStr) * sizeof(char));
putBusy = TRUE;
kernel->interrupt->Schedule(this, ConsoleTime, ConsoleWriteInt);
}

View File

@@ -76,6 +76,9 @@ class ConsoleOutput : public CallBackObj {
void PutChar(char ch); // Write "ch" to the console display,
// and return immediately. "callWhenDone"
// will called when the I/O completes.
void PutInt(int value);
void CallBack(); // Invoked when next character can be put
// out to the display.

View File

@@ -22,6 +22,7 @@
#include "copyright.h"
#include "interrupt.h"
#include "synchconsole.h"
#include "main.h"
// String definitions for debugging messages
@@ -359,3 +360,31 @@ Interrupt::DumpState()
cout << "\nEnd of pending interrupts\n";
}
void Interrupt::PrintInt(int value)
{
kernel->synchConsoleOut->PutInt(value);
}
OpenFileId
Interrupt::OpenFile(char *filename)
{
return kernel->fileSystem->OpenFiles(filename);
}
int
Interrupt::WriteFile(char *buffer, int size, OpenFileId fd)
{
return kernel->fileSystem->WriteFile(buffer, size, fd);
}
int
Interrupt::CloseFile(OpenFileId fd)
{
return kernel->fileSystem->CloseFile(fd);
}
int
Interrupt::ReadFile(char *buffer, int size, OpenFileId fd)
{
return kernel->fileSystem->ReadFile(buffer, size, fd);
}

View File

@@ -37,6 +37,10 @@
#include "list.h"
#include "callback.h"
#include "filesys.h"
typedef int OpenFileId;
// Interrupts can be disabled (IntOff) or enabled (IntOn)
enum IntStatus { IntOff, IntOn };
@@ -48,8 +52,10 @@ enum MachineStatus {IdleMode, SystemMode, UserMode};
// IntType records which hardware device generated an interrupt.
// In Nachos, we support a hardware timer device, a disk, a console
// display and keyboard, and a network.
enum IntType { TimerInt, DiskInt, ConsoleWriteInt, ConsoleReadInt,
NetworkSendInt, NetworkRecvInt};
enum IntType {
TimerInt, DiskInt, ConsoleWriteInt, ConsoleReadInt,
NetworkSendInt, NetworkRecvInt
};
// The following class defines an interrupt that is scheduled
// to occur in the future. The internal data structures are
@@ -96,6 +102,10 @@ class Interrupt {
void PrintInt(int number);
int CreateFile(char* filename);
OpenFileId OpenFile(char* filename);
int WriteFile(char* buffer, int size, OpenFileId fd);
int CloseFile(OpenFileId fd);
int ReadFile(char* buffer, int size, OpenFileId fd);
void YieldOnReturn(); // cause a context switch on return
// from an interrupt handler

View File

@@ -53,6 +53,8 @@ enum ExceptionType { NoException, // Everything ok!
OverflowException, // Integer overflow in add or sub.
IllegalInstrException, // Unimplemented or reserved instr.
MemoryLimitException, // Insufficient memory
NumExceptionTypes
};

View File

@@ -53,7 +53,10 @@ const int UserTick = 1; // advance for each user-level instruction
const int SystemTick = 10; // advance each time interrupts are enabled
const int RotationTime = 500; // time disk takes to rotate one sector
const int SeekTime = 500; // time disk takes to seek past one track
const int ConsoleTime = 100; // time to read or write one character
// MP4 MODIFIED
const int ConsoleTime = 1; // time to read or write one character
const int NetworkTime = 100; // time to send or receive one packet
const int TimerTicks = 100; // (average) time between timer interrupts

View File

@@ -107,13 +107,13 @@ LD = $(GCCDIR)ld
INCDIR =-I../userprog -I../lib
CFLAGS = -G 0 -c $(INCDIR) -B../../usr/local/nachos/lib/gcc-lib/decstation-ultrix/2.95.2/ -B../../usr/local/nachos/decstation-ultrix/bin/
NACHOS = ../build.linux/nachos
ifeq ($(hosttype),unknown)
PROGRAMS = unknownhost
else
# change this if you create a new test program!
# PROGRAMS = add halt consoleIO_test1 consoleIO_test2 fileIO_test1 fileIO_test2
PROGRAMS = halt
PROGRAMS = mp4_consoleIO_1 mp4_consoleIO_2 mp4_consoleIO_3 mp4_consoleIO_4
endif
all: $(PROGRAMS)
@@ -121,72 +121,34 @@ all: $(PROGRAMS)
start.o: start.S ../userprog/syscall.h
$(CC) $(CFLAGS) $(ASFLAGS) -c start.S
halt.o: halt.c
$(CC) $(CFLAGS) -c halt.c
halt: halt.o start.o
$(LD) $(LDFLAGS) start.o halt.o -o halt.coff
$(COFF2NOFF) halt.coff halt
mp4_consoleIO_1.o: mp4_consoleIO_1.c
$(CC) $(CFLAGS) -c mp4_consoleIO_1.c
add.o: add.c
$(CC) $(CFLAGS) -c add.c
mp4_consoleIO_1: mp4_consoleIO_1.o start.o
$(LD) $(LDFLAGS) start.o mp4_consoleIO_1.o -o mp4_consoleIO_1.coff
$(COFF2NOFF) mp4_consoleIO_1.coff mp4_consoleIO_1
add: add.o start.o
$(LD) $(LDFLAGS) start.o add.o -o add.coff
$(COFF2NOFF) add.coff add
shell.o: shell.c
$(CC) $(CFLAGS) -c shell.c
shell: shell.o start.o
$(LD) $(LDFLAGS) start.o shell.o -o shell.coff
$(COFF2NOFF) shell.coff shell
mp4_consoleIO_2.o: mp4_consoleIO_2.c
$(CC) $(CFLAGS) -c mp4_consoleIO_2.c
sort.o: sort.c
$(CC) $(CFLAGS) -c sort.c
sort: sort.o start.o
$(LD) $(LDFLAGS) start.o sort.o -o sort.coff
$(COFF2NOFF) sort.coff sort
mp4_consoleIO_2: mp4_consoleIO_2.o start.o
$(LD) $(LDFLAGS) start.o mp4_consoleIO_2.o -o mp4_consoleIO_2.coff
$(COFF2NOFF) mp4_consoleIO_2.coff mp4_consoleIO_2
segments.o: segments.c
$(CC) $(CFLAGS) -c segments.c
segments: segments.o start.o
$(LD) $(LDFLAGS) start.o segments.o -o segments.coff
$(COFF2NOFF) segments.coff segments
mp4_consoleIO_3.o: mp4_consoleIO_3.c
$(CC) $(CFLAGS) -c mp4_consoleIO_3.c
matmult.o: matmult.c
$(CC) $(CFLAGS) -c matmult.c
matmult: matmult.o start.o
$(LD) $(LDFLAGS) start.o matmult.o -o matmult.coff
$(COFF2NOFF) matmult.coff matmult
mp4_consoleIO_3: mp4_consoleIO_3.o start.o
$(LD) $(LDFLAGS) start.o mp4_consoleIO_3.o -o mp4_consoleIO_3.coff
$(COFF2NOFF) mp4_consoleIO_3.coff mp4_consoleIO_3
consoleIO_test1.o: consoleIO_test1.c
$(CC) $(CFLAGS) -c consoleIO_test1.c
consoleIO_test1: consoleIO_test1.o start.o
$(LD) $(LDFLAGS) start.o consoleIO_test1.o -o consoleIO_test1.coff
$(COFF2NOFF) consoleIO_test1.coff consoleIO_test1
mp4_consoleIO_4.o: mp4_consoleIO_4.c
$(CC) $(CFLAGS) -c mp4_consoleIO_4.c
consoleIO_test2.o: consoleIO_test2.c
$(CC) $(CFLAGS) -c consoleIO_test2.c
consoleIO_test2: consoleIO_test2.o start.o
$(LD) $(LDFLAGS) start.o consoleIO_test2.o -o consoleIO_test2.coff
$(COFF2NOFF) consoleIO_test2.coff consoleIO_test2
fileIO_test1.o: fileIO_test1.c
$(CC) $(CFLAGS) -c fileIO_test1.c
fileIO_test1: fileIO_test1.o start.o
$(LD) $(LDFLAGS) start.o fileIO_test1.o -o fileIO_test1.coff
$(COFF2NOFF) fileIO_test1.coff fileIO_test1
fileIO_test2.o: fileIO_test2.c
$(CC) $(CFLAGS) -c fileIO_test2.c
fileIO_test2: fileIO_test2.o start.o
$(LD) $(LDFLAGS) start.o fileIO_test2.o -o fileIO_test2.coff
$(COFF2NOFF) fileIO_test2.coff fileIO_test2
fileIO_test3.o: fileIO_test3.c
$(CC) $(CFLAGS) -c fileIO_test3.c
fileIO_test3: fileIO_test3.o start.o
$(LD) $(LDFLAGS) start.o fileIO_test3.o -o fileIO_test3.coff
$(COFF2NOFF) fileIO_test3.coff fileIO_test3
mp4_consoleIO_4: mp4_consoleIO_4.o start.o
$(LD) $(LDFLAGS) start.o mp4_consoleIO_4.o -o mp4_consoleIO_4.coff
$(COFF2NOFF) mp4_consoleIO_4.coff mp4_consoleIO_4
clean:
@@ -196,6 +158,13 @@ clean:
distclean: clean
$(RM) -f $(PROGRAMS)
run: $(PROGRAMS)
timeout 1 $(NACHOS) -ep mp4_consoleIO_1 70 -ep mp4_consoleIO_3 80 -ep mp4_consoleIO_2 50
echo 'done'
debug: $(PROGRAMS)
timeout 1 $(NACHOS) -d z -ep mp4_consoleIO_1 60 -ep mp4_consoleIO_2 70
unknownhost:
@echo Host type could not be determined.
@echo make is terminating.

Binary file not shown.

Binary file not shown.

View File

@@ -1,12 +1,9 @@
#include "syscall.h"
int
main()
{
int main() {
int n;
for (n=9;n>5;n--) {
for (n = 9; n > 5; n--)
PrintInt(n);
}
Halt();
return 0;
}

Binary file not shown.

View File

@@ -1,13 +1,11 @@
#include "syscall.h"
int
main()
int main()
{
int n;
for (n=15;n<=19;n++){
PrintInt(n);
}
Halt();
return 0;
}

1
code/test/file1.test Normal file
View File

@@ -0,0 +1 @@
abcdefghijklmnopqrstuvwxyz

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,10 @@
#include "syscall.h"
int main()
{
int n;
for (n = 0; n < 4; n++) {
PrintInt(1);
}
return 0;
}

View File

@@ -0,0 +1,9 @@
#include "syscall.h"
int main()
{
int n;
for (n = 0; n < 5; n++) {
PrintInt(2);
}
return 0;
}

View File

@@ -0,0 +1,10 @@
#include "syscall.h"
int
main()
{
int n;
for (n = 0; n < 12; n++) {
PrintInt(3);
}
return 0;
}

View File

@@ -0,0 +1,9 @@
#include "syscall.h"
int main()
{
int n;
for (n = 0; n < 11; n++) {
PrintInt(4);
}
return 0;
}

View File

@@ -1,3 +1,9 @@
make clean
make -d
../build.linux/nachos -e halt
make distclean
make
rm -f *.o *.ii
rm -f *.coff
echo "=========================="
timeout 1 ../build.linux/nachos -e mp4_consoleIO_1 -e mp4_consoleIO_2
echo "=========================="
timeout 1 ../build.linux/nachos -e mp4_consoleIO_3 -e mp4_consoleIO_4
echo "done"

View File

@@ -58,6 +58,14 @@ MSG:
j $31
.end MSG
.globl PrintInt
.ent PrintInt
PrintInt:
addiu $2,$0,SC_PrintInt
syscall
j $31
.end PrintInt
.globl Add
.ent Add
Add:

6
code/test/test.c Normal file
View File

@@ -0,0 +1,6 @@
#include "syscall.h"
int main()
{
Exit(0);
}

View File

@@ -49,7 +49,9 @@ Alarm::CallBack()
Interrupt* interrupt = kernel->interrupt;
MachineStatus status = interrupt->getStatus();
// Todo ----
if (status != IdleMode) {
interrupt->YieldOnReturn();
// interrupt->YieldOnReturn();
}
// ---------
}

View File

@@ -43,32 +43,48 @@ Kernel::Kernel(int argc, char **argv)
// number generator
randomSlice = TRUE;
i++;
} else if (strcmp(argv[i], "-s") == 0) {
}
else if (strcmp(argv[i], "-s") == 0) {
debugUserProg = TRUE;
} else if (strcmp(argv[i], "-e") == 0) {
}
// Todo ----
else if (strcmp(argv[i], "-e") == 0) {
execfile[++execfileNum] = argv[++i];
cout << execfile[execfileNum] << "\n";
} else if (strcmp(argv[i], "-ci") == 0) {
}
else if (strcmp(argv[i], "-ep") == 0) {
execfile[++execfileNum] = argv[++i];
execPriority[execfileNum] = atoi(argv[++i]);
cout << execfile[execfileNum] << " with priority "
<< execPriority[execfileNum] << "\n";
}
// ---------
else if (strcmp(argv[i], "-ci") == 0) {
ASSERT(i + 1 < argc);
consoleIn = argv[i + 1];
i++;
} else if (strcmp(argv[i], "-co") == 0) {
}
else if (strcmp(argv[i], "-co") == 0) {
ASSERT(i + 1 < argc);
consoleOut = argv[i + 1];
i++;
#ifndef FILESYS_STUB
} else if (strcmp(argv[i], "-f") == 0) {
}
else if (strcmp(argv[i], "-f") == 0) {
formatFlag = TRUE;
#endif
} else if (strcmp(argv[i], "-n") == 0) {
}
else if (strcmp(argv[i], "-n") == 0) {
ASSERT(i + 1 < argc); // next argument is float
reliability = atof(argv[i + 1]);
i++;
} else if (strcmp(argv[i], "-m") == 0) {
}
else if (strcmp(argv[i], "-m") == 0) {
ASSERT(i + 1 < argc); // next argument is int
hostName = atoi(argv[i + 1]);
i++;
} else if (strcmp(argv[i], "-u") == 0) {
}
else if (strcmp(argv[i], "-u") == 0) {
cout << "Partial usage: nachos [-rs randomSeed]\n";
cout << "Partial usage: nachos [-s]\n";
cout << "Partial usage: nachos [-ci consoleIn] [-co consoleOut]\n";
@@ -111,9 +127,12 @@ Kernel::Initialize()
#else
fileSystem = new FileSystem(formatFlag);
#endif // FILESYS_STUB
postOfficeIn = new PostOfficeInput(10);
postOfficeOut = new PostOfficeOutput(reliability);
// MP4 MODIFIED
// postOfficeIn = new PostOfficeInput(10);
// postOfficeOut = new PostOfficeOutput(reliability);
frameTable = new FrameTable();
interrupt->Enable();
}
@@ -133,8 +152,12 @@ Kernel::~Kernel()
delete synchConsoleOut;
delete synchDisk;
delete fileSystem;
delete postOfficeIn;
delete postOfficeOut;
// MP4 MODIFIED
// delete postOfficeIn;
// delete postOfficeOut;
delete frameTable;
Exit(0);
}
@@ -261,16 +284,18 @@ void ForkExecute(Thread *t)
void Kernel::ExecAll()
{
for (int i = 1;i <= execfileNum;i++) {
int a = Exec(execfile[i]);
int a = Exec(execfile[i], execPriority[i]);
}
currentThread->Finish();
//Kernel::Exec();
}
int Kernel::Exec(char* name)
// Todo ----
int Kernel::Exec(char* name, int priority)
{
t[threadNum] = new Thread(name, threadNum);
t[threadNum]->setPriority(priority);
// ---------
t[threadNum]->space = new AddrSpace();
t[threadNum]->Fork((VoidFunctionPtr)&ForkExecute, (void*)t[threadNum]);
threadNum++;

View File

@@ -25,7 +25,8 @@ class SynchConsoleInput;
class SynchConsoleOutput;
class SynchDisk;
// Todo ----
// ---------
class Kernel {
public:
@@ -37,7 +38,11 @@ class Kernel {
// from constructor because
// refers to "kernel" as a global
void ExecAll();
int Exec(char* name);
// Todo ----
int Exec(char* name, int priority);
// ---------
void ThreadSelfTest(); // self test of threads and synchronization
void ConsoleTest(); // interactive console self test
@@ -61,13 +66,18 @@ class Kernel {
FileSystem *fileSystem;
PostOfficeInput *postOfficeIn;
PostOfficeOutput *postOfficeOut;
FrameTable *frameTable;
int hostName; // machine identifier
private:
Thread* t[10];
// Todo ----
char* execfile[10];
int execPriority[10];
// ---------
int execfileNum;
int threadNum;
bool randomSlice; // enable pseudo-random time slicing
@@ -82,5 +92,3 @@ class Kernel {
#endif // KERNEL_H

View File

@@ -22,6 +22,7 @@
#include "debug.h"
#include "scheduler.h"
#include "main.h"
#include <functional>
//----------------------------------------------------------------------
// Scheduler::Scheduler
@@ -29,9 +30,20 @@
// Initially, no ready threads.
//----------------------------------------------------------------------
// Todo ----
int cmp(Thread *a, Thread *b)
{
int ap = a->getPriority();
int bp = b->getPriority();
return (ap < bp) - (ap > bp);
}
Scheduler::Scheduler()
{
readyList = new List<Thread *>;
readyList = new SortedList(cmp);
// ---------
toBeDestroyed = NULL;
}
@@ -60,7 +72,9 @@ Scheduler::ReadyToRun (Thread *thread)
DEBUG(dbgThread, "Putting thread on ready list: " << thread->getName());
//cout << "Putting thread on ready list: " << thread->getName() << endl ;
thread->setStatus(READY);
readyList->Append(thread);
DEBUG(dbgSche, "[A] Tick [" << kernel->stats->totalTicks << "]: Process [" << thread->getName() << "] is inserted into queue.");
readyList->Insert(thread);
}
//----------------------------------------------------------------------
@@ -78,7 +92,9 @@ Scheduler::FindNextToRun ()
if (readyList->IsEmpty()) {
return NULL;
} else {
}
else {
DEBUG(dbgSche, "[B] Tick [" << kernel->stats->totalTicks << "]: Process [" << readyList->Front()->getName() << "] is removed from queue.");
return readyList->RemoveFront();
}
}
@@ -124,6 +140,7 @@ Scheduler::Run (Thread *nextThread, bool finishing)
nextThread->setStatus(RUNNING); // nextThread is now running
DEBUG(dbgThread, "Switching from: " << oldThread->getName() << " to: " << nextThread->getName());
DEBUG(dbgSche, "[C] Tick [" << kernel->stats->totalTicks << "]: Process [" << nextThread->getName() << "] is now selected for execution, thread [" << oldThread->getName() << "] is replaced.");
// This is a machine-dependent assembly language routine defined
// in switch.s. You may have to think

View File

@@ -35,8 +35,11 @@ class Scheduler {
// SelfTest for scheduler is implemented in class Thread
private:
List<Thread *> *readyList; // queue of threads that are ready to run,
// Todo ----
SortedList<Thread *> *readyList; // queue of threads that are ready to run,
// but not running
// ---------
Thread *toBeDestroyed; // finishing thread to be destroyed
// by the next thread that runs
};

View File

@@ -40,7 +40,8 @@ Thread::Thread(char* threadName, int threadID)
stackTop = NULL;
stack = NULL;
status = JUST_CREATED;
for (int i = 0; i < MachineStateSize; i++) {
for (int i = 0; i < MachineStateSize; i++)
{
machineState[i] = NULL; // not strictly necessary, since
// new thread ignores contents
// of machine registers
@@ -88,8 +89,7 @@ Thread::~Thread()
// "arg" is a single argument to be passed to the procedure.
//----------------------------------------------------------------------
void
Thread::Fork(VoidFunctionPtr func, void *arg)
void Thread::Fork(VoidFunctionPtr func, void *arg)
{
Interrupt *interrupt = kernel->interrupt;
Scheduler *scheduler = kernel->scheduler;
@@ -119,10 +119,10 @@ Thread::Fork(VoidFunctionPtr func, void *arg)
// Don't do this: void foo() { int bigArray[10000]; ... }
//----------------------------------------------------------------------
void
Thread::CheckOverflow()
void Thread::CheckOverflow()
{
if (stack != NULL)
{
if (stack != NULL) {
#ifdef HPUX // Stacks grow upward on the Snakes
ASSERT(stack[StackSize - 1] == STACK_FENCEPOST);
#else
@@ -142,8 +142,7 @@ Thread::CheckOverflow()
// 2. enable interrupts (so we can get time-sliced)
//----------------------------------------------------------------------
void
Thread::Begin ()
void Thread::Begin()
{
ASSERT(this == kernel->currentThread);
DEBUG(dbgThread, "Beginning thread: " << name);
@@ -167,8 +166,7 @@ Thread::Begin ()
//----------------------------------------------------------------------
//
void
Thread::Finish ()
void Thread::Finish()
{
(void)kernel->interrupt->SetLevel(IntOff);
ASSERT(this == kernel->currentThread);
@@ -178,7 +176,6 @@ Thread::Finish ()
// not reached
}
//----------------------------------------------------------------------
// Thread::Yield
// Relinquish the CPU if any other thread is ready to run.
@@ -197,8 +194,7 @@ Thread::Finish ()
// Similar to Thread::Sleep(), but a little different.
//----------------------------------------------------------------------
void
Thread::Yield ()
void Thread::Yield()
{
Thread *nextThread;
IntStatus oldLevel = kernel->interrupt->SetLevel(IntOff);
@@ -208,7 +204,8 @@ Thread::Yield ()
DEBUG(dbgThread, "Yielding thread: " << name);
nextThread = kernel->scheduler->FindNextToRun();
if (nextThread != NULL) {
if (nextThread != NULL)
{
kernel->scheduler->ReadyToRun(this);
kernel->scheduler->Run(nextThread, FALSE);
}
@@ -235,8 +232,7 @@ Thread::Yield ()
// so that there can't be a time slice between pulling the first thread
// off the ready list, and switching to it.
//----------------------------------------------------------------------
void
Thread::Sleep (bool finishing)
void Thread::Sleep(bool finishing)
{
Thread *nextThread;
@@ -247,7 +243,8 @@ Thread::Sleep (bool finishing)
status = BLOCKED;
// cout << "debug Thread::Sleep " << name << "wait for Idle\n";
while ((nextThread = kernel->scheduler->FindNextToRun()) == NULL) {
while ((nextThread = kernel->scheduler->FindNextToRun()) == NULL)
{
kernel->interrupt->Idle(); // no one to run, wait for an interrupt
}
// returns when it's time for us to run
@@ -279,11 +276,14 @@ PLabelToAddr(void *plabel)
{
int funcPtr = (int)plabel;
if (funcPtr & 0x02) {
if (funcPtr & 0x02)
{
// L-Field is set. This is a PLT pointer
funcPtr -= 2; // Get rid of the L bit
return (*(void **)funcPtr);
} else {
}
else
{
// L-field not set.
return plabel;
}
@@ -302,8 +302,7 @@ PLabelToAddr(void *plabel)
// "arg" is the parameter to be passed to the procedure
//----------------------------------------------------------------------
void
Thread::StackAllocate (VoidFunctionPtr func, void *arg)
void Thread::StackAllocate(VoidFunctionPtr func, void *arg)
{
stack = (int *)AllocBoundedArray(StackSize * sizeof(int));
@@ -336,7 +335,6 @@ Thread::StackAllocate (VoidFunctionPtr func, void *arg)
*stack = STACK_FENCEPOST;
#endif
#ifdef x86
// the x86 passes the return address on the stack. In order for SWITCH()
// to go to ThreadRoot when we switch to this thread, the return addres
@@ -372,8 +370,7 @@ Thread::StackAllocate (VoidFunctionPtr func, void *arg)
// while executing kernel code. This routine saves the former.
//----------------------------------------------------------------------
void
Thread::SaveUserState()
void Thread::SaveUserState()
{
for (int i = 0; i < NumTotalRegs; i++)
userRegisters[i] = kernel->machine->ReadRegister(i);
@@ -388,14 +385,12 @@ Thread::SaveUserState()
// while executing kernel code. This routine restores the former.
//----------------------------------------------------------------------
void
Thread::RestoreUserState()
void Thread::RestoreUserState()
{
for (int i = 0; i < NumTotalRegs; i++)
kernel->machine->WriteRegister(i, userRegisters[i]);
}
//----------------------------------------------------------------------
// SimpleThread
// Loop 5 times, yielding the CPU to another ready thread
@@ -410,7 +405,8 @@ SimpleThread(int which)
{
int num;
for (num = 0; num < 5; num++) {
for (num = 0; num < 5; num++)
{
cout << "*** thread " << which << " looped " << num << " times\n";
kernel->currentThread->Yield();
}
@@ -422,8 +418,7 @@ SimpleThread(int which)
// to call SimpleThread, and then calling SimpleThread ourselves.
//----------------------------------------------------------------------
void
Thread::SelfTest()
void Thread::SelfTest()
{
DEBUG(dbgThread, "Entering Thread::SelfTest");
@@ -433,3 +428,16 @@ Thread::SelfTest()
kernel->currentThread->Yield();
SimpleThread(0);
}
// Todo ----
int Thread::getPriority() const
{
return priority;
}
void Thread::setPriority(int p)
{
ASSERT(p >= 0 && p <= 149);
priority = p;
}
// ---------

View File

@@ -80,6 +80,10 @@ class Thread {
int *stackTop; // the current stack pointer
void *machineState[MachineStateSize]; // all registers except for stackTop
// Todo ----
int priority;
// ---------
public:
Thread(char* debugName, int threadID); // initialize a Thread
~Thread(); // deallocate a Thread
@@ -89,6 +93,11 @@ class Thread {
// basic thread operations
// Todo ----
int getPriority() const;
void setPriority(int p);
// ---------
void Fork(VoidFunctionPtr func, void *arg);
// Make thread run (*func)(arg)
void Yield(); // Relinquish the CPU if any

View File

@@ -27,7 +27,6 @@
// object file header, in case the file was generated on a little
// endian machine, and we're now running on a big endian machine.
//----------------------------------------------------------------------
static void
SwapHeader(NoffHeader* noffH)
{
@@ -64,9 +63,10 @@ SwapHeader (NoffHeader *noffH)
// memory. For now, this is really simple (1:1), since we are
// only uniprogramming, and we have a single unsegmented page table
//----------------------------------------------------------------------
AddrSpace::AddrSpace()
{
pageTable = NULL; // initialize with NULL
/*
pageTable = new TranslationEntry[NumPhysPages];
for (int i = 0; i < NumPhysPages; i++) {
pageTable[i].virtualPage = i; // for now, virt page # = phys page #
@@ -79,6 +79,7 @@ AddrSpace::AddrSpace()
// zero out the entire address space
bzero(kernel->machine->mainMemory, MemorySize);
*/
}
//----------------------------------------------------------------------
@@ -88,7 +89,9 @@ AddrSpace::AddrSpace()
AddrSpace::~AddrSpace()
{
delete pageTable;
/* delete pageTable; */
// release frame table by page table
kernel->frameTable->Release(pageTable, numPages);
}
@@ -101,7 +104,6 @@ AddrSpace::~AddrSpace()
//
// "fileName" is the file containing the object code to load into memory
//----------------------------------------------------------------------
bool
AddrSpace::Load(char* fileName)
{
@@ -135,37 +137,102 @@ AddrSpace::Load(char *fileName)
numPages = divRoundUp(size, PageSize);
size = numPages * PageSize;
ASSERT(numPages <= NumPhysPages); // check we're not trying
// to run anything too big --
// at least until we have
// virtual memory
pageTable = kernel->frameTable->Allocate(numPages);
if (!pageTable) {
kernel->interrupt->setStatus(SystemMode);
ExceptionHandler(MemoryLimitException);
kernel->interrupt->setStatus(UserMode);
}
DEBUG(dbgAddr, "Initializing address space: " << numPages << ", " << size);
// then, copy in the code and data segments into memory
// Note: this code assumes that virtual address = physical address
uint paddr; // physical address
ExceptionType ex; // occurring exception
int sz, // total size to load
vaddr, // base virtual address
fpos, // base file position
to_load; // size to load on each time
if (noffH.code.size > 0) {
DEBUG(dbgAddr, "Initializing code segment.");
DEBUG(dbgAddr, noffH.code.virtualAddr << ", " << noffH.code.size);
executable->ReadAt(
&(kernel->machine->mainMemory[noffH.code.virtualAddr]),
noffH.code.size, noffH.code.inFileAddr);
sz = noffH.code.size;
vaddr = noffH.code.virtualAddr;
fpos = noffH.code.inFileAddr;
for (uint offset = 0; offset < sz; offset += PageSize) {
ex = Translate(vaddr + offset, &paddr, 1);
if (ex != NoException) {
kernel->interrupt->setStatus(SystemMode);
ExceptionHandler(ex);
kernel->interrupt->setStatus(UserMode);
}
to_load = offset + PageSize < sz ? PageSize : sz - offset;
executable->ReadAt(
&(kernel->machine->mainMemory[paddr]),
to_load, fpos + offset);
}
}
if (noffH.initData.size > 0) {
DEBUG(dbgAddr, "Initializing data segment.");
DEBUG(dbgAddr, noffH.initData.virtualAddr << ", " << noffH.initData.size);
sz = noffH.initData.size;
vaddr = noffH.initData.virtualAddr;
fpos = noffH.initData.inFileAddr;
for (uint offset = 0; offset < sz; offset += PageSize) {
ex = Translate(vaddr + offset, &paddr, 1);
if (ex != NoException) {
kernel->interrupt->setStatus(SystemMode);
ExceptionHandler(ex);
kernel->interrupt->setStatus(UserMode);
}
to_load = offset + PageSize < sz ? PageSize : sz - offset;
executable->ReadAt(
&(kernel->machine->mainMemory[noffH.initData.virtualAddr]),
noffH.initData.size, noffH.initData.inFileAddr);
&(kernel->machine->mainMemory[paddr]),
to_load, fpos + offset);
}
}
#ifdef RDATA
if (noffH.readonlyData.size > 0) {
DEBUG(dbgAddr, "Initializing read only data segment.");
DEBUG(dbgAddr, noffH.readonlyData.virtualAddr << ", " << noffH.readonlyData.size);
sz = noffH.readonlyData.size;
vaddr = noffH.readonlyData.virtualAddr;
fpos = noffH.readonlyData.inFileAddr;
// read only flag for page table
for (int i = 0, lim = divRoundUp(sz, PageSize),
from = vaddr / PageSize; i < lim; ++i)
pageTable[from + i].readOnly = TRUE;
for (uint offset = 0; offset < sz; offset += PageSize) {
ex = Translate(vaddr + offset, &paddr, 0); // read only
if (ex != NoException) {
kernel->interrupt->setStatus(SystemMode);
ExceptionHandler(ex);
kernel->interrupt->setStatus(UserMode);
}
to_load = offset + PageSize < sz ? PageSize : sz - offset;
executable->ReadAt(
&(kernel->machine->mainMemory[noffH.readonlyData.virtualAddr]),
noffH.readonlyData.size, noffH.readonlyData.inFileAddr);
&(kernel->machine->mainMemory[paddr]),
to_load, fpos + offset);
}
}
#endif
@@ -181,7 +248,6 @@ AddrSpace::Load(char *fileName)
// the address space
//
//----------------------------------------------------------------------
void
AddrSpace::Execute(char* fileName)
{
@@ -191,7 +257,7 @@ AddrSpace::Execute(char* fileName)
this->InitRegisters(); // set the initial register values
this->RestoreState(); // load page table register
kernel->machine->Run(); // jump to the user progam
kernel->machine->Run(); // jump to the user program
ASSERTNOTREACHED(); // machine->Run never returns;
// the address space exits
@@ -208,7 +274,6 @@ AddrSpace::Execute(char* fileName)
// will be saved/restored into the currentThread->userRegisters
// when this thread is context switched out.
//----------------------------------------------------------------------
void
AddrSpace::InitRegisters()
{
@@ -242,9 +307,9 @@ AddrSpace::InitRegisters()
//
// For now, don't need to save anything!
//----------------------------------------------------------------------
void AddrSpace::SaveState()
{}
{
}
//----------------------------------------------------------------------
// AddrSpace::RestoreState
@@ -253,7 +318,6 @@ void AddrSpace::SaveState()
//
// For now, tell the machine where to find the page table.
//----------------------------------------------------------------------
void AddrSpace::RestoreState()
{
kernel->machine->pageTable = pageTable;
@@ -311,6 +375,43 @@ AddrSpace::Translate(unsigned int vaddr, unsigned int *paddr, int isReadWrite)
return NoException;
}
FrameTable::FrameTable() {
for (int i = 0; i < NumPhysPages; ++i)
available.Append(i);
}
FrameTable::~FrameTable() {}
uint FrameTable::RemainSize() { return available.NumInList(); }
PageTable FrameTable::Allocate(uint pageNum) {
// if not enough memory
if (RemainSize() < pageNum)
return NULL;
PageTable ptb = new TranslationEntry[pageNum];
for (int i = 0; i < pageNum; ++i) {
ptb[i].virtualPage = i;
int f = available.RemoveFront(); // frame number
ptb[i].physicalPage = f;
// initialize flags
ptb[i].valid = TRUE;
ptb[i].use = FALSE;
ptb[i].dirty = FALSE;
ptb[i].readOnly = FALSE;
// zero out the entire address space
bzero(kernel->machine->mainMemory + f * PageSize, PageSize);
}
return ptb;
}
void FrameTable::Release(PageTable ptb, int pageNum) {
if (!ptb)
return; // nothing to release
for (int i = 0; i < pageNum; ++i)
available.Append(ptb[i].physicalPage);
delete[] ptb;
}

View File

@@ -51,3 +51,51 @@ class AddrSpace {
};
#endif // ADDRSPACE_H
#ifndef FRAME_TABLE_H
#define FRAME_TABLE_H
#include "machine.h"
#include "list.h"
/**
* Data structure of Virtual Memory
*/
typedef TranslationEntry* PageTable;
/**
* Data structure of Physical Memory
*/
class FrameTable {
public:
/**
* Initialize a frame table
*/
FrameTable();
~FrameTable();
/**
* Allocate pageNum of frames (pages) and collect
* corresponding translation information into a page table.
*
* @param pageNum numbers of pages
* @return a new Page table, NULL if not enough memory space
*/
PageTable Allocate(uint pageNum);
/**
* Release the physical memory frame
* which the info stored in PageTable
*/
void Release(PageTable ptb, int pageNum);
/**
* @return the remaining numbers of entry of the frame table
*/
uint RemainSize();
private:
List<int> available;
};
#endif /* FRAME_TABLE_H */

View File

@@ -54,6 +54,7 @@ ExceptionHandler(ExceptionType which)
int type = kernel->machine->ReadRegister(2);
int val;
int status, exit, threadID, programID;
int fd, size;
DEBUG(dbgSys, "Received Exception " << which << " type: " << type << "\n");
switch (which) {
case SyscallException:
@@ -74,6 +75,13 @@ ExceptionHandler(ExceptionType which)
SysHalt();
ASSERTNOTREACHED();
break;
case SC_PrintInt:
val = kernel->machine->ReadRegister(4);
SysPrintInt(val);
kernel->machine->WriteRegister(PrevPCReg, kernel->machine->ReadRegister(PCReg));
kernel->machine->WriteRegister(PCReg, kernel->machine->ReadRegister(PCReg) + 4);
kernel->machine->WriteRegister(NextPCReg, kernel->machine->ReadRegister(PCReg) + 4);
return;
case SC_Create:
val = kernel->machine->ReadRegister(4);
{
@@ -88,6 +96,62 @@ ExceptionHandler(ExceptionType which)
return;
ASSERTNOTREACHED();
break;
case SC_Open:
val = kernel->machine->ReadRegister(4);
{
char* filename = &(kernel->machine->mainMemory[val]);
//cout << filename << endl;
fd = SysOpen(filename);
kernel->machine->WriteRegister(2, (int)fd);
}
kernel->machine->WriteRegister(PrevPCReg, kernel->machine->ReadRegister(PCReg));
kernel->machine->WriteRegister(PCReg, kernel->machine->ReadRegister(PCReg) + 4);
kernel->machine->WriteRegister(NextPCReg, kernel->machine->ReadRegister(PCReg) + 4);
return;
ASSERTNOTREACHED();
break;
case SC_Write:
val = kernel->machine->ReadRegister(4);
size = kernel->machine->ReadRegister(5);
fd = kernel->machine->ReadRegister(6);
{
char* buffer = &(kernel->machine->mainMemory[val]);
size = SysWrite(buffer, size, fd);
kernel->machine->WriteRegister(2, (int)size);
}
kernel->machine->WriteRegister(PrevPCReg, kernel->machine->ReadRegister(PCReg));
kernel->machine->WriteRegister(PCReg, kernel->machine->ReadRegister(PCReg) + 4);
kernel->machine->WriteRegister(NextPCReg, kernel->machine->ReadRegister(PCReg) + 4);
return;
ASSERTNOTREACHED();
break;
case SC_Close:
fd = kernel->machine->ReadRegister(4);
{
val = SysClose(fd);
kernel->machine->WriteRegister(2, (int)val);
}
kernel->machine->WriteRegister(PrevPCReg, kernel->machine->ReadRegister(PCReg));
kernel->machine->WriteRegister(PCReg, kernel->machine->ReadRegister(PCReg) + 4);
kernel->machine->WriteRegister(NextPCReg, kernel->machine->ReadRegister(PCReg) + 4);
return;
ASSERTNOTREACHED();
break;
case SC_Read:
val = kernel->machine->ReadRegister(4);
size = kernel->machine->ReadRegister(5);
fd = kernel->machine->ReadRegister(6);
{
char* buffer = &(kernel->machine->mainMemory[val]);
size = SysRead(buffer, size, fd);
kernel->machine->WriteRegister(2, (int)size);
}
kernel->machine->WriteRegister(PrevPCReg, kernel->machine->ReadRegister(PCReg));
kernel->machine->WriteRegister(PCReg, kernel->machine->ReadRegister(PCReg) + 4);
kernel->machine->WriteRegister(NextPCReg, kernel->machine->ReadRegister(PCReg) + 4);
return;
ASSERTNOTREACHED();
break;
case SC_Add:
DEBUG(dbgSys, "Add " << kernel->machine->ReadRegister(4) << " + " << kernel->machine->ReadRegister(5) << "\n");
/* Process SysAdd Systemcall*/

View File

@@ -0,0 +1,11 @@
#include "syscall.h"
int
main()
{
int n;
for (n = 0; n < 4; n++) {
PrintInt(1);
}
return 0;
}

View File

@@ -0,0 +1,11 @@
#include "syscall.h"
int
main()
{
int n;
for (n = 0; n < 5; n++) {
PrintInt(2);
}
return 0;
}

View File

@@ -0,0 +1,12 @@
#include "syscall.h"
int
main()
{
int n;
for (n = 0; n < 12; n++) {
PrintInt(3);
}
return 0;
}

View File

@@ -0,0 +1,12 @@
#include "syscall.h"
int
main()
{
int n;
for (n = 0; n < 11; n++) {
PrintInt(4);
}
return 0;
}

View File

@@ -15,6 +15,7 @@
#include "synchconsole.h"
typedef int OpenFileId;
void SysHalt()
{
@@ -34,5 +35,37 @@ int SysCreate(char *filename)
return kernel->interrupt->CreateFile(filename);
}
void SysPrintInt(int value)
{
kernel->interrupt->PrintInt(value);
}
// -1: open fail
// fd
OpenFileId SysOpen(char* filename)
{
return kernel->interrupt->OpenFile(filename);
}
// -1: write fail
// size
int SysWrite(char* buffer, int size, OpenFileId fd)
{
return kernel->interrupt->WriteFile(buffer, size, fd);
}
// 1: close success
// 0: close fail
int SysClose(OpenFileId fd)
{
return kernel->interrupt->CloseFile(fd);
}
// -1: read fail
// size
int SysRead(char* buffer, int size, OpenFileId fd)
{
return kernel->interrupt->ReadFile(buffer, size, fd);
}
#endif /* ! __USERPROG_KSYSCALL_H__ */

View File

@@ -6,8 +6,7 @@
*/
#define NOFFMAGIC 0xbadfad /* magic number denoting Nachos
* object code file
*/
/* object code file*/
typedef struct segment {
int virtualAddr; /* location of segment in virt addr space */

View File

@@ -106,6 +106,20 @@ SynchConsoleOutput::PutChar(char ch)
lock->Release();
}
//----------------------------------------------------------------------
// SynchConsoleOutput::PutInt
// Write a int to the console display, waiting if necessary.
//----------------------------------------------------------------------
void
SynchConsoleOutput::PutInt(int value)
{
lock->Acquire();
consoleOutput->PutInt(value);
waitFor->P();
lock->Release();
}
//----------------------------------------------------------------------
// SynchConsoleOutput::CallBack
// Interrupt handler called when it's safe to send the next

View File

@@ -41,6 +41,7 @@ class SynchConsoleOutput : public CallBackObj {
~SynchConsoleOutput();
void PutChar(char ch); // Write a character, waiting if necessary
void PutInt(int value);
private:
ConsoleOutput* consoleOutput;// the hardware display

View File

@@ -36,6 +36,7 @@
#define SC_ThreadJoin 15
#define SC_Add 42
#define SC_MSG 100
#define SC_PrintInt 16
#ifndef IN_ASM
@@ -52,6 +53,11 @@
/* Stop Nachos, and print out performance stats */
void Halt();
/*
* Show the int value on console
*/
void PrintInt(int value);
/*
* Add the two operants and return the result
*/

7
docker-compose.yaml Normal file
View File

@@ -0,0 +1,7 @@
---
services:
test:
build: .
user: ytshih
volumes:
- './:/work'