Nachos Instructional OS: Part 2 CS 170, Tao Yang, Fall 2015 - - PowerPoint PPT Presentation

nachos instructional os part 2
SMART_READER_LITE
LIVE PREVIEW

Nachos Instructional OS: Part 2 CS 170, Tao Yang, Fall 2015 - - PowerPoint PPT Presentation

Nachos Instructional OS: Part 2 CS 170, Tao Yang, Fall 2015 Announcement and update Project 1 deadline was extended. Project 2 description was revised last weekend. Start now or you miss deadline There are bonus points to submit and


slide-1
SLIDE 1

Nachos Instructional OS: Part 2

CS 170, Tao Yang, Fall 2015

slide-2
SLIDE 2

5/14/2015 2

Announcement and update

Project 1 deadline was extended.

 Project 2 description was revised last

  • weekend. Start now or you miss deadline

 There are bonus points to submit and pass

1/3 of autograding by this Saturday.

 Midterm exam sample was given out.  Exercise 1 will be updated in next few days.  Some students still look for a partner…

slide-3
SLIDE 3

5/14/2015 3

What to learn?

 How to execute a program in Nachos

 Produce binary MIPS code from a C program  Execute this MIPS code in a tiny space  Make a simple Nachos system call in a C program

 Project 2.

 Support the execution of multiple processes

 Support multiprogramming and memory protection with

address translation using 1-level page table

 System calls for process execution.  System calls for a simple file system interface.

slide-4
SLIDE 4

System Layers

Base Operating System (Linux for our class) Nachos kernel threads Thread 1 Thread 2 Thread N Nachos OS modules (Threads mgm, File System, Code execution/memory mapping, System calls/Interrupt) MIPS Virtual Machine (Memory, Disk, Console)

User process: Binary code User process: Binary code

slide-5
SLIDE 5

Machine

  • bject

SP Rn PC

memory page table

5/14/2015 5

Virtual Machine Layer

 under machine subdirectory.  Approximates the MIPS architecture  Can execute a sequence of MIPS instructions.

registers Timer

slide-6
SLIDE 6

5/14/2015 6

Two modes of executions

 User mode: execute instructions which only access

the user space.

 Kernel mode

 kernel executes when Nachos first starts up

 or when an instruction causes a trap

 illegal instruction,  page fault  system call

Nachos layer

slide-7
SLIDE 7

5/14/2015 7

Code execution steps in Nachos

 Load instructions into the machine's memory.  Initialize registers (program counter, etc).  Tell the machine to start executing instructions.  The machine fetches the instruction, decodes it, and

executes it.

 Repeat until all instructions are executed.

Handle interrupt/page fault when needed Nachos Nachos execution layer MIPS Machine

User binary code

slide-8
SLIDE 8

5/14/2015 8

Machine Object: Implement a MIPS machine

 an instance created when Nachos starts up.  Supported public variables:

 Registers: 40 registers.

 4KB Memory: Byte-addressable. 32 pages

(128Bytes)

 Virtual memory: use a single linear page table or

a software-managed TLB.

Machine

  • bject

SP Rn PC

memory page table

slide-9
SLIDE 9

5/14/2015 9

Code/machine/machine.h

class Machine { char *mainMemory; // physical memory to store user program, // code and data, while executing int registers[NumTotalRegs]; // CPU registers, for executing user programs TranslationEntry *pageTable; unsigned int pageTableSize; }

Machine

  • bject

SP Rn PC

memory page table

slide-10
SLIDE 10

5/14/2015 10

Machine Object: Supported

  • perations

 Machine(bool debug);//allocate memory of 32 pages

(128bytes per page). Initialize memory/register/ page table

 Translate(int virtAddr, int* physAddr, int size, bool

writing);

 OneInstruction();

// Run one instruction of a user program.

 Run();

// Run a user program

