⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 exception.cpp

📁 LINUX 下NACHOS 系统的页面调度算法的实现
💻 CPP
字号:
// exception.cc //	Entry point into the Nachos kernel from user programs.//	There are two kinds of things that can cause control to//	transfer back to here from user code:////	syscall -- The user code explicitly requests to call a procedure//	in the Nachos kernel.  Right now, the only function we support is//	"Halt".////	exceptions -- The user code does something that the CPU can't handle.//	For instance, accessing memory that doesn't exist, arithmetic errors,//	etc.  ////	Interrupts (which can also cause control to transfer from user//	code into the Nachos kernel) are handled elsewhere.//// For now, this only handles the Halt() system call.// Everything else core dumps.//// Copyright (c) 1992-1993 The Regents of the University of California.// All rights reserved.  See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions.#include "copyright.h"#include "system.h"#include "syscall.h"#include "machine.h"#include "addrspace.h"#include "exception.h"extern void MPTest(int);extern void StartProcess(char *file);static void updatePCReg(void);static void initConsole(void);static void loadExecutable (Thread *, int addr);static void startThread();//----------------------------------------------------------------------// ExceptionHandler// 	Entry point into the Nachos kernel.  Called when a user program//	is executing, and either does a syscall, or generates an addressing//	or arithmetic exception.////// 	For system calls, the following is the calling convention://// 	system call code -- r2//		arg1 -- r4//		arg2 -- r5//		arg3 -- r6//		arg4 -- r7////	The result of the system call, if any, must be put back into r2. //// And don't forget to increment the pc before returning. (Or else you'll// loop making the same system call forever!////	"which" is the kind of exception.  The list of possible exceptions //	are in machine.h.//----------------------------------------------------------------------voidExceptionHandler(ExceptionType which){  int type = machine->ReadRegister(2);  initConsole();//-----------------------------------------------------------------------  // Exception Handler handles system calls from a user program// The following system calls have been implemented:// 1.Halt()  halt the "NACHOS" system!!// 2.Exit()  exit from the current user process, i.e kill it// 3.Exec()  create a new process and execute it// 4.Write() for writing text into a file// 5.Read() for reading from a file// 6.Join() for resuming after an Exec() call//-----------------------------------------------------------------------  if ((which == SyscallException) && (type == SC_Halt)) {    DEBUG('a', "Shutdown, initiated by user program.\n");    delete console;    delete writeLock;    delete readAvail;    delete writeDone;    interrupt->Halt();  }   else if((which == SyscallException) && (type == SC_Exit))   {      int exitStatus = machine->ReadRegister(4);      DEBUG('t', "Program exiting on status %d...\n", exitStatus);      machine->WriteRegister(2,exitStatus);      updatePCReg();      DEBUG('t',"Current Joinvalue  %d\n",joinInvoked);      threadsIn--;      int findThread = 0;      if ( joinInvoked != 0)      {	  while (currentThread != joinThreadList.threadExecuting[findThread])	     findThread++;	  joinThreadList.threadExecuting[findThread] = (Thread *)NULL;	  DEBUG('t',"Thread sending Broadcast is %d\n",findThread);	  joinThreadList.completeThread[findThread]->Broadcast	      (joinThreadList.completeLock[findThread]);	  statusReturned[findThread] = exitStatus;	  DEBUG('t', "Status Returned When Waking %d\n",	      statusReturned[findThread]);      }      DEBUG('t',"Current thread completing  %d\n",findThread);      threadComplete[findThread] = 1;      DEBUG('t',"Current Joinvalue  %d\n",joinInvoked);            // releasing memory      //delete currentThread->space;      currentThread->Finish();  }  else if ((which == SyscallException) && (type == SC_Exec))  {      int addr = (int)machine->ReadRegister(4);      updatePCReg();      threadsIn++;      Thread * execThread = new Thread("execThread");      joinThreadList.threadExecuting[numThreadsExec] = execThread;      joinThreadList.completeThread[numThreadsExec] = 	new  Condition("New Thread Executing");      threadComplete[numThreadsExec] = 0;      DEBUG('t',"Executing a child thread...\n");      DEBUG('t',"The thread id is %d\n", numThreadsExec);      machine->WriteRegister(2, numThreadsExec);      numThreadsExec ++;      loadExecutable(execThread, addr);            execThread->Fork((VoidFunctionPtr)startThread,addr);  }  else if ((which == SyscallException) && (type == SC_Join))  {        int addr = (int)machine->ReadRegister(4);       DEBUG('a',"The joining wait is on  %d\n",addr);      updatePCReg();      joinThreadList.completeLock[addr] = new Lock("Dummy Lock");      joinThreadList.completeLock[addr]->Acquire();      IntStatus oldLevel = interrupt->SetLevel(IntOff);      if ((threadToBeDestroyed != joinThreadList.threadExecuting[addr])	  || (threadComplete[addr] == 0))      {	  joinInvoked++;	    DEBUG('a',"New Joinvalue after ++ %d\n",joinInvoked);	  joinThreadList.completeThread[addr]->Wait              (joinThreadList.completeLock[addr]);	  joinInvoked--;	  DEBUG('a',"New Joinvalue after -- %d\n",joinInvoked);      }      (void) interrupt->SetLevel(oldLevel);      joinThreadList.completeLock[addr]->Release();      machine->WriteRegister(2,statusReturned[addr]);      DEBUG('a', "Status Returned after Waking %d\n",statusReturned[addr]);      DEBUG('a',"The thread woken up is %d\n",addr);  }        else if((which == SyscallException) && (type == SC_Write))  {      int addr  = (int)machine->ReadRegister(4);      int Size = (int)machine->ReadRegister(5);      OpenFileId writeHandle = (int)machine->ReadRegister(6);      ASSERT(writeHandle == ConsoleOutput);      DEBUG('a', "Address of buffer %d\n", addr);      DEBUG('a', "Size of buffer %d\n",Size );      char buffer[Size+1];      int oneChar, i=0;        // Transfer buffer content from user space to kernel space      machine->ReadMem(addr, 1, &oneChar);           while((i <Size) && (oneChar != '\0'))      {            buffer[i] = oneChar;	  machine->ReadMem(++addr, 1, &oneChar);	  i++;      }      buffer[i] = 0;      Size = i;      i = 0;      while (buffer[i] != 0 && i < Size)       {	  IntStatus oldLevel = interrupt->SetLevel(IntOff);	  writeLock->Acquire();          // wait for write process to be done	  console->PutChar(buffer[i++]);          writeDone->P();          (void) interrupt->SetLevel(oldLevel);          writeLock->Release();      }      updatePCReg();  }  else if((which == SyscallException) && (type == SC_TestCase)) {    updatePCReg();    // run with interrupts off, just in case:    IntStatus oldLevel = interrupt->SetLevel(IntOff);    TestCase(machine->ReadRegister(4));     (void) interrupt->SetLevel(oldLevel);  }  else if (which == PageFaultException)   {    stats->numPageFaults++;    int BadVPage=(machine->ReadRegister(BadVAddrReg)/PageSize);    machine->memManager->PageFaultExceptionHandler(BadVPage);  }  else if (which == IllegalInstrException)   {    printf("Illegal Instruction: EXITING...\n");    currentThread->Finish();  }  #ifdef CHANGE  else  {     printf("Unkown Exception.\n");     interrupt->Halt();  }  #endif} //-----------------------------------------------------------------// Updating the Program Counter before returning to the User mode// ensures that the "SYSCALL" instruction is not executed forever.// Don't use this for page faults, because you want to retry the// faulting instruction, not skip it!//-----------------------------------------------------------------void updatePCReg(void){  int pc = machine->ReadRegister(PCReg);  machine->WriteRegister(PrevPCReg,pc);  pc = machine->ReadRegister(NextPCReg);  machine->WriteRegister(PCReg,pc);  pc += 4;  machine->WriteRegister(NextPCReg,pc);}// This initialization should only be done once.void initConsole(void){  static int Initialized = 0;    if (Initialized == 0) {      Initialized = 1;       readAvail = new Semaphore("readAvail", 0);      writeDone = new Semaphore("writeDone", 0);      writeLock = new Lock("writeLock");      console = new Console((char *) NULL, (char *) NULL,          ReadAvail, WriteDone, 0);  }}// This code is for the Exec call, to do error checking and load the// executable file into memory.void loadExecutable(Thread *execThread, int addr){  char filename[20];  int fileptr, i = 0;   for (int ckm = 0; ckm < 20; ckm ++)       filename[ckm]='\0';   DEBUG('t',"Physical page now free %d\n", machine->memManager->memAvail());  DEBUG('t',"The address of filename is %d\n",addr);   machine->ReadMem(addr, 1, &fileptr);  while((char)fileptr != '\0')  {      filename[i] = (char)fileptr;      addr++;      machine->ReadMem(addr, 1,&fileptr);      i++;  }  filename[i] = '\0';  DEBUG('t',"Filename to execute.. %s\n",filename);  OpenFile *executable = fileSystem->Open(filename);   if (executable == NULL) {      printf("Unable to open file %s\n", filename);      return;  }  AddrSpace *space = new AddrSpace(executable);  execThread->space = space;}// Use Thread::Fork to call this; it starts the child running the program// for the exec call.void startThread(){    currentThread->space->InitRegisters(); // set the initial register values    currentThread->space->RestoreState();  // load page table register     machine->Run();                     // jump to the user progam    ASSERT(FALSE);                      // machine->Run never returns;                                        // the address space exits                                        // by doing the syscall "exit"}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -