0% found this document useful (0 votes)
318 views27 pages

Nachos 2

Nachos is an educational operating system designed to simulate key components like multiprocessing, process management and console support. The document discusses adding these features to Nachos by describing how it currently only runs one user program at a time without process abstraction or console I/O. It explains the basic execution flow from Nachos starting a user program to it running on the simulated MIPS hardware. The goal is for Nachos to better resemble a true OS by supporting multiple concurrent processes and console functionality.

Uploaded by

Muntakim Sadik
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
318 views27 pages

Nachos 2

Nachos is an educational operating system designed to simulate key components like multiprocessing, process management and console support. The document discusses adding these features to Nachos by describing how it currently only runs one user program at a time without process abstraction or console I/O. It explains the basic execution flow from Nachos starting a user program to it running on the simulated MIPS hardware. The goal is for Nachos to better resemble a true OS by supporting multiple concurrent processes and console functionality.

Uploaded by

Muntakim Sadik
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 27

[NACHOS] MULTIPROGRAMMING, PROCESSMANAGEMENT ANDCONSOLE

January,2008

Md TanvirAlAmin
Nachos is an instructional operating system designed by Thomas Anderson at University of California, Berkeley. Originally written in

C++for MIPS, Nachos runs as a userprocess on a hostOS. Here, in this report we have discussed our work about adding multiprogrammingfacilityandconsolesupportinnachos3.4

[Nachos]Multiprogramming,Processmanagementandconsole

1[Nachos]Multiprogramming, Processmanagementandconsole
WHENNACHOSREALLYLOOKSLIKEANOPERATINGSYSTEM
We can do meaningful operations with Nachos at kernel level, without even thinking of any user. Thats exactly what we did for Threading and Synchronization assignment. Nachos was acting just as a thread packageScheduling,RunningandSwitchingbetweennonpreemptivekernelthreads. But, by definition, an operation system is to be a system organizer on behalf of the user, running in supervisormode,directlycommunicatingwithhardwareandpresentingsomelevelofabstraction[1][2].

1.1SOMEBACKGROUND
User Program and Its difference with Kernel
An user program is a sequence of instructions for a specific machine, which it can directly execute by loading in memory. Full instruction set of an architecture isnt available for a user program. To ensure safety, security and consistency of kernel data structures, certain memory locations and instructions are availabletothekernelonly,i.e.theyareavailableonlyinsupervisormode. Kernel runs in supervisor mode (or kernel mode) and as a manager for all resources available, it works on behalfoftheuser.Kernelloadsoneormanyofthoseuserprogramsinmemory,allocatesanddeallocates memory,registersandfreesupresources. There are two extreme ends in OS design. One is monolithic approach, and the another is microkernel based. In monolithic design, entire kernel is loaded as a single big program in single address space. Each partofitcanaccessotherpartsorvariablesandcancallanyfunctionresidingintheaddressspace.Ifthere is fatal bug in a single portion, the entire kernel is hooked up and we need to restart the machine. Monolithickernelisfast,andifwellwrittenandbugfreeisbestsuitedforperformance. On the other end is Microkernel. Just most necessary functions are part of kernel hence the name microkernel. And rest of the operations are written as services. Servers operate in user mode and one servercancommunicatewithanotherviamessagepassing.Thegoodpointisthatifanymodulesfail,the systemdoesnthangandjustrestartingthatserviceusuallysolvestheproblem.ThebadpointisthatThe good point comes only after a penalty paid in performance. Windows NT initially was designed with

Page1

[Nachos]Multiprogramming,Processmanagementandconsole

microkernel approach. Though it resulted in maintainable modular code, they eventually had to move mostofthepartstokerneltomakeitasuccessfulbusinessproduct. So we can understand, Kernel is what runs in supervisor mode, and all other is user programs [1]. Compilers, window managers, and utility programs packaged with a typical operating system are actually userprogramsthoughtheyarepartofsystemsoftware.SoalltheLinuxdistributionsarebasicallysame.If wedontalterthekernelcode,theydifferonlyinprovidedutilityprograms.

Transition of User mode and Kernel mode in Unix


Afterthesystembootsup,kerneldoessomemanagementtasks,createsandinitializesthedatastructures necessary. Unix based operating systems then create [3] Process 0 which runs in kernel mode. Process 0 forks and creates User mode Process called init(). Every other user programs are created by calling fork() copying parents address space. Record of parent child relationships are kept inside several kernel data structures.[3] When user process is let to run, the system is in user mode and kernel mode (or supervisor mode) is achievedonlyviatrapsorsystemcalls[6].Fordetailedstudy,pleasecheckouttheassociatedreferences.

1.2USINGUSERPROGRAMSINDEFAULTIMPLEMENTATIONINNACHOS
Nachosstartsupexecutionatmain()functioninthreads/main.cc.ThereareblocksforTHREADS, USER_PROGRAM,NETWORK,FILE_SYSTEMtests.Herewewillworkwithuserprogramtests.The defaultnachosimplementationcanjustrunasingleuserprogramspecifiedincommandline. Totestuserprogramswewillrunthehaltprogram.Itisintestdirectory.Wehavetoenteruserprog directoryandrunnachoslike cd userprog ./nachos x ../test/halt Thehalt.cprogramiswrittenas:
#include "syscall.h" int main() { Halt(); /* not reached */ }

