📄 disk.cc
字号:
// disk.cc // Routines to simulate a physical disk device; reading and writing// to the disk is simulated as reading and writing to a UNIX file.// See disk.h for details about the behavior of disks (and// therefore about the behavior of this simulation).//// Disk operations are asynchronous, so we have to invoke an interrupt// handler when the simulated operation completes.//// DO NOT CHANGE -- part of the machine emulation//// 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 "disk.h"#include "debug.h"#include "sysdep.h"#include "main.h"// We put a magic number at the front of the UNIX file representing the// disk, to make it less likely we will accidentally treat a useful file // as a disk (which would probably trash the file's contents).const int MagicNumber = 0x456789ab;const int MagicSize = sizeof(int);const int DiskSize = (MagicSize + (NumSectors * SectorSize));//----------------------------------------------------------------------// Disk::Disk()// Initialize a simulated disk. Open the UNIX file (creating it// if it doesn't exist), and check the magic number to make sure it's // ok to treat it as Nachos disk storage.//// "toCall" -- object to call when disk read/write request completes//----------------------------------------------------------------------Disk::Disk(CallBackObj *toCall){ int magicNum; int tmp = 0; DEBUG(dbgDisk, "Initializing the disk."); callWhenDone = toCall; lastSector = 0; bufferInit = 0; sprintf(diskname,"DISK_%d",kernel->hostName); fileno = OpenForReadWrite(diskname, FALSE); if (fileno >= 0) { // file exists, check magic number Read(fileno, (char *) &magicNum, MagicSize); ASSERT(magicNum == MagicNumber); } else { // file doesn't exist, create it fileno = OpenForWrite(diskname); magicNum = MagicNumber; WriteFile(fileno, (char *) &magicNum, MagicSize); // write magic number // need to write at end of file, so that reads will not return EOF Lseek(fileno, DiskSize - sizeof(int), 0); WriteFile(fileno, (char *)&tmp, sizeof(int)); } active = FALSE;}//----------------------------------------------------------------------// Disk::~Disk()// Clean up disk simulation, by closing the UNIX file representing the// disk.//----------------------------------------------------------------------Disk::~Disk(){ Close(fileno);}//----------------------------------------------------------------------// Disk::PrintSector()// Dump the data in a disk read/write request, for debugging.//----------------------------------------------------------------------static voidPrintSector (bool writing, int sector, char *data){ int *p = (int *) data; if (writing) cout << "Writing sector: " << sector << "\n"; else cout << "Reading sector: " << sector << "\n"; for (unsigned int i = 0; i < (SectorSize/sizeof(int)); i++) { cout << p[i] << " "; } cout << "\n"; }//----------------------------------------------------------------------// Disk::ReadRequest/WriteRequest// Simulate a request to read/write a single disk sector// Do the read/write immediately to the UNIX file// Set up an interrupt handler to be called later,// that will notify the caller when the simulator says// the operation has completed.//// Note that a disk only allows an entire sector to be read/written,// not part of a sector.//// "sectorNumber" -- the disk sector to read/write// "data" -- the bytes to be written, the buffer to hold the incoming bytes//----------------------------------------------------------------------voidDisk::ReadRequest(int sectorNumber, char* data){ int ticks = ComputeLatency(sectorNumber, FALSE); ASSERT(!active); // only one request at a time ASSERT((sectorNumber >= 0) && (sectorNumber < NumSectors)); DEBUG(dbgDisk, "Reading from sector " << sectorNumber); Lseek(fileno, SectorSize * sectorNumber + MagicSize, 0); Read(fileno, data, SectorSize); if (debug->IsEnabled('d')) PrintSector(FALSE, sectorNumber, data); active = TRUE; UpdateLast(sectorNumber); kernel->stats->numDiskReads++; kernel->interrupt->Schedule(this, ticks, DiskInt);}voidDisk::WriteRequest(int sectorNumber, char* data){ int ticks = ComputeLatency(sectorNumber, TRUE); ASSERT(!active); ASSERT((sectorNumber >= 0) && (sectorNumber < NumSectors)); DEBUG(dbgDisk, "Writing to sector " << sectorNumber); Lseek(fileno, SectorSize * sectorNumber + MagicSize, 0); WriteFile(fileno, data, SectorSize); if (debug->IsEnabled('d')) PrintSector(TRUE, sectorNumber, data); active = TRUE; UpdateLast(sectorNumber); kernel->stats->numDiskWrites++; kernel->interrupt->Schedule(this, ticks, DiskInt);}//----------------------------------------------------------------------// Disk::CallBack()// Called by the machine simulation when the disk interrupt occurs.//----------------------------------------------------------------------voidDisk::CallBack (){ active = FALSE; callWhenDone->CallBack();}//----------------------------------------------------------------------// Disk::TimeToSeek()// Returns how long it will take to position the disk head over the correct// track on the disk. Since when we finish seeking, we are likely// to be in the middle of a sector that is rotating past the head,// we also return how long until the head is at the next sector boundary.// // Disk seeks at one track per SeekTime ticks (cf. stats.h)// and rotates at one sector per RotationTime ticks//----------------------------------------------------------------------intDisk::TimeToSeek(int newSector, int *rotation) { int newTrack = newSector / SectorsPerTrack; int oldTrack = lastSector / SectorsPerTrack; int seek = abs(newTrack - oldTrack) * SeekTime; // how long will seek take? int over = (kernel->stats->totalTicks + seek) % RotationTime; // will we be in the middle of a sector when // we finish the seek? *rotation = 0; if (over > 0) // if so, need to round up to next full sector *rotation = RotationTime - over; return seek;}//----------------------------------------------------------------------// Disk::ModuloDiff()// Return number of sectors of rotational delay between target sector// "to" and current sector position "from"//----------------------------------------------------------------------int Disk::ModuloDiff(int to, int from){ int toOffset = to % SectorsPerTrack; int fromOffset = from % SectorsPerTrack; return ((toOffset - fromOffset) + SectorsPerTrack) % SectorsPerTrack;}//----------------------------------------------------------------------// Disk::ComputeLatency()// Return how long will it take to read/write a disk sector, from// the current position of the disk head.//// Latency = seek time + rotational latency + transfer time// Disk seeks at one track per SeekTime ticks (cf. stats.h)// and rotates at one sector per RotationTime ticks//// To find the rotational latency, we first must figure out where the // disk head will be after the seek (if any). We then figure out// how long it will take to rotate completely past newSector after // that point.//// The disk also has a "track buffer"; the disk continuously reads// the contents of the current disk track into the buffer. This allows // read requests to the current track to be satisfied more quickly.// The contents of the track buffer are discarded after every seek to // a new track.//----------------------------------------------------------------------intDisk::ComputeLatency(int newSector, bool writing){ int rotation; int seek = TimeToSeek(newSector, &rotation); int timeAfter = kernel->stats->totalTicks + seek + rotation;#ifndef NOTRACKBUF // turn this on if you don't want the track buffer stuff // check if track buffer applies if ((writing == FALSE) && (seek == 0) && (((timeAfter - bufferInit) / RotationTime) > ModuloDiff(newSector, bufferInit / RotationTime))) { DEBUG(dbgDisk, "Request latency = " << RotationTime); return RotationTime; // time to transfer sector from the track buffer }#endif rotation += ModuloDiff(newSector, timeAfter / RotationTime) * RotationTime; DEBUG(dbgDisk, "Request latency = " << (seek + rotation + RotationTime)); return(seek + rotation + RotationTime);}//----------------------------------------------------------------------// Disk::UpdateLast// Keep track of the most recently requested sector. So we can know// what is in the track buffer.//----------------------------------------------------------------------voidDisk::UpdateLast(int newSector){ int rotate; int seek = TimeToSeek(newSector, &rotate); if (seek != 0) bufferInit = kernel->stats->totalTicks + seek + rotate; lastSector = newSector; DEBUG(dbgDisk, "Updating last sector = " << lastSector << " , " << bufferInit);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -