diskdevice-model.c

来自「一个用在mips体系结构中的操作系统」· C语言 代码 · 共 1,659 行 · 第 1/4 页

C
1,659
字号
	fseek(ds->datafile, (long)(ds->firstSector * SECTOR_SIZE), SEEK_SET);	if (ds->reading)	  fread(buffer, (size_t)SECTOR_SIZE, xferSize, ds->datafile);	else {	    INVARIANT2(fwrite(buffer, (size_t)SECTOR_SIZE, xferSize, 			      ds->datafile) == xferSize,		       "DiskDeviceFinish: error while writing to data file\n");	}    }}/* @SUBTITLE "DiskDeviceShape: return the shape of the disk" *//* Return the shape of the disk. */void DiskDeviceShape(int disk, ulong *nSectors, ulong *sectorSize,		ulong *nTracks, ulong *sectorsPerTrack){    *nSectors = TOTAL_NSECTORS;    *sectorSize = SECTOR_SIZE;    *nTracks = NTRACKS;    *sectorsPerTrack = NSECTORS;}/* ======================================================================= *//* @SUBTITLE "DiskDeviceTransfer: a complete disk transaction" *//* Do a disk operation. We give it everything it needs to know: the disk * number, sector number on that disk, length in sectors, * a read/write flag, and the buffer for the data.    * This BLOCKS until the time when the transfer would be complete. */voidDiskDeviceTransfer(int disk, ulong sector, ulong nsectors,		   boolean write, UserData buffer){    TICS eventTime;    struct diskstatus *ds = &(dstatus[disk]);      /* check whether the caller of this function is insane */    SanityCheck(disk, sector, nsectors);      /* record the preceding idle period */    if (ds->finishTime > 0) { /* this disk has been used before */	SUM_ARRAY_METRIC(stats.diskidle, disk, 			 (GetTime() - ds->finishTime) * MSECperTIC);	INDEX_TIME_EVENT(EV_DISKIDLE, disk, 0, ds->finishTime);    }    /* record the event of reading or writing */    INDEX_EVENT(write ? EV_DISKWRITE : EV_DISKREAD, disk, sector);    SUM_ARRAY_METRIC(write ? stats.diskwrite : stats.diskread, disk, 1.0);    INDEX_EVENT(EV_DISKBUSY, disk, 0);      eventTime = GetTime();    ds->startTime = eventTime; /* start the disk */      DEBUG_TRACE(("DiskDeviceXfer \t%d\t@%s: sector:%lu  nsectors:%lu  R/W:%d\n",		 disk, time_print(eventTime), sector, nsectors, write));    /* only Controller() can change the values */    ds->newReading = !write;	    ds->newSector = sector;    /* go through all sectors */    ds->newLastSector = sector + nsectors - 1;    ds->newHaveBuffer = TRUE;    /* ask the controller to process the request */    DEBUG_TRACE(("\t"));    SendCommand(disk, eventTime);    DEBUG_TRACE(("\tDiskDeviceTransfer \t%d\t@%s  suspending %d/%d\n",		 disk, time_print(eventTime), CURR_PROCESSOR, MY_TID));    ds->wait_thread = MY_STID;    thread_suspend(MY_TID);   /* send the thread to sleep */    ds->finishTime = GetTime();    AVG_ARRAY_METRIC(stats.diskwait, disk, 		     (ds->finishTime - ds->startTime) * MSECperTIC);    STDDEV_ARRAY_METRIC(stats.diskwait_sd, stats.diskwait, disk, 			(ds->finishTime - ds->startTime) * MSECperTIC);    ds->startTime = NEVER;    /* reset the disk */    /* actually read and write the data to vdisk */    if (ds->datafile != NULL) {	fseek(ds->datafile, ((long) sector * SECTOR_SIZE), SEEK_SET);	if (ds->reading)	  fread(buffer, (size_t)SECTOR_SIZE, nsectors, ds->datafile);	else	  INVARIANT2(fwrite(buffer, (size_t)SECTOR_SIZE, nsectors, 			    ds->datafile) == nsectors,		     "DiskDeviceTransfer: error while writing to data file\n");    }}#ifndef SOLOstatic struct {    dmaRoutine_t dmaRoutine;    void *dmaArg;    doneRoutine_t doneRoutine;    int doneArg;} simosInterface[NO_OF_DISKS];PRIVATE voidFinishRequest(void *clientData){#ifdef SOLO   int disk = (int) clientData;#else    int disk = PTR_TO_UINT64(clientData);#endif    struct diskstatus *ds = &(dstatus[disk]);    ds->finishTime = GetTime();    AVG_ARRAY_METRIC(stats.diskwait, disk, 		     (ds->finishTime - ds->startTime) * MSECperTIC);    STDDEV_ARRAY_METRIC(stats.diskwait_sd, stats.diskwait, disk, 			(ds->finishTime - ds->startTime) * MSECperTIC);    ds->startTime = NEVER;    /* reset the disk */    simosInterface[disk].doneRoutine( simosInterface[disk].doneArg);}/* ======================================================================= *//* @SUBTITLE "DiskDeviceTransferStart: a complete disk transaction" *//* Do a disk operation. We give it everything it needs to know: the disk * number, sector number on that disk, length in sectors, * a read/write flag, and the buffer for the data.    */voidDiskDeviceTransferStart(int disk, ulong sector, ulong nsectors,  boolean write,        dmaRoutine_t dmaRoutine, void *dmaArg,        doneRoutine_t doneRoutine, int doneArg){    TICS eventTime;    struct diskstatus *ds = &(dstatus[disk]);      /* check whether the caller of this function is insane */    SanityCheck(disk, sector, nsectors);      /* record the preceding idle period */    if (ds->finishTime > 0) { /* this disk has been used before */	SUM_ARRAY_METRIC(stats.diskidle, disk, 			 (GetTime() - ds->finishTime) * MSECperTIC);	INDEX_TIME_EVENT(EV_DISKIDLE, disk, 0, ds->finishTime);    }    /* record the event of reading or writing */    INDEX_EVENT(write ? EV_DISKWRITE : EV_DISKREAD, disk, sector);    SUM_ARRAY_METRIC(write ? stats.diskwrite : stats.diskread, disk, 1.0);    INDEX_EVENT(EV_DISKBUSY, disk, 0);      eventTime = GetTime();    ds->startTime = eventTime; /* start the disk */      DEBUG_TRACE(("DiskDeviceXfer \t%d\t@%s: sector:%lu  nsectors:%lu  R/W:%d\n",		 disk, time_print(eventTime), sector, nsectors, write));    /* only Controller() can change the values */    ds->newReading = !write;	    ds->newSector = sector;    /* go through all sectors */    ds->newLastSector = sector + nsectors - 1;    ds->newHaveBuffer = TRUE;    /* ask the controller to process the request */    DEBUG_TRACE(("\t"));    SendCommand(disk, eventTime);    DEBUG_TRACE(("\tDiskDeviceTransfer \t%d\t@%s  suspending %d/%d\n",		 disk, time_print(eventTime), CURR_PROCESSOR, MY_TID));    simosInterface[disk].doneRoutine = doneRoutine;    simosInterface[disk].doneArg = doneArg;    simosInterface[disk].dmaRoutine = dmaRoutine;    simosInterface[disk].dmaArg = dmaArg;    ds->wait_thread = MY_STID;    thread_suspend_continue(MY_TID, FinishRequest, (void *)UINT_TO_PTRSIZE(disk));      /* send the thread to sleep */}#endif/* @SUBTITLE "DiskDeviceSync: Synchronizing the disk." *//* All the data in the disk cache is written to the disk before returning. */void DiskDeviceSync(int disk){    TICS eventTime;    struct diskstatus *ds = &(dstatus[disk]);    INVARIANT3(ds->startTime == NEVER,	       "DiskDeviceSync %d: previous DiskDeviceStart not finished!\n",	       disk);    DEBUG_TRACE(("DiskDeviceSync \t%d\n", disk));      eventTime = GetTime();    SendSyncCommand(disk, eventTime);    ds->wait_thread = MY_STID;    thread_suspend(MY_TID);   /* send the thread to sleep, SendDoneMessage				 wakes it up */}/* ======================================================================= *//* @SUBTITLE "SendCommand: send a command to the disk" *//* Called by DiskDeviceTransfer to send a command to the disk.  * It schedules an EndCommand() call in the future.  */PRIVATE voidSendCommand(int disk, TICS eventTime){    TICS grabTime = 0;	      /* time it took to grab the bus */    DEBUG_TRACE(("SendCommand\t%d\t@%s: nextDiskXfer = %lu\n", disk, 		 time_print(eventTime), dstatus[disk].nextDiskXfer));      if (GrabBus(disk, &grabTime, eventTime)) {       DDEventRequest(ENDCOMMAND, (eventTime + grabTime + COMMANDTIME_t),                       disk);       if (grabTime > 0) {          INDEX_TIME_EVENT(EV_BUSSTATE, dstatus[disk].busId, BUSSTATE_GRAB,                            eventTime);       }       INDEX_TIME_EVENT(EV_BUSSTATE, dstatus[disk].busId, BUSSTATE_COMMAND,                         eventTime + grabTime);    } else {       DEBUG_TRACE(("SendCommand:  Waiting for bus\n"));       WaitForBus(disk, SENDCOMMAND, eventTime);    }    }/* @SUBTITLE "EndCommand: end command xfer, start controller" *//* Scheduled by SendCommand() to end a command  * and schedule a Controller() event. */PRIVATE voidEndCommand(int disk, TICS eventTime){    struct diskstatus *ds = &(dstatus[disk]);       DEBUG_TRACE(("EndCommand\t%d\t@%s: nextDiskXfer = %lu\n", disk, 		 time_print(eventTime), ds->nextDiskXfer));      /* give the bus to the next event on the bus queue */    PassBus(disk, eventTime);    /* if command was sent by DiskDeviceStart, wake it up */    /* we can tell DiskDeviceStart sent command, if there is no buffer */    if (!ds->newHaveBuffer)      DDEventWakeup(disk,ds->wait_thread, eventTime);    /* start the controller */    Controller(disk, eventTime);}/* @SUBTITLE "Controller: examine new request and get disk going." *//* Scheduled by EndCommand() to start a disk * read or write operation and then go to sleep.   * Note that this function may be called twice in some requests; if the * previous request is a write that was immediately reported, and this * request does not extend it, we pause until that previous write completes * to disk; then the Controller is "restarted" to consider the new request. */PRIVATE voidController(int disk, TICS eventTime){    struct diskstatus *ds = &(dstatus[disk]);       ulong sector;    TICS endCtrllerTime;    boolean extendWrite = FALSE; /* can we extend the current write request? */    DEBUG_TRACE(("Controller\t%d\t@%s: nextDiskXfer = %lu  currentBusXfer:%lu\n",		 disk, time_print(eventTime), 		 ds->nextDiskXfer, ds->currentBusXfer));    INDEX_TIME_EVENT(EV_DISKSTATE, disk, DISKSTATE_CONTROL, eventTime);    if (ds->restartController == NEVER)      {	  if (ds->newReading)	    endCtrllerTime = eventTime + CTRLOVHDREAD_t;	  else	    endCtrllerTime = eventTime + CTRLOVHDWRITE_t;      }    else      endCtrllerTime = eventTime;    /* Check to see whether the current bus transfer is ahead of the       current disk transfer.  If TRUE, previous operation was an       immediate reported write.       If the incoming operation is a read or a non-connecting write, we       simply return and let the second call to Controller() deal with       it.  If the next operation is a sequential write, we extend the       write and continue.  */    if (ds->currentDiskXfer < ds->currentBusXfer)      {	  if (ds->newReading || (ds->newSector != ds->lastSector + 1))	    {		ds->restartController = endCtrllerTime;		DEBUG_TRACE(("\trestart Controller %d after @%s and EndDiskXfer\n", 			     disk, time_print(endCtrllerTime)))		  return;	    }	  else		      /* need to extend an immediate-reporting write */	    {		ds->restartController = NEVER;		extendWrite = TRUE;	    }      }     else		      /* no need to restart */      ds->restartController = NEVER;      sector = ds->firstSector = ds->newSector;    ds->lastSector = ds->newLastSector;    ds->reading = ds->newReading;	    ds->haveBuffer = ds->newHaveBuffer;      if (ds->reading)	      /* read */      {	  /* cache hit? */	  if (sector >= ds->firstCachedSector && sector < ds->nextDiskXfer)	    {		      /* cache hit */		SUM_ARRAY_METRIC(stats.diskhit, disk, 1.0);		ds->wantBus = endCtrllerTime; /* want to start transferring */		if (!ds->activeRead) {		    /* get prefetching started */		    DDEventRequest(DISKMOVE, endCtrllerTime, disk);		    ds->needMove = FALSE;		} else	      /* transfers continue in the background */		  INDEX_TIME_EVENT(EV_DISKSTATE, disk, 				   DISKSTATE_XFER, endCtrllerTime);	  		/* flush the cache up to that point */		ds->firstCachedSector = sector;		ds->nextBusXfer = ds->currentBusXfer = sector;		/* cache hit on ready item, can start transferring */		if (sector < ds->currentDiskXfer) 		  DDEventRequest(CONSIDERBUSXFER, endCtrllerTime, disk);	    }	  else	    {		      /* cache miss */		SUM_ARRAY_METRIC(stats.diskmiss, disk, 1.0);		/* reset (flush) the cache */		ds->firstCachedSector = sector;		ds->nextDiskXfer = ds->currentDiskXfer = sector;		ds->nextBusXfer = ds->currentBusXfer = sector;	  		ds->wantBus = endCtrllerTime;	  		if (ds->activeRead)		  {		      if (ds->prefetchReq == NULL)			ds->cancelPrefetch = TRUE;		      else			{			    DDEventCancel(ds->prefetchReq);			    ds->cancelPrefetch = FALSE;			    ds->activeRead = FALSE;			    ds->prefetchReq = NULL;			    /* move to new request */			    DDEventRequest(DISKMOVE, endCtrllerTime, disk); 			    ds->needMove = FALSE;			}		  }		else		  {		      DDEventRequest(DISKMOVE, endCtrllerTime, disk); 		      ds->needMove = FALSE;		  }	    }      }    else		      /* write */      {	  if (!extendWrite)	    {		SUM_ARRAY_METRIC(stats.diskmiss, disk, 1.0);		/* discard all cache only when we are not extending a write */		ds->firstCachedSector = sector;		ds->nextDiskXfer = ds->currentDiskXfer = sector;		ds->nextBusXfer = ds->currentBusXfer = sector;	  	  		if (ds->activeRead)		  {		      if (ds->prefetchReq == NULL)			ds->cancelPrefetch = TRUE;		      else			{			    DDEventCancel(ds->prefetchReq);			    ds->cancelPrefetch = FALSE;			    ds->activeRead = FALSE;			    ds->prefetchReq = NULL;			    /* move to new request */			    DDEventRequest(DISKMOVE, endCtrllerTime, disk); 			    ds->needMove = FALSE;			}		  }		else		  {		      DDEventRequest(DISKMOVE, endCtrllerTime, disk); 		      ds->needMove = FALSE;		  }	    }	  else {	      /* the transfer continues in the background */	      SUM_ARRAY_METRIC(stats.diskhit, disk, 1.0);	      /* We want to update firstCachedSector to be the same 	       * as the new request's firstSector, but we can't until the 	       * current request finishes.  To allow the bus xfer to go, 	       * we will allow firstCachedSector to track currentDiskXfer

⌨️ 快捷键说明

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