// kernel.cc // Initialization and cleanup routines for the Nachos kernel. // // Copyright (c) 1992-1996 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 "debug.h" #include "main.h" #include "kernel.h" #include "sysdep.h" #include "synch.h" #include "synchlist.h" #include "libtest.h" #include "string.h" #include "synchdisk.h" #include "post.h" #include "synchconsole.h" //---------------------------------------------------------------------- // Kernel::Kernel // Interpret command line arguments in order to determine flags // for the initialization (see also comments in main.cc) //---------------------------------------------------------------------- Kernel::Kernel(int argc, char** argv) { randomSlice = FALSE; debugUserProg = FALSE; consoleIn = NULL; // default is stdin consoleOut = NULL; // default is stdout #ifndef FILESYS_STUB formatFlag = FALSE; #endif reliability = 1; // network reliability, default is 1.0 hostName = 0; // machine id, also UNIX socket name // 0 is the default machine id for (int i = 1; i < argc; i++) { if (strcmp(argv[i], "-rs") == 0) { ASSERT(i + 1 < argc); RandomInit(atoi(argv[i + 1]));// initialize pseudo-random // number generator randomSlice = TRUE; i++; } else if (strcmp(argv[i], "-s") == 0) { debugUserProg = TRUE; } // Todo ---- else if (strcmp(argv[i], "-e") == 0) { execfile[++execfileNum] = argv[++i]; cout << execfile[execfileNum] << "\n"; } 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) { ASSERT(i + 1 < argc); consoleOut = argv[i + 1]; i++; #ifndef FILESYS_STUB } else if (strcmp(argv[i], "-f") == 0) { formatFlag = TRUE; #endif } 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) { ASSERT(i + 1 < argc); // next argument is int hostName = atoi(argv[i + 1]); i++; } 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"; #ifndef FILESYS_STUB cout << "Partial usage: nachos [-nf]\n"; #endif cout << "Partial usage: nachos [-n #] [-m #]\n"; } } } //---------------------------------------------------------------------- // Kernel::Initialize // Initialize Nachos global data structures. Separate from the // constructor because some of these refer to earlier initialized // data via the "kernel" global variable. //---------------------------------------------------------------------- void Kernel::Initialize() { // We didn't explicitly allocate the current thread we are running in. // But if it ever tries to give up the CPU, we better have a Thread // object to save its state. currentThread = new Thread("main", threadNum++); currentThread->setStatus(RUNNING); stats = new Statistics(); // collect statistics interrupt = new Interrupt; // start up interrupt handling scheduler = new Scheduler(); // initialize the ready queue alarm = new Alarm(randomSlice); // start up time slicing machine = new Machine(debugUserProg); synchConsoleIn = new SynchConsoleInput(consoleIn); // input from stdin synchConsoleOut = new SynchConsoleOutput(consoleOut); // output to stdout synchDisk = new SynchDisk(); // #ifdef FILESYS_STUB fileSystem = new FileSystem(); #else fileSystem = new FileSystem(formatFlag); #endif // FILESYS_STUB // MP4 MODIFIED // postOfficeIn = new PostOfficeInput(10); // postOfficeOut = new PostOfficeOutput(reliability); frameTable = new FrameTable(); interrupt->Enable(); } //---------------------------------------------------------------------- // Kernel::~Kernel // Nachos is halting. De-allocate global data structures. //---------------------------------------------------------------------- Kernel::~Kernel() { delete stats; delete interrupt; delete scheduler; delete alarm; delete machine; delete synchConsoleIn; delete synchConsoleOut; delete synchDisk; delete fileSystem; // MP4 MODIFIED // delete postOfficeIn; // delete postOfficeOut; delete frameTable; Exit(0); } //---------------------------------------------------------------------- // Kernel::ThreadSelfTest // Test threads, semaphores, synchlists //---------------------------------------------------------------------- void Kernel::ThreadSelfTest() { Semaphore* semaphore; SynchList* synchList; LibSelfTest(); // test library routines currentThread->SelfTest(); // test thread switching // test semaphore operation semaphore = new Semaphore("test", 0); semaphore->SelfTest(); delete semaphore; // test locks, condition variables // using synchronized lists synchList = new SynchList; synchList->SelfTest(9); delete synchList; } //---------------------------------------------------------------------- // Kernel::ConsoleTest // Test the synchconsole //---------------------------------------------------------------------- void Kernel::ConsoleTest() { char ch; cout << "Testing the console device.\n" << "Typed characters will be echoed, until ^D is typed.\n" << "Note newlines are needed to flush input through UNIX.\n"; cout.flush(); do { ch = synchConsoleIn->GetChar(); if (ch != EOF) synchConsoleOut->PutChar(ch); // echo it! } while (ch != EOF); cout << "\n"; } //---------------------------------------------------------------------- // Kernel::NetworkTest // Test whether the post office is working. On machines #0 and #1, do: // // 1. send a message to the other machine at mail box #0 // 2. wait for the other machine's message to arrive (in our mailbox #0) // 3. send an acknowledgment for the other machine's message // 4. wait for an acknowledgement from the other machine to our // original message // // This test works best if each Nachos machine has its own window //---------------------------------------------------------------------- void Kernel::NetworkTest() { if (hostName == 0 || hostName == 1) { // if we're machine 1, send to 0 and vice versa int farHost = (hostName == 0 ? 1 : 0); PacketHeader outPktHdr, inPktHdr; MailHeader outMailHdr, inMailHdr; char* data = "Hello there!"; char* ack = "Got it!"; char buffer[MaxMailSize]; // construct packet, mail header for original message // To: destination machine, mailbox 0 // From: our machine, reply to: mailbox 1 outPktHdr.to = farHost; outMailHdr.to = 0; outMailHdr.from = 1; outMailHdr.length = strlen(data) + 1; // Send the first message postOfficeOut->Send(outPktHdr, outMailHdr, data); // Wait for the first message from the other machine postOfficeIn->Receive(0, &inPktHdr, &inMailHdr, buffer); cout << "Got: " << buffer << " : from " << inPktHdr.from << ", box " << inMailHdr.from << "\n"; cout.flush(); // Send acknowledgement to the other machine (using "reply to" mailbox // in the message that just arrived outPktHdr.to = inPktHdr.from; outMailHdr.to = inMailHdr.from; outMailHdr.length = strlen(ack) + 1; postOfficeOut->Send(outPktHdr, outMailHdr, ack); // Wait for the ack from the other machine to the first message we sent postOfficeIn->Receive(1, &inPktHdr, &inMailHdr, buffer); cout << "Got: " << buffer << " : from " << inPktHdr.from << ", box " << inMailHdr.from << "\n"; cout.flush(); } // Then we're done! } void ForkExecute(Thread* t) { if (!t->space->Load(t->getName())) { return; // executable not found } t->space->Execute(t->getName()); } void Kernel::ExecAll() { for (int i = 1;i <= execfileNum;i++) { int a = Exec(execfile[i], execPriority[i]); } currentThread->Finish(); //Kernel::Exec(); } // 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++; return threadNum - 1; /* cout << "Total threads number is " << execfileNum << endl; for (int n=1;n<=execfileNum;n++) { t[n] = new Thread(execfile[n]); t[n]->space = new AddrSpace(); t[n]->Fork((VoidFunctionPtr) &ForkExecute, (void *)t[n]); cout << "Thread " << execfile[n] << " is executing." << endl; } cout << "debug Kernel::Run finished.\n"; */ // Thread *t1 = new Thread(execfile[1]); // Thread *t1 = new Thread("../test/test1"); // Thread *t2 = new Thread("../test/test2"); // AddrSpace *halt = new AddrSpace(); // t1->space = new AddrSpace(); // t2->space = new AddrSpace(); // halt->Execute("../test/halt"); // t1->Fork((VoidFunctionPtr) &ForkExecute, (void *)t1); // t2->Fork((VoidFunctionPtr) &ForkExecute, (void *)t2); // currentThread->Finish(); // Kernel::Run(); // cout << "after ThreadedKernel:Run();" << endl; // unreachable } int Kernel::CreateFile(char* filename) { return fileSystem->Create(filename); }