Page2

[Nachos]Multiprogramming,Processmanagementandconsole

Commandsforcompilingthisuserprogramwhennachosiscompiledisincludedintestdirectorys Makefile,as
halt.o: halt.c $(CC) $(CFLAGS) -c halt.c halt: halt.o start.o $(LD) $(LDFLAGS) start.o halt.o -o halt.coff ../bin/coff2noff halt.coff halt

Ifwemodifyonlytheuserprogram,weneedtorecompileonlytheprogram,whichcanbedoneby executingcommandgmakewhileintestdirectory.Ifweexecutegmakefromnachosrootentiresource treewillbecompiledaccordingtotheMakefileineachdirectory. Thedefaultnachosimplementationonlytakesanargumentforthenameofuserprogramandrunsitina simplememorymodelandexits.Itneithersupportsmultiprogrammingforuserprograms,norhaveany processmanagementorconsolefunctionality.Well,thatisthetaskforNachosassignment2.

Note : The test directory contains many user programs. But with default implementation, only halt.c will work and the others will signal illegal operations, because those programs contains system calls and console writes which are not yet implemented. Only SC_Halt is implemented in userprog/exeception.cc

Page3

[Nachos]Multiprogramming,Processmanagementandconsole

1.3HOWNACHOSWORKSINUSERPROGRAMMODE
Ifxisspecified,main()functionin/threads/main.cclooksforauserprogramincommandline.Ifoneis foundStartProcess(.)iscalledtoexecutethatfile.Ifcisfoundconsoletestdemoruns. StartProcessisinuserprog/progtest.cc This function opens the executable file, creates an address space for it, attaches the address space with current Thread, initializes registers for the new user process and calls machine>Run() in machine/mipssim.cc.Creatingtheaddressspacemeansallocatingmemory,specifyingtest,dataandstack segments, loading instruction text in the text segment from NOFF format executable (NOFF = Nachos ObjectFileFormat).Formoredetailschecktheuserprog/addrspace.ccfile. Foreaseofchecking,importantlinesareshowninredboldinfollowingcodeblocks.Debugandroutine taskcodelinesaregrayed.
void StartProcess(char *filename) { OpenFile *executable = fileSystem->Open(filename); AddrSpace *space; if (executable == NULL) { printf("Unable to open file %s\n", filename); return; } space = new AddrSpace(executable); currentThread->space = space; delete executable; space->InitRegisters(); space->RestoreState(); machine->Run(); ASSERT(FALSE); } // close file // set the initial register values // load page table register // jump to the user progam // machine->Run never returns; // the address space exits // by doing the syscall "exit"

Machine::Run()ispartofMIPSsimulator. WhenMachine::Run()iscalled,weactuallyhavetheuserprogramrunning.(Tobeapurist,simulatingin theMIPSenvironmentcreated).Machine::Run()explicitlysetthemodeinUserModebycalling setStatus(UserMode).ThenittakesandexecuteseachinstructionviaOneInstruction,andsignalsaclock tick. Machine::OneInstructionwritteninmachine/mipssim.ccreallydoestheworkofadecode,execute,write backstageofaMIPSmachine.Checkthatfunctiontoseehowitactuallydoesit.


Page4

[Nachos]Multiprogramming,Processmanagementandconsole

Inrealsystem,thiswillbedonebyCPU,andclocktickwillbeoccurredbytherealtimeclockinhardware. Clockticksgenerateaclocktickinterrupt.Soinrealsystem,thiswillcausehardwaretrapandcause systemtoruninterrupthandlingcodewritteninspecialareaofmemory.Ontheotherhandinnachosthis willcausethesimulatedhardwaretoruncodesinInterrupt::OneTick().


void Machine::Run() { Instruction *instr = new Instruction;

// storage for decoded instruction

if(DebugIsEnabled('m')) printf("Starting thread \"%s\" at time %d\n", currentThread->getName(), stats->totalTicks); interrupt->setStatus(UserMode); for (;;) { OneInstruction(instr); interrupt->OneTick(); if (singleStep && (runUntilTime <= stats->totalTicks)) Debugger(); } }

