diskdevice-model.c

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

C
1,659
字号
	       * until it hits firstSector (see also EndDiskXfer).	       */	      ds->firstCachedSector = (ulong)                 min(ds->currentDiskXfer, ds->firstSector);	      INDEX_TIME_EVENT(EV_DISKSTATE, disk, 			       DISKSTATE_XFER, endCtrllerTime);	  }	  ds->wantBus = endCtrllerTime;	  DDEventRequest(CONSIDERBUSXFER, endCtrllerTime, disk);      }}/* @SUBTITLE "SendBufferMesg: Give a buffer to the Controller()" *//* Give a buffer to the Controller() so that disk transfers can take place */PRIVATE voidSendBufferMesg(int disk, TICS eventTime){    TICS grabTime = 0;	      /* time it took to grab the bus */      DEBUG_TRACE(("SendBufferMesg\t%d\t@%s: nextDiskXfer = %lu\n", disk, 		 time_print(eventTime), dstatus[disk].nextDiskXfer));      if (GrabBus(disk, &grabTime, eventTime)) {       DDEventRequest(ENDBUFFERMESG, (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(("SendBufferMesg:  Waiting for bus\n"));       WaitForBus(disk, SENDBUFFERMESG, eventTime);    }    }/* @SUBTITLE "EndBufferMesg:  Finish sending the buffer" */ /* Finish sending the buffer and consider a bus transfer. */PRIVATE voidEndBufferMesg(int disk, TICS eventTime){    struct diskstatus *ds = &(dstatus[disk]);       DEBUG_TRACE(("EndBufferMesg\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);    ds->haveBuffer = TRUE;      /* If the controller is not waiting for disk transfer to finish,       we can now consider a bus transfer */    if (ds->restartController == NEVER)      {	  DEBUG_TRACE(("\t"));	  ConsiderBusXfer(disk, eventTime);       }}/* @SUBTITLE "SendSyncCommand:  ask disk to sync" *//* Scheduled by DiskDriverSync() to synchronize the disk. */PRIVATE voidSendSyncCommand(int disk, TICS eventTime){    TICS grabTime = 0;	      /* time it took to grab the bus */      DEBUG_TRACE(("SendSyncCommand\t%d\t@%s: nextDiskXfer = %lu\n", disk, 		 time_print(eventTime), dstatus[disk].nextDiskXfer));    if (GrabBus(disk, &grabTime, eventTime)) {       DDEventRequest(ENDSYNCCOMMAND,                      (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(("SendSyncCommand:  Waiting for bus\n"));       WaitForBus(disk, SENDSYNCCOMMAND, eventTime);    }    }/* @SUBTITLE "EndSyncCommand: set flag to wakeup when disk done" *//* Scheduled by SendSyncCommand() to synchronize * the disk by setting a flag so EndDiskXfer can wake * the DiskDriverSync up.  */PRIVATE voidEndSyncCommand(int disk, TICS eventTime){    struct diskstatus *ds = &(dstatus[disk]);     DEBUG_TRACE(("EndSyncCommand\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);    /* only set sync flag when we have outstanding disk operations */    if (ds->currentDiskXfer < ds-> currentBusXfer)      {	  ds->wantSync = TRUE;	  DEBUG_TRACE(("\tdisk %d want last EndDiskXfer to SendDoneMessage\n", 		       disk));      }    else      {	  ds->wantSync = FALSE;	  /* done syncing coz we didn't have to sync in the first place */	  DDEventRequest(SENDDONEMESSAGE, eventTime, disk);       }}/* @SUBTITLE "DiskMove: move disk head before disk xfer" *//* Compute the time to move the disk head, then schedule StartDiskXfer at * the move-completion time. */PRIVATE voidDiskMove(int disk, TICS eventTime){    struct diskstatus *ds = &(dstatus[disk]);      TICS endMoveTime;      endMoveTime = MoveTime_t(disk, ds->nextDiskXfer, eventTime);      ds->activeRead = ds->reading; /* so we know a StartDiskXfer is coming */    DEBUG_TRACE(("DiskMove \t%d\t@%s: nextDiskXfer = %lu\n", disk, 		 time_print(eventTime), ds->nextDiskXfer));    DDEventRequest(STARTDISKXFER, endMoveTime, disk);    INDEX_TIME_EVENT(EV_DISKSTATE, disk, DISKSTATE_MOVE, eventTime);    SUM_ARRAY_METRIC(stats.diskmoves, disk, 1.0);}/* @SUBTITLE "StartDiskXfer: start one-sector disk xfer" *//*  * Start a disk transfer event given the disk and the called time. * The disk is at the beginning of nextSector at the given eventTime. * * !! StartDiskXfer() should only advance ds->nextDiskXfer.  It should * !! by no means change ds->currentDiskXfer. */PRIVATE voidStartDiskXfer(int disk, TICS eventTime){    TICS abstime;    struct diskstatus *ds = &(dstatus[disk]);      DEBUG_TRACE(("StartDiskXfer \t%d\t@%s: nextDiskXfer = %lu\n", disk, 		 time_print(eventTime), ds->nextDiskXfer));    if (ds->done)       {	  INDEX_TIME_EVENT(EV_DISKSTATE, disk, DISKSTATE_IDLE, eventTime);	  return;      }      if (ds->cancelPrefetch)      {	  ds->cancelPrefetch = FALSE;	  ds->activeRead = FALSE;	  DDEventRequest(DISKMOVE, eventTime, disk); /* move to new request */      }    else      {	  if (ds->reading)    /* reading */	    {		/* try to enqueue the next sector onto the queue */		if (!CACHE_FULL(disk)) 		  {		      ds->nextDiskXfer++;		      abstime = DSECTORXFER_t(eventTime);		      ds->prefetchReq = DDEventRequest(ENDDISKXFER, 						       abstime, disk);		      INDEX_TIME_EVENT(EV_DISKSTATE, disk,				       DISKSTATE_XFER, eventTime);		  }		else		  {		      /* cache is full */		      ds->activeRead = FALSE;		      ds->needMove = TRUE;		      INDEX_TIME_EVENT(EV_DISKSTATE, disk, 				       DISKSTATE_IDLE, eventTime);		  }	    }    	  else		      /* writing */	    {		/* there is nothing to be written onto the disk */		if (ds->nextDiskXfer == ds->currentBusXfer) 		  {		      ds->needMove = TRUE; /* not yet */		      INDEX_TIME_EVENT(EV_DISKSTATE, disk, 				       DISKSTATE_IDLE, eventTime);		  } 		else		  {		      ds->nextDiskXfer++;		      abstime = DSECTORXFER_t(eventTime);		      ds->prefetchReq = DDEventRequest(ENDDISKXFER, 						       abstime, disk);		      INDEX_TIME_EVENT(EV_DISKSTATE, disk,				       DISKSTATE_XFER, eventTime);		  }	    }      }}/* @SUBTITLE "EndDiskXfer: end of one sector; start another" *//*   *  Just finished transferring nextSector to/from queue. So, consider *  starting another sector xfer, and possibly a bus transfer. * * !! EndDiskXfer() should only advance ds->currentDiskXfer.  It should * !! by no means change ds->nextDiskXfer. */PRIVATE voidEndDiskXfer(int disk, TICS eventTime){    struct diskstatus *ds = &(dstatus[disk]);      DEBUG_TRACE(("EndDiskXfer \t%d\t@%s: nextDiskXfer = %lu\n", disk, 		 time_print(eventTime), ds->nextDiskXfer));    ds->prefetchReq = NULL;   /* EndDiskXfer has been pulled off the heap */    if (ds->done)       {	  INDEX_TIME_EVENT(EV_DISKSTATE, disk, DISKSTATE_IDLE, eventTime);	  return;      }      if (ds->cancelPrefetch)      {	  ds->cancelPrefetch = FALSE;	  ds->activeRead = FALSE;	  DDEventRequest(DISKMOVE, eventTime, disk); /* move to new request */      }    else      {	  if (ds->reading)    /* reading */	    {		ds->currentDiskXfer++;		if (!ds->activeBusXfer)  		  {		      DEBUG_TRACE(("\t"));		      ConsiderBusXfer(disk, eventTime);		  }		/* start next sector */		DDEventRequest(STARTDISKXFER, 			       MoveNextTime_t(disk, ds->nextDiskXfer, 					      eventTime), disk);	    }	  else		      /* writing */	    {		ds->currentDiskXfer++;		/* when writes get extended, sometimes fCS gets behind */		/* (see end of controller() for explanation) */		ds->firstCachedSector = (ulong)		  min(ds->currentDiskXfer, ds->firstSector);#ifndef SOLO                if ((ds->lastSector - ds->firstSector + 1) > CACHE_SLOTS) {                   /* Size of transfer is larger than the cache                    * To keep the transfer moving, we need to update                     * the firstCachedSector field to reflect what                    * has been transferred to the disk                    */                   ds->firstCachedSector = (ulong)                      max(ds->currentDiskXfer, ds->firstCachedSector);                }#endif		if (!ds->activeBusXfer)		  {		      DEBUG_TRACE(("\t"));		      ConsiderBusXfer(disk, eventTime);		  }	  		/* start disk transfer again if we are not done */		if (ds->nextDiskXfer <= ds->lastSector)		  DDEventRequest(STARTDISKXFER, 				 MoveNextTime_t(disk, ds->nextDiskXfer, 						eventTime), disk);		else		  {		      INDEX_TIME_EVENT(EV_DISKSTATE, disk, DISKSTATE_IDLE, 				       eventTime);#ifdef IMMEDIATE_REPORT		      if (ds->restartController != NEVER)			DDEventRequest(CONTROLLER, 				       max(ds->restartController, eventTime), 				       disk);		      else if (ds->wantSync)			DDEventRequest(SENDDONEMESSAGE, eventTime, disk);	#else		      DDEventRequest(SENDDONEMESSAGE, eventTime, disk);#endif /* IMMEDIATE_REPORT */		  }	    }      }}/* @SUBTITLE "ConsiderBusXfer: consider starting a bus xfer" */PRIVATE voidConsiderBusXfer(int disk, TICS eventTime){    struct diskstatus *ds = &(dstatus[disk]);    ulong readySectors;	      /* sectors that are ready */    boolean lastSectorReady = FALSE;    boolean start = FALSE;    TICS grabTime = 0;	      /* time it took to grab the bus */    DEBUG_TRACE(("ConsiderBusXfer\t%d\t@%s: nextBusXfer = %lu\n", disk, 		 time_print(eventTime), ds->nextBusXfer));      if (eventTime >= ds->wantBus && !ds->activeBusXfer && ds->haveBuffer)      { 	  if (ds->reading)	    {		lastSectorReady = (ds->currentDiskXfer > ds->lastSector);		readySectors = (ds->currentDiskXfer - ds->nextBusXfer);	  		start = ((readySectors >= READFENCE) || lastSectorReady || 			 CACHE_FULL(disk));	    }	  else	    {		lastSectorReady = (ds->nextBusXfer > ds->lastSector);		readySectors = (ds->currentBusXfer - ds->nextDiskXfer);	  		start = ((readySectors <= WRITEFENCE) && !lastSectorReady &&			 !CACHE_FULL(disk));	    }      	  if (start)	    {		ds->activeBusXfer = TRUE; /* somehow, we WILL start it */		if (GrabBus(disk, &grabTime, eventTime))		  {		      DDEventRequest(STARTBUSXFER, (eventTime + grabTime), 				     disk);		      if (grabTime > 0)			INDEX_TIME_EVENT(EV_BUSSTATE, ds->busId, BUSSTATE_GRAB, 					 eventTime);		  }		else		  {		      DEBUG_TRACE(("ConsiderBusXfer: waiting for bus\n"));		      WaitForBus(disk, STARTBUSXFER, eventTime);		  }	    }      }  }#ifndef SOLOextern int SimhdGetDiskNum(int);PRIVATE voidDmaDone(int encoded_ctrl_unit) {   int diskNum = SimhdGetDiskNum(encoded_ctrl_unit);   AdvanceTime();   EndBusXfer(diskNum, GetTime());}#endif /* @SUBTITLE "StartBusXfer: start one-sector bus xfer" *//*   *  Start a bus transfer at the given eventTime. * *  !! StartBusXfer() should only advance ds->nextBusXfer.  It should by *  !! no means change ds->currentBusXfer. */PRIVATE voidStartBusXfer(int disk, TICS eventTime){    struct diskstatus *ds = &(dstatus[disk]);     TICS finish;    INVARIANT4(disk == *(ds->busOwner),	       "StartBusXfer: I (disk %d) do not own the bus, disk %d does\n",	       disk, *(ds->busOwner));    DEBUG_TRACE(("StartBusXfer \t%d\t@%s: nextBusXfer = %lu\n", disk, 		 time_print(eventTime), ds->nextBusXfer));      INDEX_TIME_EVENT(EV_BUSSTATE, ds->busId, BUSSTATE_DATA, eventTime);    finish = BSECTORXFER_t(eventTime); /* find the finish time of the xfer */    ds->nextBusXfer++;

⌨️ 快捷键说明

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