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

📄 interrupt.cc

📁 美国加州大学操作系统课程实验平台Nachos
💻 CC
字号:
// interrupt.cc //	Routines to simulate hardware interrupts.////	The hardware provides a routine (SetLevel) to enable or disable//	interrupts.////	In order to emulate the hardware, we need to keep track of all//	interrupts the hardware devices would cause, and when they//	are supposed to occur.  ////	This module also keeps track of simulated time.  Time advances//	only when the following occur: //		interrupts are re-enabled//		a user instruction is executed//		there is nothing in the ready queue////  DO NOT CHANGE -- part of the machine emulation//// 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 "interrupt.h"#include "main.h"// String definitions for debugging messagesstatic char *intLevelNames[] = { "off", "on"};static char *intTypeNames[] = { "timer", "disk", "console write", 			"console read", "network send", 			"network recv"};//----------------------------------------------------------------------// PendingInterrupt::PendingInterrupt// 	Initialize a hardware device interrupt that is to be scheduled //	to occur in the near future.////	"callOnInt" is the object to call when the interrupt occurs//	"time" is when (in simulated time) the interrupt is to occur//	"kind" is the hardware device that generated the interrupt//----------------------------------------------------------------------PendingInterrupt::PendingInterrupt(CallBackObj *callOnInt, 					int time, IntType kind){    callOnInterrupt = callOnInt;    when = time;    type = kind;}//----------------------------------------------------------------------// PendingCompare//	Compare to interrupts based on which should occur first.//----------------------------------------------------------------------static intPendingCompare (PendingInterrupt *x, PendingInterrupt *y){    if (x->when < y->when) { return -1; }    else if (x->when > y->when) { return 1; }    else { return 0; }}//----------------------------------------------------------------------// Interrupt::Interrupt// 	Initialize the simulation of hardware device interrupts.//	//	Interrupts start disabled, with no interrupts pending, etc.//----------------------------------------------------------------------Interrupt::Interrupt(){    level = IntOff;    pending = new SortedList<PendingInterrupt *>(PendingCompare);    inHandler = FALSE;    yieldOnReturn = FALSE;    status = SystemMode;}//----------------------------------------------------------------------// Interrupt::~Interrupt// 	De-allocate the data structures needed by the interrupt simulation.//----------------------------------------------------------------------Interrupt::~Interrupt(){    while (!pending->IsEmpty()) {	delete pending->RemoveFront();    }    delete pending;}//----------------------------------------------------------------------// Interrupt::ChangeLevel// 	Change interrupts to be enabled or disabled, without advancing //	the simulated time (normally, enabling interrupts advances the time).////	Used internally.////	"old" -- the old interrupt status//	"now" -- the new interrupt status//----------------------------------------------------------------------voidInterrupt::ChangeLevel(IntStatus old, IntStatus now){    level = now;    DEBUG(dbgInt, "\tinterrupts: " << intLevelNames[old] << " -> " << intLevelNames[now]);}//----------------------------------------------------------------------// Interrupt::SetLevel// 	Change interrupts to be enabled or disabled, and if interrupts//	are being enabled, advance simulated time by calling OneTick().//// Returns://	The old interrupt status.// Parameters://	"now" -- the new interrupt status//----------------------------------------------------------------------IntStatusInterrupt::SetLevel(IntStatus now){    IntStatus old = level;        // interrupt handlers are prohibited from enabling interrupts    ASSERT((now == IntOff) || (inHandler == FALSE));    ChangeLevel(old, now);			// change to new state    if ((now == IntOn) && (old == IntOff)) {	OneTick();				// advance simulated time    }    return old;}//----------------------------------------------------------------------// Interrupt::OneTick// 	Advance simulated time and check if there are any pending //	interrupts to be called. ////	Two things can cause OneTick to be called://		interrupts are re-enabled//		a user instruction is executed//----------------------------------------------------------------------voidInterrupt::OneTick(){    MachineStatus oldStatus = status;    Statistics *stats = kernel->stats;// advance simulated time    if (status == SystemMode) {        stats->totalTicks += SystemTick;	stats->systemTicks += SystemTick;    } else {	stats->totalTicks += UserTick;	stats->userTicks += UserTick;    }    DEBUG(dbgInt, "== Tick " << stats->totalTicks << " ==");// check any pending interrupts are now ready to fire    ChangeLevel(IntOn, IntOff);	// first, turn off interrupts				// (interrupt handlers run with				// interrupts disabled)    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	kernel->currentThread->Yield();	status = oldStatus;    }}//----------------------------------------------------------------------// Interrupt::YieldOnReturn// 	Called from within an interrupt handler, to cause a context switch//	(for example, on a time slice) in the interrupted thread,//	when the handler returns.////	We can't do the context switch here, because that would switch//	out the interrupt handler, and we want to switch out the //	interrupted thread.//----------------------------------------------------------------------voidInterrupt::YieldOnReturn(){     ASSERT(inHandler == TRUE);      yieldOnReturn = TRUE; }//----------------------------------------------------------------------// Interrupt::Idle// 	Routine called when there is nothing in the ready queue.////	Since something has to be running in order to put a thread//	on the ready queue, the only thing to do is to advance //	simulated time until the next scheduled hardware interrupt.////	If there are no pending interrupts, stop.  There's nothing//	more for us to do.//----------------------------------------------------------------------voidInterrupt::Idle(){    DEBUG(dbgInt, "Machine idling; checking for interrupts.");    status = IdleMode;    if (CheckIfDue(TRUE)) {	// check for any pending interrupts	status = SystemMode;	return;			// return in case there's now				// a runnable thread    }    // if there are no pending interrupts, and nothing is on the ready    // queue, it is time to stop.   If the console or the network is     // operating, there are *always* pending interrupts, so this code    // is not reached.  Instead, the halt must be invoked by the user program.    DEBUG(dbgInt, "Machine idle.  No interrupts to do.");    cout << "No threads ready or runnable, and no pending interrupts.\n";    cout << "Assuming the program completed.\n";    Halt();}//----------------------------------------------------------------------// Interrupt::Halt// 	Shut down Nachos cleanly, printing out performance statistics.//----------------------------------------------------------------------voidInterrupt::Halt(){    cout << "Machine halting!\n\n";    kernel->stats->Print();    delete kernel;	// Never returns.}//----------------------------------------------------------------------// Interrupt::Schedule// 	Arrange for the CPU to be interrupted when simulated time//	reaches "now + when".////	Implementation: just put it on a sorted list.////	NOTE: the Nachos kernel should not call this routine directly.//	Instead, it is only called by the hardware device simulators.////	"toCall" is the object to call when the interrupt occurs//	"fromNow" is how far in the future (in simulated time) the //		 interrupt is to occur//	"type" is the hardware device that generated the interrupt//----------------------------------------------------------------------voidInterrupt::Schedule(CallBackObj *toCall, int fromNow, IntType type){    int when = kernel->stats->totalTicks + fromNow;    PendingInterrupt *toOccur = new PendingInterrupt(toCall, when, type);    DEBUG(dbgInt, "Scheduling interrupt handler the " << intTypeNames[type] << " at time = " << when);    ASSERT(fromNow > 0);    pending->Insert(toOccur);}//----------------------------------------------------------------------// Interrupt::CheckIfDue// 	Check if any interrupts are scheduled to occur, and if so, //	fire them off.//// Returns://	TRUE, if we fired off any interrupt handlers// Params://	"advanceClock" -- if TRUE, there is nothing in the ready queue,//		so we should simply advance the clock to when the next //		pending interrupt would occur (if any).//----------------------------------------------------------------------boolInterrupt::CheckIfDue(bool advanceClock){    PendingInterrupt *next;    Statistics *stats = kernel->stats;    ASSERT(level == IntOff);		// interrupts need to be disabled,					// to invoke an interrupt handler    if (debug->IsEnabled(dbgInt)) {	DumpState();    }    if (pending->IsEmpty()) {   	// no pending interrupts	return FALSE;	    }		    next = pending->Front();    if (next->when > stats->totalTicks) {        if (!advanceClock) {		// not time yet            return FALSE;        }        else {      		// advance the clock to next interrupt	    stats->idleTicks += (next->when - stats->totalTicks);	    stats->totalTicks = next->when;	    // UDelay(1000L); // rcgood - to stop nachos from spinning.	}    }    DEBUG(dbgInt, "Invoking interrupt handler for the ");    DEBUG(dbgInt, intTypeNames[next->type] << " at time " << next->when);    if (kernel->machine != NULL) {    	kernel->machine->DelayedLoad(0, 0);    }    inHandler = TRUE;    do {        next = pending->RemoveFront();    // pull interrupt off list        next->callOnInterrupt->CallBack();// call the interrupt handler	delete next;    } while (!pending->IsEmpty()     		&& (pending->Front()->when <= stats->totalTicks));    inHandler = FALSE;    return TRUE;}//----------------------------------------------------------------------// PrintPending// 	Print information about an interrupt that is scheduled to occur.//	When, where, why, etc.//----------------------------------------------------------------------static voidPrintPending (PendingInterrupt *pending){    cout << "Interrupt handler "<< intTypeNames[pending->type];    cout << ", scheduled at " << pending->when;}//----------------------------------------------------------------------// DumpState// 	Print the complete interrupt state - the status, and all interrupts//	that are scheduled to occur in the future.//----------------------------------------------------------------------voidInterrupt::DumpState(){    cout << "Time: " << kernel->stats->totalTicks;    cout << ", interrupts " << intLevelNames[level] << "\n";    cout << "Pending interrupts:\n";    pending->Apply(PrintPending);    cout << "\nEnd of pending interrupts\n";}

⌨️ 快捷键说明

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