void Interrupt::OneTick() { MachineStatus old = status; // advance simulated time if (status == SystemMode) { stats->totalTicks += SystemTick; stats->systemTicks += SystemTick; } else { // USER_PROGRAM stats->totalTicks += UserTick; stats->userTicks += UserTick; } DEBUG('i', "\n== Tick %d ==\n", stats->totalTicks); // check any pending interrupts are now ready to fire ChangeLevel(IntOn, IntOff); // first, turn off interrupts // (interrupt handlers run with // interrupts disabled) while (CheckIfDue(FALSE)) // check for pending interrupts ; ChangeLevel(IntOff, IntOn); // re-enable interrupts if (yieldOnReturn) { // if the timer device handler asked // for a context switch, ok to do it now yieldOnReturn = FALSE; status = SystemMode; // yield is a kernel routine currentThread->Yield(); status = old; } }

Page5

[Nachos]Multiprogramming,Processmanagementandconsole

As we can see where, there is a provision for Thread yield in Interrupt::OneTick. If rs switch is specified, threads areset to be subject to random switchingat defined points, then Interrupt::OneTick may switch a context.(Nachosdonthavetimeslicingimplemented). If current Thread is not yielded control again returns inside Machine::Run(), it fetches another instruction accordingtoPCviaregisters[PCReg] andexecutesit. Atthelastofuserprogramitcalls(automaticallyadded)theSC_Haltsystemcall.Thissystemcallismeant to do necessary process management (to be added by the student) and clean up tasks when a process terminates.

1.4NACHOSSYSTEMCALLS
Checkthefileuserprog/syscall.handyouwillfinddeclarationsfornachossystemcalls.
#define #define #define #define #define #define #define #define #define #define #define SC_Halt SC_Exit SC_Exec SC_Join SC_Create SC_Open SC_Read SC_Write SC_Close SC_Fork SC_Yield 0 1 2 3 4 5 6 7 8 9 10

Exceptionsorinterruptsarethewayauserprogramtakeservicefromkernel,i.ekernelwillrunoncontext oftheuserprogram.Whenauserprogramisrunningisusermode,thereisnowaytodirectlygotokernel mode. Rather every CPU provides special instructions to trap in Special places in memory, which contains interrupt/exception handlers not alterable by the user and control is returned to kernel code in kernel mode.Thissystemis forsecurity andconsistency.When asystem call occurs, a SyscallExceptionisRaised in MIPS [7]. For details on the actual MIPS cpu mechanism refer to the Computer Organization and Design booksbyHenessyandPatterson. CheckthefollowingredportioninsideMachine::OneInstruction()functioninmachine/mipssim.cc
case OP_SYSCALL: RaiseException(SyscallException, 0); return; case OP_XOR: registers[instr->rd] = registers[instr->rs] ^ registers[instr->rt]; break;

Page6

[Nachos]Multiprogramming,Processmanagementandconsole

Hint : Try to find why the OP_XOR case in has a break but OP_SYSCALL has a return . You should be able to find it out by yourself, when you understand the different types of exceptions that may occur and associated actions.

Machine::RaiseExceptionisinmachine/machine.cc RaiseException saves address of the exception creating instruction, changes to Kernel Mode and calls the ExceptionHandler (Interrupt Handlers for Intel 80X86 architectures), where control reappears as kernel mode. When returning from Handling the exception it again returns to UserMode again, as highlighted in violetinthecodeblockbelow.
void Machine::RaiseException(ExceptionType which, int badVAddr) { DEBUG('m', "Exception: %s\n", exceptionNames[which]); // ASSERT(interrupt->getStatus() == UserMode); registers[BadVAddrReg] = badVAddr; DelayedLoad(0, 0); // finish anything in progress interrupt->setStatus(SystemMode); ExceptionHandler(which); // interrupts are enabled at this point interrupt->setStatus(UserMode);

So we learn, basically this is the way control switches from the program running in user mode to kernel. Kernel will run in the context of that program. A running user program can return to kernel due to hardware interrupts, software exceptions, errors. Clock ticks are also hardware exceptions. In real hardware when a clock tick occurs, the clock tick exception handler take some scheduling decisions about ifacontextswitchistobedoneorwhethersomeprogrammoreeligiblefortheCPUiswaiting. A process is created or halted, a program asks for read or write operations, asks to spawn a thread or to join another thread, claims dynamic memory or resources or asks for some other operating system assistance everything is done via system calls, and these provide ample opportunity for the kernel to takecontrolback,dosometasksandreturntouseragain. ExceptionHandlerisinuserprog/exception.ccDefaultimplementationismeagerandimplementsonly SC_Halt,whichjusthaltsthemachine.AllothercallsaresignaledwithFalseAssertion.
void ExceptionHandler(ExceptionType which) { int type = machine->ReadRegister(2); if ((which == SyscallException) && (type == SC_Halt)) {

Page7

[Nachos]Multiprogramming,Processmanagementandconsole

DEBUG('a', "Shutdown, initiated by user program.\n"); interrupt->Halt(); } else { printf("Unexpected user mode exception %d %d\n", which, type); ASSERT(FALSE); } }

ForNachos2assignmentwehavetofillthisExceptionHandlerupforatleast5moreexceptions. ChecktheNachosPrimerdocument[4]fordetailsaboutNachosmachinesimulation.

Notes: When in actual hardware, implementing system calls requires a control transfer which involves some sort of architecture specific feature. A typical way to implement this is to use a software interrupt or trap. Interrupts transfer control to the kernel so software simply needs to set up some register with the system call number they want and execute the software interrupt. For MIPS there is a SYSCALL instruction. With Intel CPU, we can trap to kernel mode via INT instruction. Pentium II provides fast system call interface via SYSENTER and SYSEXIT instructions.

1.5NACHOSCONSOLE
Gotouserprogdirectory,andstartnachosas ./nachos c Nachosconsoledemo(ConsoleTestfunction)willstart,whichjustprintswhatuserhavewritten. ConsoleTestfunctionisinuserprog/progtest.cc.Itshowshowtoimplementandsynchronizeashared console,whentherearemultipleprocesses.

Page8

[Nachos]Multiprogramming,Processmanagementandconsole

1.6TASKSTOPERFORM
DefaultNachosexecutesuserprogramsonlyusingasimplememorymodel(checkaddrspace.cc),andonly one program can run at a time. We have to alter address space creation in such way so that multiprogramming is supported, and several user programs can reside in the provided memory and one program cant access other programs memory area (memory protection). Each user program will use its addressspaceasifitistheonlyprogramrunninginaFlatmodel(i.e.Memorymanagementwillbedoneby Nachos, not the user program). In short we have to implement page table based virtual memory scheme [1]tosupportmultiprogramming. UserprocessesaremeanttohaveprocessId.Oneuserprocesscancreateanotheruserprocess,sothereis a tree hierarchy. Parent can also wait for the child. We have to add support for process management, so that process parent child relationships are maintained in a data structure. Proper actions are taken for the casesparentexitsbeforechild,parentnevercallsjoinorparentcallsjoinandchildisalreadyexitedandso on. So we need to add classes and related functions so that process management is done when a user programcreated,exitsandJoinsotherprogram. To implement a fault free console for user i/o, we have to write synchronized console class. The ConsoleTestwillprovidecluesforasynchronizedconsole. Wehavetowritesystemcallhandlerssothatanewuserprogramcanbecreated(similartoforkinlinux, but not like the thread Fork of nachos), one process can wait for another and user program is supported with Read and Write operations. So in exception.cc, we have to write system calls handlers for SC_Exec, SC_Exit,SC_Write,SC_Read,SC_JoinsothatMultiprogramming,ConsoleI/OandProcessManagement issupported.CheckNachos2assignment[8]descriptionfordetailedspecification. In our implementation we also implemented PageFaultException handler so that swapping of memory pagesinandoutofswapspacewasalsosupported. Tocompletetheprojectsuccessfully,oneneedstohavesuccessfullyimplementedNachos1,Threadsand Synchronization Primitives. In this concept development stage, you are highly encouraged to study the source codes starting from main.cc to system.cc, interrupt.cc, scheduler.cc, machine.cc, mipssim.cc, list.cc, bitmap.cc, synchlist.cc, exception.cc, addrspace.cc, progtest.cc, synch.cc, thread.cc, translate.cc.Youwillalsoneedconsole.cclater.

Warning: Do not change any file in machine folder when programming. They are part of machine simulation and resembles the hardware. When we are to write an operating system, we cant change the hardware design, those are already fixed.

Page9

[Nachos]Mult tiprogramming,Processma anagementan ndconsole

2Tra ackingtheProje P ect


DEPENDENCYOFTASKS,WHICHONETODOWHEN

Whendoingthis W t projectwe w hadtowo orkiterativel lyorlikespir ral.Thingsar reinterrelate ed,soonetaskwasnt c complete insingle s pass.Here H ourpro ocessmodelis i described.Itmaynotbe b thebestmodel m tofollo ow,butit w worked fine for us. This s whole rep port also foll lows the fol llowing sequ uence. The numbers on n left are a associated se ections.

Prereq quisite:Unders standing gofThreadsan ndSynch hronizat tion

1Proce P essConc C ceptDev velop pment


3 Add A Mult M tiprogram mmin ng (S SC_E Exec, ,SC_ _Exit t,addrsp pace) ) 4Proces ss manag gement

Page10

5Cons C sole Man nagemen nt

ThoroughIntegrationTe ests

[Nachos]Multiprogramming,Processmanagementandconsole

3AddMultiprogramming
Defaultnachosprovidesexampleofrunninguseprogramthroughmonoprogramming[Refertosec1.3] Tocreatenewprocessfromanotherprocess,weneedtoinvokesystemcalls. SC_Execisthesystemcalltostartanewuserprocess. SC_Exitisthesystemcalltoexitauserprocess. Insection3.1and3.2weatfirstwritecodesforthesystemcallsSC_ExecandSC_Exitassuming monoprogramming.Butwecanteventesttheserightinthatform,becausecallingSC_Execmeans creatingauserprocessfromauserprocesswhichbydefinitionismultiprogramming.Insection3.3we addatypicalmemorymanagementformultiprogrammingsothatseveraluserprocesscanresideinmain memoryhencecompletethemultiprogrammingpart.

3.1SC_EXEC
Use Case
Fromuserprogramwewanttowritelike SpaceId myProcess; myProcess = Exec(../test/sort); Andthiswillexecutenoffformatbinaryfilesortresidingintestfolderasauserprocess.

Idea
Thebasicstepofworksneededforthisisdescribedin/userprog/progtest.cc,infunctionStartProcess (refertosection1.3ofthisdocument).Thisfunctioniscalledfrom.threads/main.ccwhenxisspecifiedas anoptionwhenrunningnachos.Sowhatweactuallyhavetodointhissectionistoportthiscodeasa systemcallhandlerin/userprog/exception.cc. Sostartlikethis(inside/userprog/exception.cc).
Void ExceptionHandler(ExceptionType which) { int type = machine->ReadRegister(2);

if (which == SyscallException) {

Page11

[Nachos]Multiprogramming,Processmanagementandconsole

switch(type) { case SC_Halt: { DEBUG('a', "Shutdown, initiated by user program.\n"); interrupt->Halt(); break; } case SC_Exec: { /* write code for handling Exec */ /* ----------------------------*/ /* be careful to on and off interrupts at proper places */ /* ----------------------------*/ /* return the process id for the newly created process, return value is to write at R2 */ Machine->WriteRegister(2, processed);

/* routine task do at last -- generally manipulate PCReg, PrevPCReg, NextPCReg so that they point to proper place*/ int pc; pc=machine->ReadRegister(PCReg); machine->WriteRegister(PrevPCReg,pc); pc=machine->ReadRegister(NextPCReg); machine->WriteRegister(PCReg,pc); pc += 4; machine->WriteRegister(NextPCReg,pc); } } } }

Guide : How to write code for handling Exec


StartProcessgetsexecutablefilenameasparameter(actuallythepointer).ForStartProcessthatpointeris insidekernelmemory,butforSC_Execthepointerisinsideusermemory.Sowehavetouse machine>ReadMemory(..)toreadthatlocation. MIPSSystemcallpassesparametersintoregistersr4,r5,r6,r7
Page12

[Nachos]Multiprogramming,Processmanagementandconsole

Togettheaddressofthefilename,wewrite
int buffadd = machine->ReadRegister(4); /* only one argument, so thats in R4 */

nextwereadthefilenameintokernelspace,usingReadMem. char *filename = new char[100];


//find a proper place to free this allocation if(!machine->ReadMem(buffadd,1,&ch))return; i=0; while( ch!=0 ) { filename[i]=(char)ch; bufadd+=1; i++; if(!machine->ReadMem(bufadd,1,&ch))return; } filename[i]=(char)0; /* now filename contains the file */

Nowwehavethefilename,andwecanopenit. Openit,asitisinStartProcess,calculatespaceneeded,createathread,allocateaddressspaceandload theexecutablefileintomemory(MonoprogrammingmodellikeStartProcess) AthreadisnotcreatedinStartProcess,andinfactitsnotnecessaryformonoprogramming,butaswe eventuallyaregoingtomakeitmultiprogramming,creatingaexecuteworkerthreadfortheprocess makesworkeasierforfuture.


OpenFile *executable = fileSystem->Open(filename); AddrSpace *space; space = new AddrSpace(executable); Thread * t = new Thread(tname); t->space = space; int processId = t->getId(); /* create this function by yourself */

Wealsohavetoforkthethreadtocreateakernellevelstack(userlevelstackiscreatedbyAddrSpace) andalsotoscheduleit,sothatthenewlycreateduserprocessruns. CheckStartProcessfunction.Therearesomeinitializationtasksabouttheregistersetandmachinestate whichneedstoconfiguredandrestoredeachtimeauserprocessexecutingthreadisscheduledoryield. whenanewprocessisstartedandisreadytorun.AsStartProcessdoesntcreatenewthreads,those


Page13

[Nachos]Multiprogramming,Processmanagementandconsole

initializationsarewritteninStartProcess.Buthereweareusingaseparatekernelthreadtoexecutethe process.Soweneedthoseinitializationsexactlywhenthatthreadisscheduled,andnotbeforeornot after. Createafunctioninsideexception.cc,sayforexample,processCreator,andforktheexecutorthreadwith thatfunction.t->Fork(processCreator,0); processCreatorcanlooklikethefollowingfunction,whichactuallydoessomeoftheinitializationtasks required(checkwhatisinStartProcessandwhichofthosearemovedtoprocessCreator)


void processCreator(int arg) { currentThread->space->InitRegisters(); currentThread->space->RestoreState(); machine->Run(); ASSERT(FALSE); }

// load page table register

// jump to the user progam // machine->Run never returns;

SowhenthethreadtisforkedwithprocessCreator,tisscheduled.Whentgetsachancetorunasakernel thread,itinitializesitsregistersetandstatesfortheuserprocess.AfterMachine::Runisexecuted,theuser processruns(themipssimulation). NowthebasiccodeforStartProcessisdone.Wedontbotheraboutprocessid,untilprocessmanagement isdone.ForthetimebeingjustkeepaprovisionofidinThreads,(maybewithastaticvariabletokeep trackofthreadscreated)andreturnthatasprocessid. Besuretoonandoffinterruptsatproperplaces.Besuretowritetheroutinetaskcodesupdating PCReg,NextPCRegandPrevPCReg.

Page14

[Nachos]Multiprogramming,Processmanagementandconsole

3.2SC_EXIT

Use Case
FromuserprogramwewillwritelikeExit(1); Andthissystemcallwillcauseoperatingsystemtodothecleanuptasksandmangeinternaldata structures.

Guide
Forthepurporseofthissection,wejustneedtofinishthecurrentthread,currentThread>Finish().Besure thatthecleanuptasksaredoneproperly.

3.3MEMORYMANAGEMENT
Whatwehavedonesofar,isjustpartofabigjob.Wehaventyetdoneanythingaboutmanaging memory. Severalprogramneedstoresideinmainmemory Oneprogramshouldnotbeabletoaccessanotherprogramsarea Thismemorymanagementshouldbetransparenttoeachuserprocess,i.ememoryshouldbe managedentirelybyoperatingsystemandhardware,userprocessshouldbeinvariantwhether thereisamultiprogrammingormonoprogramming.

Page Table
Hereweusepagetablebasedmemorymanagement.Eachprocesshasitsownaddressspace.Each processunderstandsandrealizesaddressesofitsownaddressspaceonly.Thepagetabletranslatesvirtual addresses(addressfromaprocessesownaddressspace)tophysicaladdress(actualaddressinphysical memoryaccessiblebykernelonly). Thememoryisdividedintoseveralfixedsizepages. At/machine/machine.hcheck
Page15

[Nachos]Multiprogramming,Processmanagementandconsole

#define PageSize SectorSize #define NumPhysPages 128

vpn# ppn# 1 2 3 4 1 3 1Process1Area 4 9 2Process2Area

Process#1PageTable vpn# 1 2 ppn# 2 7

3Process1Area 4Process1Area 5Process3Area 6Process3Area 7Process2Area 8Process3Area 9Process1Area 10Process3Area

Process#2PageTable vpn# 1 2 3 4 5 6 ppn# 5 6 8 10 11 12

11Process3Area 12Process3Area 13Unallocated 14Unallocated

PhysicalMemory

Process#3PageTable

Page16

[Nachos]Multiprogramming,Processmanagementandconsole

Check/machine/translate.cctoseehownachosMIPSsimulatortranslatesthevirtualaddressintophysical addresses. Weneedapagetableforeachprocess. Check/userprog/addrspace.ccand/userprog/addrspace.h.AnaddressspacewascreatedinsideSC_Exec handler.


AddrSpace::AddrSpace(OpenFile *executable) find
AddrSpace::AddrSpace(OpenFile *executable) { NoffHeader noffH; unsigned int i, size; executable->ReadAt((char *)&noffH, sizeof(noffH), 0); if ((noffH.noffMagic != NOFFMAGIC) && (WordToHost(noffH.noffMagic) == NOFFMAGIC)) SwapHeader(&noffH); ASSERT(noffH.noffMagic == NOFFMAGIC); // 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; //print the number of pages needs to allocated for this user process // printf("number of pages = %ud\n",numPages); ASSERT(numPages <= NumPhysPages); // check we're not trying // to run anything too big -// at least until we have // virtual memory DEBUG('a', "Initializing address space, num pages %d, size %d\n", numPages, size); // first, set up the translation 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; pageTable[i].use = FALSE; pageTable[i].dirty = FALSE; pageTable[i].readOnly = FALSE; // if the code segment was entirely on // a separate page, we could set its // pages to be read-only }

Page17

[Nachos]Multiprogramming,Processmanagementandconsole

// zero out the entire address space, to zero the unitialized data segment

// and the stack segment bzero(machine->mainMemory, size); // then, copy in the code and data segments into memory if (noffH.code.size > 0) {
DEBUG('a', "Initializing code segment, at 0x%x, size %d\n", noffH.code.virtualAddr, noffH.code.size); executable->ReadAt(&(machine->mainMemory[noffH.code.virtualAddr]), noffH.code.size, noffH.code.inFileAddr); } if (noffH.initData.size > 0) { DEBUG('a', "Initializing data segment, at 0x%x, size %d\n", noffH.initData.virtualAddr, noffH.initData.size); executable->ReadAt(&(machine->mainMemory[noffH.initData.virtualAddr]), noffH.initData.size, noffH.initData.inFileAddr); } }

