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 + -
显示快捷键?