 ReadRegister(int num);  WriteRegister(int num, int value);  ReadMem(int addr, int size, int* value);  WriteMem(int addr, int size, int value);

slide-11
SLIDE 11

5/14/2015 11

Code/machine/ipssim.cc

void Machine::Run(){

Instruction *instr = new Instruction; // storage for decoded instruction interrupt->setStatus(UserMode); for (;;) { OneInstruction(instr); //fetch and execute one instruction interrupt->OneTick(); //advance clock }

}

slide-12
SLIDE 12

12

Code/machine/machine.h

class Instruction { public: void Decode(); // decode binary representation of instruction unsigned int value; // binary representation of the instruction unsigned char opCode; // Type of instruction unsigned char rs, rt, rd; // Three registers from instruction. int extra; // offset or other purpose. Treat as 0 };

slide-13
SLIDE 13

13

Code/machine/ipssim.cc

Void Machine::OneInstruction(Instruction *instr) { //Fetch an instruction and then decode if (!machine->ReadMem(registers[PCReg], 4, &raw)) return; //if error, return instr->value = raw; instr->Decode(); // Execute the instruction switch (instr->opCode) { … case OP_ADDU: registers[instr->rd] = registers[instr->rs] + registers[instr->rt];break; case OP_SW: machine->WriteMem(registers[instr->rs], 4, registers[instr- >rt]); break; … case OP_SYSCALL: RaiseException(SyscallException, 0); return; … } // Advance program counters. registers[PCReg] = registers[NextPCReg]; registers[NextPCReg] = pcAfter; //which is registers[NextPCReg] + 4; }

slide-14
SLIDE 14

14

Code/machine/translate.cc

bool Machine::WriteMem(int addr, int size, int value) { ExceptionType exception; int physicalAddress; exception = Translate(addr, &physicalAddress, size, TRUE);//address translation if (exception != NoException) { machine->RaiseException(exception, addr); return FALSE; } switch (size) { //Copy value to the target physical memory address properly case 1: machine->mainMemory[physicalAddress] = (unsigned char) (value & 0xff); break; case 2: *(unsigned short *) &machine->mainMemory[physicalAddress] = ShortToMachine((unsigned short) (value & 0xffff)); break; case 4: …. } } bool Machine::ReadMem(int addr, int size, int *value) { … }

slide-15
SLIDE 15

A Simple Page Table

PFN 0 PFN 1 PFN i

page #i

  • ffset

user virtual address

PFN i +

  • ffset

process page table physical memory page frames Each process has its

  • wn page table.

Virtual addresses are translated relative to the current page table.

slide-16
SLIDE 16

ExceptionType Machine::Translate(int virtAddr, * physAddr, size, writing) { unsigned int vpn, offset; TranslationEntry *entry; unsigned int pageFrame; // calculate virtual page number, and offset within the page vpn = (unsigned) virtAddr / PageSize;

  • ffset = (unsigned) virtAddr % PageSize;

entry = &pageTable[vpn]; pageFrame = entry->physicalPage; entry->use = TRUE; // set the use, dirty bits if (writing) entry->dirty = TRUE; *physAddr = pageFrame * PageSize + offset; // compute physical address return NoException; }

16

Code/machine/translate.cc

Physical page use bit | dirty bit

slide-17
SLIDE 17

Machine

  • bject

SP Rn PC

memory page table

5/14/2015 17

Virtual Machine Layer

registers Timer Interrupt

slide-18
SLIDE 18

5/14/2015 18

Interrupt Object

Maintain an event queue with a simulated clock.

Supported operations:

 Schedule(VoidFunctionPtr handler, int arg, int when, IntType

type) Schedule a future event to take place at time ``when''.

 Usage: schedule a yield at random interval.

 SetLevel(IntStatus level). Used to temporarily disable and

re-enable interrupts. Two levels are supported: IntOn and IntOff.

 OneTick()—advance 1 clock tick  CheckIfDue(bool advanceClock). Examines if some event

should be serviced.

 Idle(). ``advances'' to the clock to the time of the next

scheduled event

slide-19
SLIDE 19

5/14/2015 19

Interrupt::OneTick()

 Software managed clock.

 The clock advances 1 tick after one binary

instruction execution with user mode , 10 with system mode

 after every restored interrupt

(disable/enable Interrupt)

 or after the MIPS simulator executes one

instruction.

 When the ready list is empty, fast-advance

ticks until the next scheduled event happens.

slide-20
SLIDE 20

20

Timer object

 Generate interrupts at regular or random intervals  Then Nachos invokes the predefined clock event

handling procedure.

 Supported operation:

 Timer(VoidFunctionPtr timerHandler, int callArg,

bool doRandom).

 Create a real-time clock that interrupts

 every TimerTicks (100) time units  Or set this a random number for random mode

 nachos –rs 0

Setup a random timer that requests a thread yield

slide-21
SLIDE 21

21

Console Object

 Simulates a character-oriented CRT device  Data can be written to the device one character at a

time through the PutChar() routine.

 Input characters arrive one-at-a-time. They can be

retrieved by GetChar().

 Supported operations:

 Console(char *readFile, char *writeFile,

VoidFunctionPtr readAvail,VoidFunctionPtr writeDone, int callArg). Create a console instance.``readFile'' is the Unix file

  • f where the data is to be read from; if NULL,

standard input is assumed.

 PutChar(char ch)  GetChar()

slide-22
SLIDE 22

5/14/2015 22

Disk Object

Simulates the behavior of a real disk.

 The disk has only a single platter, with multiple tracks (32).  Each track contains the same number of sectors (32).  Allow only one pending operation at a time.  Contain a ``track buffer'' cache. Immediately after seeking to

a new track, the disk starts reading sectors, placing them in the track buffer.

Supported operations:

 Disk(char *name, VoidFunctionPtr callWhenDone, int callArg)  ReadRequest(int sectorNumber, char *data)  WriteRequest(int sectorNumber, char *data)  ComputeLatency(int newSector, bool writing)

slide-23
SLIDE 23

Executing a user program

data

user space MIPS instructions executed by the emulator Nachos kernel

MIPS emulator

halt Machine

  • bject

fetch/execute examine/deposit SaveState/RestoreState examine/deposit Machine::Run() ExceptionHandler()

SP Rn PC

registers memory page table

process page tables

slide-24
SLIDE 24

From C program to MIPS binary

int j; char* s = “hello\n”; int p() { j = write(1, s, 6); return(j); } myprogram.c

gcc compiler

…..

p: store this store that push jsr _write ret etc.

myprogram.s

assembler

data

myprogram.o

linker

  • bject

file

data

program

(executable file) myprogram

data data data libraries and

  • ther
  • bjects
slide-25
SLIDE 25

5/14/2015 25

Binary code format (Noff)

Source code: under userprog subdirectory.

 Current Nachos can run a single MIPS binary (Noff

format)

 type ``nachos -x ../test/halt''.

 A user program must be compiled using a cross-

platform gcc compiler that generates MIPS code.

 A Noff-format file contains (bin/noff.h)

 the Noff header, describes the contents of the rest

  • f the file

 executable code segment (TEXT)  initialized data segment (DATA)  uninitialized data segment (BSS).

slide-26
SLIDE 26

Space usage during execution of a C program

Stack grows from top-down. Heap grows bottom-up Uninitialized data

STACK HEAP BSS

DATA

TEXT Initialized data Code

slide-27
SLIDE 27

5/14/2015 27

TEXT, DATA, BSS, HEAP, STACK in C

Int f3=3; /* DATA segment */ Int f1; /*BSS segment*/ def[] = "1"; int main(void) { static char abc[12]; /* BSS segment */ static float pi = 3.14159; int i = 3; /* Stack*/ char *cp; cp= malloc(10); /* HEAP for allocated chunk*/ f1= i+f3; /* code is in TEXT. f1 on STACK*/ strcpy(abc , "Test" ); } DATA or BSS? DATA or BSS or STACK? DATA or BSS or STACK? Where is “Test”? DATA or BSS or STACK?

STACK HEAP BSS

DATA

TEXT

slide-28
SLIDE 28

5/14/2015 28

TEXT, DATA, BSS, HEAP, STACK in C

Int f3=3; /* DATA segment */ Int f1; /*BSS segment*/ def[] = "1"; /* DATA segment */ int main(void) { static char abc[12], /* BSS segment */ static float pi = 3.14159; /* DATA segment */ int i = 3; /* Stack*/ char *cp; /*stack*/ cp= malloc(10); /*malloc allocates space from HEAP*/ f1= i+f3; /* code is in TEXT*/ strcpy(abc , "Test" ); /* “Test” is located in DATA segment */ }

STACK HEAP BSS

DATA

TEXT

slide-29
SLIDE 29

5/14/2015 29

Noff format

. Each segment has the following information:

 virtualAddr: virtual address that

segment begins at.

 inFileAddr: Pointer within the Noff file

where that section actually begins.

 The size (in bytes) of that segment.

STACK HEAP BSS

DATA

TEXT

slide-30
SLIDE 30

5/14/2015

size = noffH.code.size + noffH.initData.size + noffH.uninitData.size+ UserStackSize

User process for executing a program

A Nachos thread is extended as a process

 Each process has its own address space containing

 Executable code (Code segment)  Initialized data (Data segment)  Uninitialized data (BSS)  Stack space for function calls/local variables

 how big is address space?  A process owns some other objects, such as open file

descriptors.

slide-31
SLIDE 31

5/14/2015 31

Steps in User process creation

Currently only execute a single user program.

1.

Create an address space.

2.

Zero out all of physical memory (machine- >mainMemory)

3.

Read the binary into physical memory and initialize data segment.

4.

Initialize the translation tables to do a one-to-one mapping between virtual and physical addresses.

5.

Zero all registers, setting PCReg and NextPCReg to 0 and 4 respectively.

6.

Set the stackpointer to the largest virtual address of the process (stack grows downward).

slide-32
SLIDE 32

5/14/2015 32

Key Calling graph when Nachos executes under userprog directory

main() in main.cc Initialize() in system.cc StartProcess () in progtest.cc Space= New AddrSpace() in addrspace.cc Space-> InitRegisters() Executable file ReadAt() Space

  • >RestoreState()

Machine->Run () in mipssim.cc Machine-> WriteRegister() Machine-> OneInstruction() Interupt-> OneTick() In Interupt.cc

slide-33
SLIDE 33

void StartProcess(char *filename) { OpenFile *executable; AddrSpace *space; executable = fileSystem->Open(filename); if (executable == NULL) { printf("Unable to open file %s\n", filename); return; } space = new AddrSpace(executable); currentThread->space = space; delete executable; // close file space->InitRegisters(); space->RestoreState(); machine->Run(); ASSERT(FALSE);

}

Creating a Nachos Process (code/userprog/progtest.cc)

Create an AddrSpace

  • bject, allocating physical

memory and setting up the process page table. Set address space of current thread/process. Initialize registers, load pagetable, and begin execution in user mode. Create a handle for reading text and initial data out of the executable file. Run binary code

slide-34
SLIDE 34

AddrSpace::AddrSpace(OpenFile *executable) { NoffHeader noffH; unsigned int i, size; executable->ReadAt((char *)&noffH, sizeof(noffH), 0); // how big is address space? size = noffH.code.size + noffH.initData.size + noffH.uninitData.size + UserStackSize; // we need to increase the size to leave room for the stack numPages = divRoundUp(size, PageSize); size = numPages * PageSize; pageTable = new TranslationEntry[numPages]; for (i = 0; i < numPages; i++) { pageTable[i].virtualPage = i; // for now, virtual page # = phys page # pageTable[i].physicalPage = i; pageTable[i].valid = TRUE; }

....

Creating a Nachos Address Space (code/userprog/addrspace.cc)

Read the header of binary file Compute address space need Setup a page table for address translation

slide-35
SLIDE 35

bzero(machine->mainMemory, size); // copy in the code and data if (noffH.code.size > 0) { executable->ReadAt(&(machine->mainMemory[noffH.code.virtualAddr]), noffH.code.size, noffH.code.inFileAddr); } if (noffH.initData.size > 0) { executable->ReadAt(&(machine->mainMemory[noffH.initData.virtualAddr]), noffH.initData.size, noffH.initData.inFileAddr); }

Initializing a Nachos Address Space

Zero out memory allocated Copy code segment to memory Copy initialized data segment to memory

slide-36
SLIDE 36

36

Compilation of halt.c

Test/halt.c: #include "syscall.h" main() { Halt(); /* not reached */ } … Halt: addiu $2,$0,SC_Halt syscall j $31 .end Halt main: …. jal Halt … gcc -S start.s has system call entries. System call number is always in register 2 halt.s: assembly code of halt.c Test/start.s

slide-37
SLIDE 37

5/14/2015 37

Nachos –x halt using halt.c in test directory

Interrupt-> Halt() In Interupt.cc Machine-> RaiseException(SyscallException) Machine->Run () in mipssim.cc ExceptionHandler(SyscallException) Machine-> OneInstruction()

slide-38
SLIDE 38

38

Code/userprog/exception.cc

ExceptionType Machine::Translate(int virtAddr, * physAddr, size, writing) { void ExceptionHandler(ExceptionType which) { int type = machine->ReadRegister(2); if ((which == SyscallException) && (type == SC_Halt)) { DEBUG('a', "Shutdown, initiated by user program.\n"); interrupt->Halt(); } } // Code Convention: // system call code -- r2 // arg1 -- r4, arg2 -- r5, arg3 -- r6, arg4 -- r7

slide-39
SLIDE 39

5/14/2015 39

Summary: actions of “nachos –x halt”

1.

The main thread starts by running function StartProcess() in file progtest.cc. This thread is used to run halt binary.

2.

StartProcess() allocates a new address space and loads the halt binary. It also initializes registers and sets up the page table.

3.

Call Machine::Run() to execute the halt binary using the MIPS emulator.

1.

The halt binary invokes the system call Halt(), which causes a trap back to the Nachos kernel via functions RaiseException() and ExceptionHandler().

4.

The exception handler determines that a Halt() system call was requested from user mode, and it halts Nachos.

slide-40
SLIDE 40

5/14/2015 40

Assignment 2: Multiprogramming&System Calls

Modify source code under userprog subdirectory.

 ~500-600 lines of code.

The crossplatform compiler is under ~cs170/gcc/.

 This compiler on x86 machines produces a.out with the coff

format.

 Use utility coff2noff (under nachos’ bin directory) to convert

it as Noff.

 Check the makefile under test subdirectory on how to use

gcc and coff2noff.

System calls to be implemented:

 Multiprogramming: Fork(), Yield(), Exit(), Exec() and Join().  File and console I/O: Creat(), Open(), Read(), Write(), and

Close().

slide-41
SLIDE 41

Multi-Processes and the Kernel

text data BSS user stack data

2n-1

Nachos kernel

2n-1

text data BSS user stack data text data BSS user stack data

Fork or Exec binary

slide-42
SLIDE 42

5/14/2015 42

To run multiple processes

Nachos should

 Provide the physical memory management;

 Fill memory with proper data, instruction.

 Set up an address translation table with

linear page tables;

 Save/restore address-space related state

during process switching (AddrSpace::SaveUserState() and AddrSpace:RestoreUserState() are called).

slide-43
SLIDE 43

43

Project 2: Files involved

Key files. (Red for modification/extension)

progtest.cc -- test routines to run user code.

addrspace.h addrspace.cc -- create an address space and load the program from disk.

syscall.h -- the system call interface.

exception.cc -- the handler for system calls and other user-level exceptions such as page faults.

filesys.h, openfile.h console.h -- interface to the Nachos file system and console (connected Linux file system)

Extension : pcb.cc, memorymanager.cc processmanager.cc,

  • penfilemanager.cc, useropenfile.cc

Other related files:

bitmap.h bitmap.cc -- manipulate bitmsps (useful for keeping track

  • f physical page frames).

translate.h, translate.cc -- translation tables.

machine.h, machine.cc -- emulates main memory, processor, etc.

mipsim.cc -- emulates MPIS R2/3000 instructions.

console.cc -- emulates a terminal using UNIX files.

slide-44
SLIDE 44

44

Project 2: Makefile flow

 make -C userprog

 userprog subdirectory. You expand here  Produce nachos which supports processes and

system calls

 make -C bin

 bin subdirectory. No change is needed  Produce programs that read Nachos binary code

format used by test program compilation

 make -C test

 test subdiretory. Add your test cases here  Produce MIPS binary code for test cases.  Executed as ../userprog/nachos –x binaryname

slide-45
SLIDE 45

45

Deadline

 Earlier submission of partial results for

2 bonus points

 May 3  Pass 1/3 of autograding tests

 Full submission

 May 12 (35 points)

slide-46
SLIDE 46

Project 2: Implementation Notes

Tao Yang

slide-47
SLIDE 47

Part I: Multiprogramming

 void Fork(func) creates a new user-level (child)

process, whose address space starts out as an exact copy of that of the caller (the parent),

 void Yield(): temporarily relinquish the CPU to

another process.

 void Exit( status) call takes a single argument, which

is an integer status value as in Unix. The currently executing process is terminated.

 SpaceID Exec(filename) spawns a new user-level

thread (process), but creates a new address space. It should return to the parent a SpaceId.

 int Join(ID) call waits and returns only after a process

with the specified space ID has finished. Return the exit code collected.

slide-48
SLIDE 48

Getting Started

Review syscall.h (under userprog directory).

Review start.cc (under test directory) which includes all system call stubs, following the style of Halt.

Modify ExceptionHandler() in exception.cc to include all system call entries.

 After each system call, increment PC registers so that

ExceptionHandler() execution flow returns back to next instruction after user’s system call place.

 counter = machine->ReadRegister(PCReg);  machine->WriteRegister(PrevPCReg,counter);  counter = counter + 4;

machine->WriteRegister(PCReg,counter);

 counter = counter + 4;

machine->WriteRegister(NextPCReg,counter);

 Arguments of a system call are in Registers 4, 5, 6 etc.

 how to verify? You may review MPIS assembly code

produced for a test C program using gcc with -S.

 If needed, return result is register 2

 machine->WriteRegister(2,result);

slide-49
SLIDE 49

Process Control Block (PCB)

Information associated with each process

 Process state  Program counter  CPU registers  CPU scheduling information  Memory-management information

 Page table

 Accounting information  I/O status information

slide-50
SLIDE 50

PCB (Process Control Block)

 Write the PCB and a process manager. Create a

PCB class that will store the necessary information about a process.

 To start, it should have a PID, parent PID, and kernel

ThreadID.

 pcb.h, pcb.cc

 The process manager-

 getPID and clearPID methods,

which return an unused process id and clear a process id.

 Maintain state, exit status, conditional waiting  processmanager.h, processmanager.cc.

slide-51
SLIDE 51

Diagram of Process State

slide-52
SLIDE 52

Memory Manager

 Write a Memory Manager that will be used to

facilitate memory allocation:

 Track memory page usage.  Allocate a page  Free a page  memorymanager.cc/memorymanager.h

 Modify AddrSpace:AddrSpace (addrspace.cc)

to use the memory manager.

 Modify the page table constructors to use pages

allocated by your memory manager

 Create a PCB (process control block) also for each

process to include key control information.

slide-53
SLIDE 53

Management of Free Pages

Before allocation After allocation Can use vector of bits to represent availability of each page 00110001110001101 … 110010 1allocated, 0free

slide-54
SLIDE 54

AddSpace.cc

 Write a function (e.g. AddrSpace::Translate),

which converts a virtual address to a physical

  • address. It does so by breaking the virtual

address into a page table index and an offset.

 Already in the harness code release

 Write a function( e.g. AddrSpace::ReadFile),

which loads the code and data segments into the translated memory, instead of at position 0.

 Read data into a system buffer (diskBuffer).  Copy buffered data into proper memory locations

(e.g. at machine->mainMemory[physAddr].)

slide-55
SLIDE 55

Address Translation for Paging

Logical address = logical page number + page offset Role of page table: logical page number  physical page number Physical address = physical page number + page offset

slide-56
SLIDE 56

How to Run User Processes Concurrently?

2n-1

text data BSS user stack data text data BSS user stack data text data BSS user stack data

2n-1

… Machine->run() … … Machine->run() … … Machine->run() …

Nachos Kernel Threads Main program Forked process Forked process binary

Create a Nachos kernel thread to manage each user process and execute its binary!

slide-57
SLIDE 57

Nachos system call Fork()

 Fork() creates a new process with a duplicated space

from parent, but executes a specific function.

 Not same definition as syscall.h  Difference compared to Linux fork()?

Func1(){ char *str = “Hello\n"; Write(str, 6, 1); } main(){ char *str = "Greetings from the parent!\n"; Fork(Func1); Write(str, 28, 1); } Hello Greetings from the parent!

slide-58
SLIDE 58

58

Compilation of a Fork program

#include "syscall.h“ Func1(){} main() { Fork(Func1); Fork(Func1); } Func1: … main: ... la $4, Func1 jal Fork … la $4, Func1 jal Fork … gcc -S Assembly code … Fork: addiu $2,$0,SC_Fork syscall j $31 .end Fork … System call number is in register 2. Argument 1 is in register 4 Test/start.s

slide-59
SLIDE 59

5/14/2015 59

Questions on Forking a Process

When to spawn a new kernel thread?

 Do we directly use thread fork function to execute

the binary of a child?

 Thread->Fork(Func1, NULL)?  Thread->Fork(Machine->Run, NULL)?

 Who needs to set the program counter for the new

process? Parent thread vs child thread?

Machine-> RaiseException(SyscallException) Machine->Run () in mipssim.cc ExceptionHandler(SyscallException) Machine-> OneInstruction()

slide-60
SLIDE 60

User Process and Nachos Kernel Threads

2n-1 2n-1

text data BSS user stack data … Machine->run() … ForkBridge { … Machine->run() … } ForkBridge { … Machine->run() … }

Nachos Kernel Threads Main program

text data BSS user stack data text data BSS user stack data

Forked process Forked process Thread fork binary

Spawn a thread which executes ForkBridge(). ForkBridge() manages each user process.

slide-61
SLIDE 61

Implement Fork() in ExceptionHandler()

1.

Func1 address is in register 4.

Target function to be executed in the new space.

2.

Create a new kernel thread.

3.

Create a new AddrSpace to be a duplicate

  • f the CurrentThread's space and get a new

PCB.

4.

The new thread runs a dummy function that creates a bridge for execution of the user function).

1.

Call NewThread->Fork(ForkBridge, Func1)

  • 5. The current thread calls Yield() so the new

thread can run.

slide-62
SLIDE 62

ForkBridge() : Key parts

 Set counter = Func1  Initialize and restore the registers. For

example,

 currentThread->RestoreUserState();  currentThread->space->RestoreState();  machine->WriteRegister(PCReg, counter);  machine->WriteRegister(PrevPCReg,counter-4);  machine->WriteRegister(NextPCReg,counter+4);

 Call machine->Run() which executes the

forked user process starting from the desired Func1 address.

slide-63
SLIDE 63

Nachos system call Exec()

 Exec() creates a new process with new code and

data segments from a file. Return the new address space ID.

 Only use the first argument.  Difference compared to Linux exec()?

main(){ char *str = "Greetings from the parent!\n"; Write(str, 28, 1); Exec("../test/hello“, 0,0,0); Write(str, 28, 1); } Greetings from the parent! Greetings from the parent!

slide-64
SLIDE 64

Implement Exec()

main(){ char *str = "Greetings from the parent!\n"; Write(str, 28, 1); Exec("../test/hello“, 0,0,0); }

2n-1 2n-1

text data BSS user stack data … Machine->run() …

Nachos Kernel Threads Main program

text data BSS user stack data

new process

ExecLauncher { … Machine->run() … }

Thread fork binary

slide-65
SLIDE 65

Implement Exec()

 Exec handler creates a new process from a file.

 Allocate a new address space which fits this file.

 Load data/code from an OpenFile object constructed

from the filename passed in by the user.

 In order to get that file name you will have to write a

function that copies over the string from user space.

 Allocate a new kernel thread and a PCB to execute

with the above space.

 Fork the new thread to run a dummy bridge function

that sets the machine registers straight and runs the code

 Call NewThread->Fork(execLauncher ,NULL);

 The calling thread should yield to give control to the

newly spawned thread.

 Return the space ID.

slide-66
SLIDE 66

Bridge function for Exec()

 Called execLanucher() in the released harness

code.

 Initialize registers/restore state.

 (currentThread->space)->InitRegisters();  (currentThread->space)->RestoreState();

 Machine->run();

slide-67
SLIDE 67

Nachos system call Yield()

 Current process gives up CPU and yields to another

process Func1(){ char *str = “Hello\n"; Yield(); Write(str, 6, 1); } main(){ char *str = "Greetings from the parent!\n"; Fork(Func1); Write(str, 28, 1); } Greetings from the parent! Hello

slide-68
SLIDE 68

CPU Switch From Process to Process

slide-69
SLIDE 69

Implement Yield(): Context Switch

 Save the current user process state.

 AddrSpace:SaveState()

 Current process state is READY.  Conduct the current kernel thread switch with thread yield.  When returns, restore

the user process restate

 AddrSpace:RestoreState()

Yield()

… Machine->run() …

Nachos Kernel Threads Process A Process B

Bridge{ … Machine->run() … }

Thread yield Two context switches involved

  • 1. Process context switch

Who saves/restores state?

  • 2. Kernel context switch

Who saves/restores state?

slide-70
SLIDE 70

5/14/2015

Key operations of Nachos’ function Thread::Yield()

SWITCH () in switch.s nextThread = scheduler->FindNextToRun(); if (nextThread != NULL) { scheduler->ReadyToRun(this); scheduler->Run(nextThread); } Restore current context. Save current context SWITCH() Thread:Yield()

slide-71
SLIDE 71

Nachos threads/scheduler:Run()

#ifdef USER_PROGRAM if (currentThread->space != NULL) { currentThread->SaveUserState(); currentThread->space->SaveState(); } #endif SWITCH(oldThread, nextThread); … #ifdef USER_PROGRAM if (currentThread->space != NULL) { currentThread->RestoreUserState(); currentThread->space->RestoreState(); } #endif

slide-72
SLIDE 72

Nachos system call int Join(SpaceId id)

 Wait until the completion of a specific process and

return exit code. int main() { int i, c, ret; for( i=0 ; i <1 ; ++i ) { c= Exec( “hello“,0,0,0 ); ret=Join(c); }

2n-1

… Machine->run() …

Nachos Kernel Threads Main program new process

ExecLauncher { … Machine->run() … }

Thread fork c=Exec() Join(c) Exit(0)

slide-73
SLIDE 73

Implement Join()

 If the child process already finishes, return its exit status

 Who maintains such info?

 Change the current process state as blocked  Call ProcessManager

for a conditional waiting.

 When waking up,

the current process state should be Running.

 Return the exit code

  • f child process.

Join()

… Machine->run() …

Nachos Kernel Threads Process A Process B

Bridge{ … Machine->run() … }

Thread yield

ProcessManager/PCB

slide-74
SLIDE 74

Nachos system call Exit (int code)

 Exit the current process and return the exit code

int main() { int i, c, ret; for( i=0 ; i <1 ; ++i ) { c= Exec( “hello“,0,0,0); ret=Join(c); }

2n-1

… Machine->run() …

Nachos Kernel Threads Main program new process

ExecLauncher { … Machine->run() … }

Thread fork c=Exec() Join(c) Exit(0)

slide-75
SLIDE 75

Implement Exit()

 Exit code is in register 4  Set the exit status of this process in PCB  Release resource allocated to this process

 Close files opened.

 Change the current process state as Terminated  Broadcast everybody

that I exit.

 Clear/release the address

space of this process.

 Clear/release the current

kernel thread threadFinish()

Join()

… Machine->run() …

Nachos Kernel Threads Process A Process B

Bridge{ … Machine->run() … }

Thread yield Exit(0)

ProcessManager

slide-76
SLIDE 76

Review of Linux System Calls for Files

 fileHandle = open(pathName, flags)

 fileHandle = creat(path, flags);

 errorCode = close(fileHandle)  byteCount = read(fileHandle, buf, count)  byteCount = write(fileHandle, buf, count)  position=lseek(fileHandle, offset, flag)

Re-position the offset of the current file location for next read/write.

Current offset count New offset

slide-77
SLIDE 77

What is the output content of tmpfile?

tmpfile Child Parent main() { int pid, fd; char *s1; fd = open("tmpfile", O_WRONLY | O_TRUNC | O_CREAT, 0666); pid = fork(); if (pid > 0) { sleep(1); /* Delay the parent by 1 second */ s1 = "Parent\n"; } else { s1 = "Child\n"; } write(fd, s1, strlen(s1)); close(fd); }

Create if it does not exist. Remove content if exist

slide-78
SLIDE 78

What is the output content of tmpfile?

tmpfile Parentt Child main() { int pid, fd; char *s1; pid = fork(); fd = open("tmpfile", O_WRONLY |O_CREAT, 0666); if (pid > 0) { sleep(1); /* Delay the parent by 1 second */ s1 = "Parentt"; } else { s1 = "Child"; } write(fd, s1, strlen(s1)); close(fd); }

slide-79
SLIDE 79

Nachos system calls for files

 void Create(char *name);  OpenFileId Open(char *name);  void Write(char *buffer, int size, OpenFileId id);  int Read(char *buffer, int size, OpenFileId id);  void Close(OpenFileId id);

New offset Current offset count

slide-80
SLIDE 80

System Calls for File System

 For the entire system, maintain a set of

  • bjects (SysOpenFile class) representing

system-wide opened files.

 Each file may be opened by many user processes.  Each file has filename, and offset for the current

read/write pointer

 Do parent/child processes share the same offset pointer?

 For create/Open/Read/Write, Nachos already

has a simple file system implemented

 Use FILESYS_STUB compiler directive  Directly

use Linux interface

 filesys.cc and openfile.cc under filesys directory

slide-81
SLIDE 81

Implement open()

 0, 1, 2 file descriptors are reserved for Linux

stdin, stdout, stderr.

 Make sure parent/child processes share files

  • pened before Fork(). Offset is shared.

 Use fileSystem->Open() (nachos’open) to

locate the file object.

 Add the opened file object to the system-

wide fileOpenTable.

 Keep track files opened for each process.

 Close them during Exit() as not all of them are

closed.

slide-82
SLIDE 82

Implement read()

 Allocate an internal buffer.  If Inputfile ID is ConsoleInput

 Then use getchar() and save data in the internal

buffer.

 Read until EOF or \n.

 Else, find the current read offset.

 Use openFile:ReadAt (defined in openfile.h) to

read data (essentially use Linux read())

 Copy data from the internal buffer to the

destination memory location.

 Need to copy one byte by one byte since the

address needs to be translated one by one.

How to deal the file offset shared between parent/child processes? How to deal with the file offset not shared?

slide-83
SLIDE 83

Implement write()

 Allocate an internal buffer.  Copy data from the source memory location

to the internal buffer.

 Need to copy one by one since the address needs

to be translated one by one.

 If Outputfile ID is ConsoleOutput

 Then use console output (essentially, printf

assuming string type).

 Else, find the current write offset.

 Use openFile:WriteAt (defined in openfile.h) to

write data to the Linux file.

How to deal the file offset shared between parent/child processes? How to deal with the file offset not shared?