AddrSpace::~AddrSpace() { delete pageTable; }


Redmarkedlinesneedspecialattentionandcorrectionformultiprogramming.
ASSERT(numPages <= NumPhysPages)

ThisassertionshouldbeonNumberofFreepagesremaining,ratherthantotalnumberofpages.
pageTable = new TranslationEntry[numPages];

Fine,theyhavemadethepagetableforus

pageTable[i].physicalPage = i;

Herevirtualpageisnolonger=physicalpage.Ratherweneedtofindafreepagetoassignforthat virtualpage.Alsoweshouldupdatethefreepagesdatastructuresothatthepagejustassignedisnot assignedtosomeotherprocessagainuntilitsfreed.


// zero out the entire address space,

bzero(machine->mainMemory, size); Thisistotallyfatalhere.Weneedtozerooutthepagesallocatedfortheprocess,nottheentire machine>mainMemory.Formonoprogrammingfullmainmemoryisallocatedto1program,soeachtime

Page18

[Nachos]Multiprogramming,Processmanagementandconsole

anewprogramisloaded,thatmemoryneedstobeinitialized.Butthisisnotthecasefor multiprogramming.Soweshouldcallbzeroonlyintheloop,foreachoftheindividualpagesallocated.
executable->ReadAt(&(machine->mainMemory[noffH.code.virtualAddr]), noffH.code.size, noffH.code.inFileAddr); executable->ReadAt(&(machine->mainMemory[noffH.initData.virtualAddr]), noffH.initData.size, noffH.initData.inFileAddr);

