Page principale | Hiérarchie des classes | Liste des classes | Répertoires | Liste des fichiers | Membres de classe | Membres de fichier

disk.cc

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

Généré le Sun Jan 15 00:44:24 2006 pour Architecture Cible de NachOS : par  doxygen 1.4.4