Main Page   Compound List   File List   Compound Members   File Members  

disk.cc

Go to the documentation of this file.
00001 // disk.cc 
00002 //      Routines to simulate a physical disk device; reading and writing
00003 //      to the disk is simulated as reading and writing to a UNIX file.
00004 //      See disk.h for details about the behavior of disks (and
00005 //      therefore about the behavior of this simulation).
00006 //
00007 //      Disk operations are asynchronous, so we have to invoke an interrupt
00008 //      handler when the simulated operation completes.
00009 //
00010 //  DO NOT CHANGE -- part of the machine emulation
00011 //
00012 // Copyright (c) 1992-1993 The Regents of the University of California.
00013 // All rights reserved.  See copyright.h for copyright notice and limitation 
00014 // of liability and disclaimer of warranty provisions.
00015 
00016 #include "copyright.h"
00017 #include "disk.h"
00018 #include "system.h"
00019 
00020 // We put this at the front of the UNIX file representing the
00021 // disk, to make it less likely we will accidentally treat a useful file 
00022 // as a disk (which would probably trash the file's contents).
00023 #define MagicNumber     0x456789ab
00024 #define MagicSize       sizeof(int)
00025 
00026 #define DiskSize        (MagicSize + (NumSectors * SectorSize))
00027 
00028 // dummy procedure because we can't take a pointer of a member function
00029 static void DiskDone(int arg) { ((Disk *)arg)->HandleInterrupt(); }
00030 
00031 //----------------------------------------------------------------------
00032 // Disk::Disk()
00033 //      Initialize a simulated disk.  Open the UNIX file (creating it
00034 //      if it doesn't exist), and check the magic number to make sure it's 
00035 //      ok to treat it as Nachos disk storage.
00036 //
00037 //      "name" -- text name of the file simulating the Nachos disk
00038 //      "callWhenDone" -- interrupt handler to be called when disk read/write
00039 //         request completes
00040 //      "callArg" -- argument to pass the interrupt handler
00041 //----------------------------------------------------------------------
00042 
00043 Disk::Disk(char* name, VoidFunctionPtr callWhenDone, int callArg)
00044 {
00045     int magicNum;
00046     int tmp = 0;
00047 
00048     DEBUG('d', "Initializing the disk, 0x%x 0x%x\n", callWhenDone, callArg);
00049     handler = callWhenDone;
00050     handlerArg = callArg;
00051     lastSector = 0;
00052     bufferInit = 0;
00053     
00054     fileno = OpenForReadWrite(name, FALSE);
00055     if (fileno >= 0) {                  // file exists, check magic number 
00056         Read(fileno, (char *) &magicNum, MagicSize);
00057         ASSERT(magicNum == MagicNumber);
00058     } else {                            // file doesn't exist, create it
00059         fileno = OpenForWrite(name);
00060         magicNum = MagicNumber;  
00061         WriteFile(fileno, (char *) &magicNum, MagicSize); // write magic number
00062 
00063         // need to write at end of file, so that reads will not return EOF
00064         Lseek(fileno, DiskSize - sizeof(int), 0);       
00065         WriteFile(fileno, (char *)&tmp, sizeof(int));  
00066     }
00067     active = FALSE;
00068 }
00069 
00070 //----------------------------------------------------------------------
00071 // Disk::~Disk()
00072 //      Clean up disk simulation, by closing the UNIX file representing the
00073 //      disk.
00074 //----------------------------------------------------------------------
00075 
00076 Disk::~Disk()
00077 {
00078     Close(fileno);
00079 }
00080 
00081 //----------------------------------------------------------------------
00082 // Disk::PrintSector()
00083 //      Dump the data in a disk read/write request, for debugging.
00084 //----------------------------------------------------------------------
00085 
00086 static void
00087 PrintSector (bool writing, int sector, char *data)
00088 {
00089     int *p = (int *) data;
00090 
00091     if (writing)
00092         printf("Writing sector: %d\n", sector); 
00093     else
00094         printf("Reading sector: %d\n", sector); 
00095     for (unsigned int i = 0; i < (SectorSize/sizeof(int)); i++)
00096         printf("%x ", p[i]);
00097     printf("\n"); 
00098 }
00099 
00100 //----------------------------------------------------------------------
00101 // Disk::ReadRequest/WriteRequest
00102 //      Simulate a request to read/write a single disk sector
00103 //         Do the read/write immediately to the UNIX file
00104 //         Set up an interrupt handler to be called later,
00105 //            that will notify the caller when the simulator says
00106 //            the operation has completed.
00107 //
00108 //      Note that a disk only allows an entire sector to be read/written,
00109 //      not part of a sector.
00110 //
00111 //      "sectorNumber" -- the disk sector to read/write
00112 //      "data" -- the bytes to be written, the buffer to hold the incoming bytes
00113 //----------------------------------------------------------------------
00114 
00115 void
00116 Disk::ReadRequest(int sectorNumber, char* data)
00117 {
00118     int ticks = ComputeLatency(sectorNumber, FALSE);
00119 
00120     ASSERT(!active);                            // only one request at a time
00121     ASSERT((sectorNumber >= 0) && (sectorNumber < NumSectors));
00122     
00123     DEBUG('d', "Reading from sector %d\n", sectorNumber);
00124     Lseek(fileno, SectorSize * sectorNumber + MagicSize, 0);
00125     Read(fileno, data, SectorSize);
00126     if (DebugIsEnabled('d'))
00127         PrintSector(FALSE, sectorNumber, data);
00128     
00129     active = TRUE;
00130     UpdateLast(sectorNumber);
00131     stats->numDiskReads++;
00132     interrupt->Schedule(DiskDone, (int) this, ticks, DiskInt);
00133 }
00134 
00135 void
00136 Disk::WriteRequest(int sectorNumber, char* data)
00137 {
00138     int ticks = ComputeLatency(sectorNumber, TRUE);
00139 
00140     ASSERT(!active);
00141     ASSERT((sectorNumber >= 0) && (sectorNumber < NumSectors));
00142     
00143     DEBUG('d', "Writing to sector %d\n", sectorNumber);
00144     Lseek(fileno, SectorSize * sectorNumber + MagicSize, 0);
00145     WriteFile(fileno, data, SectorSize);
00146     if (DebugIsEnabled('d'))
00147         PrintSector(TRUE, sectorNumber, data);
00148     
00149     active = TRUE;
00150     UpdateLast(sectorNumber);
00151     stats->numDiskWrites++;
00152     interrupt->Schedule(DiskDone, (int) this, ticks, DiskInt);
00153 }
00154 
00155 //----------------------------------------------------------------------
00156 // Disk::HandleInterrupt()
00157 //      Called when it is time to invoke the disk interrupt handler,
00158 //      to tell the Nachos kernel that the disk request is done.
00159 //----------------------------------------------------------------------
00160 
00161 void
00162 Disk::HandleInterrupt ()
00163 { 
00164     active = FALSE;
00165     (*handler)(handlerArg);
00166 }
00167 
00168 //----------------------------------------------------------------------
00169 // Disk::TimeToSeek()
00170 //      Returns how long it will take to position the disk head over the correct
00171 //      track on the disk.  Since when we finish seeking, we are likely
00172 //      to be in the middle of a sector that is rotating past the head,
00173 //      we also return how long until the head is at the next sector boundary.
00174 //      
00175 //      Disk seeks at one track per SeekTime ticks (cf. stats.h)
00176 //      and rotates at one sector per RotationTime ticks
00177 //----------------------------------------------------------------------
00178 
00179 int
00180 Disk::TimeToSeek(int newSector, int *rotation) 
00181 {
00182     int newTrack = newSector / SectorsPerTrack;
00183     int oldTrack = lastSector / SectorsPerTrack;
00184     int seek = abs(newTrack - oldTrack) * SeekTime;
00185                                 // how long will seek take?
00186     int over = (stats->totalTicks + seek) % RotationTime; 
00187                                 // will we be in the middle of a sector when
00188                                 // we finish the seek?
00189 
00190     *rotation = 0;
00191     if (over > 0)               // if so, need to round up to next full sector
00192         *rotation = RotationTime - over;
00193     return seek;
00194 }
00195 
00196 //----------------------------------------------------------------------
00197 // Disk::ModuloDiff()
00198 //      Return number of sectors of rotational delay between target sector
00199 //      "to" and current sector position "from"
00200 //----------------------------------------------------------------------
00201 
00202 int 
00203 Disk::ModuloDiff(int to, int from)
00204 {
00205     int toOffset = to % SectorsPerTrack;
00206     int fromOffset = from % SectorsPerTrack;
00207 
00208     return ((toOffset - fromOffset) + SectorsPerTrack) % SectorsPerTrack;
00209 }
00210 
00211 //----------------------------------------------------------------------
00212 // Disk::ComputeLatency()
00213 //      Return how long will it take to read/write a disk sector, from
00214 //      the current position of the disk head.
00215 //
00216 //      Latency = seek time + rotational latency + transfer time
00217 //      Disk seeks at one track per SeekTime ticks (cf. stats.h)
00218 //      and rotates at one sector per RotationTime ticks
00219 //
00220 //      To find the rotational latency, we first must figure out where the 
00221 //      disk head will be after the seek (if any).  We then figure out
00222 //      how long it will take to rotate completely past newSector after 
00223 //      that point.
00224 //
00225 //      The disk also has a "track buffer"; the disk continuously reads
00226 //      the contents of the current disk track into the buffer.  This allows 
00227 //      read requests to the current track to be satisfied more quickly.
00228 //      The contents of the track buffer are discarded after every seek to 
00229 //      a new track.
00230 //----------------------------------------------------------------------
00231 
00232 int
00233 Disk::ComputeLatency(int newSector, bool writing)
00234 {
00235     int rotation;
00236     int seek = TimeToSeek(newSector, &rotation);
00237     int timeAfter = stats->totalTicks + seek + rotation;
00238 
00239 #ifndef NOTRACKBUF      // turn this on if you don't want the track buffer stuff
00240     // check if track buffer applies
00241     if ((writing == FALSE) && (seek == 0) 
00242                 && (((timeAfter - bufferInit) / RotationTime) 
00243                         > ModuloDiff(newSector, bufferInit / RotationTime))) {
00244         DEBUG('d', "Request latency = %d\n", RotationTime);
00245         return RotationTime; // time to transfer sector from the track buffer
00246     }
00247 #endif
00248 
00249     rotation += ModuloDiff(newSector, timeAfter / RotationTime) * RotationTime;
00250 
00251     DEBUG('d', "Request latency = %d\n", seek + rotation + RotationTime);
00252     return(seek + rotation + RotationTime);
00253 }
00254 
00255 //----------------------------------------------------------------------
00256 // Disk::UpdateLast
00257 //      Keep track of the most recently requested sector.  So we can know
00258 //      what is in the track buffer.
00259 //----------------------------------------------------------------------
00260 
00261 void
00262 Disk::UpdateLast(int newSector)
00263 {
00264     int rotate;
00265     int seek = TimeToSeek(newSector, &rotate);
00266     
00267     if (seek != 0)
00268         bufferInit = stats->totalTicks + seek + rotate;
00269     lastSector = newSector;
00270     DEBUG('d', "Updating last sector = %d, %d\n", lastSector, bufferInit);
00271 }

Generated on Mon Feb 10 09:54:45 2003 for nachos by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002
The University of Southern California does not screen or control the content on this website and thus does not guarantee the accuracy, integrity, or quality of such content. All content on this website is provided by and is the sole responsibility of the person from which such content originated, and such content does not necessarily reflect the opinions of the University administration or the Board of Trustees