virtual addres no longer equals to physical address. And we need to translate noffH.code.virtualAddr to physical address explicitly here. We may need to write our own translation function because translate.cc translate function works on machine>pageTable, which is the pageTableofthecurrentprocess,buthereweareworkingwithadifferentprocess.

delete pageTable;

yes,wewilldeletepageTablewhenaddressspacedestructoriscalled,butbeforedoingthatweneedto updateourfreepagesmanagementdatastructure.i.ethepagesthatwereallocatedtotheprocessare freenow,andtheyshouldbeupdatedtosomedatastructuresothattheycanbeusedlater.

Keeping Track of Free Pages and Allocation of Pages


FreepagescanbetrackedeitherbyBitmapclassprovidedinNachos,orwithFreelistarray. Duringnachosbootupthisfreememorydatastructureneedstobeinitialized,andupdateisnecessary eachtimeanewprocessiscreatedordestroyed.

Page19

[Nachos]Multiprogramming,Processmanagementandconsole

4ProcessManagement
Unixmaintainsaparentchildhierarchyofprocesses.Wearetomaintainparentchildrelationshipof processesinNachos.Oneprocesscanjoinanotherprocess.Forsimplicity,here,onlyaparentcanwaitfor itschild. Inthischapterwe: 1. Createtheprocessclassandupdatethreadclass. 2. RevisitSC_Execandtherebycompleteit. 3. AddsystemcallSC_JoinandrevisitSC_Exit.

4.1PROCESSCLASS
Weneedtohaveaprocessclassforeachoftheprocess. Hereistheinterfaceofourprocessclass.
#ifndef PROCESS_H_ #define PROCESS_H_ #ifdef USER_PROGRAM #include "list.h" class Thread; enum ProcessStatus { PROCESS_JUST_CREATED, PROCESS_RUNNING, PROCESS_READY, PROCESS_BLOCKED, PROCESS_ZOMBIE };

class Process{ private: int processId; Process *parent; Thread *container; int nChildren; // number of child int exitCode; ProcessStatus status; List *children; List *waitqueue;

Page20

[Nachos]Multiprogramming,Processmanagementandconsole

public: Process(Thread *myExecutor,Process *myParent); Process *getParent() { return parent;} Thread *getThread() {return container;} int numberOfChildren(){return nChildren;} ProcessStatus getStatus() {return status;} void setStatus(ProcessStatus st) {status = st;} void void void void void addChild(Process *myChild); wakeUpJoiner(); exit(int ec); addJoiner(Process *joiner); deathOfChild(Process *p);

int getId() {return processId;} int getExitCode(){return exitCode;} void dumpChildInfo(); ~Process(); }; #endif #endif /*PROCESS_H_*/

Insidethead.hweupdatethefollowing(redmarked):
#ifdef USER_PROGRAM // A thread running a user program actually has *two* sets of CPU registers -// one for its state while executing user code, one for its state // while executing kernel code. int userRegisters[NumTotalRegs]; Process *userProcess; public: void SaveUserState(); void RestoreUserState(); AddrSpace *space; // user-level CPU register state

// save user-level register state // restore user-level register state // User code this thread is running.

void setProcess(Process *); Process *getProcess(void) {return userProcess;} #endif

ThethreadclassalsohaveauniqueIDgenerator,whichcreatesIDforeachthreadcreatorkeepingtrack viaastaticclassvariable.,andweusedsameIDforprocess,andreturnedasSpaceIDforSC_Execsystem call.


Page21

[Nachos]Multiprogramming,Processmanagementandconsole

4.2REVISITSC_EXEC
AnewprocessobjectiscreatedinsidehandlerofSC_Exec.(Redmarked) Tokeeptrackoftheprocesshierarchy,eachprocessobjectislinkedwithitsparentviaProcess *parent pointerinprocessclass,andparentsinformationispassedwhenthechildiscreated. Eachprocessalsohaveachildlist.Soparentprocessalsoattachesthechildwithitself(greenmarked).
Process *parentProcess=currentThread->getProcess(); Process *myProcess = new Process(t,parentProcess); parentProcess->addChild(myProcess);

Nowthequestionis,howdoweunderstand,currentThreadistheexecutoroftheparentoftheprocesswe aregoingtocreate?veryeasy,becausethiscodeisinsidethesystemcallSC_Exec,andwhenuserinvokes thissystemcallfromsomeuserprocess,thatprocessistheparent,andexecutorthreadofthatprocesswill actuallycometothesystemcallhandler,createthenewprocess,createthenewthreadanddootherjobs. InsideSC_Exit,weneedtheparenttodeattachitschild,changethechildsstatetozombieifparenthasnt exitedyet,checkfororphanedchildrenwhenaprocessexitsandothercleanuptasks.Butastheseare highlycorrelatedwithSC_Join,wediscusstheseatnextsection. WealsohaveaprovisionfortranslationbetweenprocessobjectandprocessIDeasily.Sowehavea translationtabledefinedin/threads/system.cc.Check/threads/system.ccandfindthatglobalobjectsare definedinthisfile.Insidesystem.ccwehave
#ifdef USER_PROGRAM SynchConsole *synchConsole; // visit this later List *processTranslationTable; Process *initProcess; Lock *pttLock; #endif

AlockisneededfortheprocessTranslationTable,becauseitisasharedobject. Wecreatetheseobjectsinsideinitializefunctionin/threads/system.cc
#ifdef USER_PROGRAM machine = new Machine(debugUserProg); // this must come first // <group 9> synchConsole = new SynchConsole (NULL, NULL); // visit this later processTranslationTable = new List; pttLock= new Lock("Process Translation Table Lock"); // </group 9>

Page22

[Nachos]Multiprogramming,Processmanagementandconsole

#endif

Insidethesystemcallhandler(SC_Exec)weupdatethesedatastructures:
pttLock->Acquire(); processTranslationTable->SortedInsert((void *)myProcess,myProcess->getId()); pttLock->Release();

AndInsideSC_Exitweupdatethesealso.ButasSC_ExitishighlycorrelatedwithSC_Join,wediscussit there.

4.3ADDSC_JOIN
Parentprocessalsocancalljoinonchild. Theusecasemaybelike:
newProc = Exec ( "../test/gchild" ) ; for(i=0;i<10;i++) j += i; Join ( newProc ) ;

Inthiscase,theparentprocesswillbeblockeduntilnewProcexits. Therearesomecomplicacieswhichneedstobesettledcarefully. Parentcallsjoin,butchildisalreadyfinished. Parentexits,buttherearechildprocessrunning,whowillbetheparentnow? InOurSolution,Forthefirstcase,theSC_Joinsystemcallwilljustreturn.Logicbehindthisis,parent processneedstobeblockeduntilchildexits.Aschildisalreadyexited,wecanthinkaboutitadelta(very small)block. Thesecondcasearrives,becausechildmanagementdatastructureswerecreatedbytheparent,theneed tobefreedbysomeappropriateAuthority.

Page23

[Nachos]Multiprogramming,Processmanagementandconsole

Whenchildfinishes,butparentisstillrunning,werenderthechildasZombie.Zombiestateisnecessary becausetheparentneedsanentryforcleanuptasks,returnvalueswhenitmaycalljoinetcetc.Ifchild processalongwiththeirdatastructuresaredeletedassoonastheyexits,wecantimplementjoin. ThatsawhywekeepinProcess.h


enum ProcessStatus { PROCESS_JUST_CREATED, PROCESS_RUNNING, PROCESS_READY, PROCESS_BLOCKED, PROCESS_ZOMBIE };

SystemcallhandlerforSC_Joinissimple. 1. ItatfirstacquiresthelockforProcessTranslationTableandsearchesthejoineeIDthereandgets ProcesspointerforthatID. 2. ItthencheckswhethercallingwiththejoineeIDisvalid. 3. Assumingvalid,itcheckswhetherthejoineealreadyexited(ZombieState) a. Ifzombie,thenitgetstheexitcodestoredintheprocessstructureforthatchild b. Ifnotzombie,thencurrentthreadsleeps(currentthreadisthethreadforthecalling process) 4. Oninvalidcalls,1isreturned. Nottomentionherethatthesystemcallhandleratfirstdoestheroutinetask(settingcorrectvalues PCReg,NextPCReg,PrevPCReg) NowthatwekeptaZombiestate.Zombiestatemeansthechildisfunctionallydead,butithasstillthe entryinitsparentschildlist.Nowwhenthisentrywillbedeleted?Easy,whentheparentexits. SowenowcheckthehandlerforSC_Exit 1. Theprocessismarkedaszombie 2. Iftherearejoinerfortheprocess,itisawaken.(interruptsoff) 3. NowweneedtocareaboutthechildrenithasForallchildcinchild_list i. Ifcisazombieprocess(thischildexitedbeforetheparentandnowweare accessingitsundeletedentries),deleteitfromprocessTranslationtableandalso deletetheprocessobject.(butdontdeleteitfromthelinkedlistrightnow) ii. Ifcisnotazombieprocess,itisstillrunning.Weassignadummyprocessname initProcess,whichisjustaprocessanddoesnothing. 4. Deletefromchildlistlinkedlistallthezombiechilds. 5. IfthecurrentprocesssparentisinitProcess,itmeansthisprocesslostitsparentpreviouslyand nowhasadummyasaparent,whichisnotgoingtoexit.Sointhatcasetheprocessitselfdeletes itsdatastructures.
Page24

[Nachos]Multiprogramming,Processmanagementandconsole

5ConsoleManagement
Sorrythischapterwillbeavailableonnextiteration.

Page25

[Nachos]Multiprogramming,Processmanagementandconsole

References
[1] [2] [3] [4] [5] [6] [7] [8] [9] ModernOperatingSystems,AndrewSTanenbaum OperatingSystemConcepts,Silberchatz,Galvin,Gagne TheDesignofUnixOperatingSystem(Chapter6,7)MauriceJBach TheNachosPrimer,MatthewPeters,RobertHill,ShyamPather ARoadmaptoNachos,ThomasNarten UnderstandingtheLinuxKernel,Section1.6.DanielP.Bovet,MarcoCesati ComputerOrganizationandDesign,Patterson,Henessy. Nachos2AssignmentDescription,Md.SohrabHossain,KhaledMahmudShahriar,Md.Moazzem Hossain,ChowdhurySayeedHayder,DepartmentofComputerScienceandEngineering,BUET. Nachos1AssignmentReportGroup9,SukarnaBarua,TanvirAlAminPopel(Level3Term2,July 2007Term,DepartmentofComputerScienceandEngineering,BUET.

Page26

You might also like