-- DiskDriverSharedImpl.mesa (last edited by: Luniewski on: December 10, 1980 3:44 PM)
DIRECTORY
DiskChannel USING [-- DiskPageNumber, -- IORequestHandle --, Cylinder --],
DiskChannelBackend USING [GetDrive],
DiskDriverShared USING [ScheduleHandle];
DiskDriverSharedImpl: PROGRAM
IMPORTS DiskChannelBackend
EXPORTS DiskDriverShared SHARES DiskChannel =
BEGIN
-- Useful permanent statisitics
totalNumberOfRequests: LONG CARDINAL ← 0;
countQueueEmptyWhenRequestArrived: LONG CARDINAL ← 0;
-- countSequentialRequestsOnSameCylinder: LONG CARDINAL ← 0;
-- countOtherRequestsOnCurrentCylinder: LONG CARDINAL ← 0;
-- countRequestsNotOnCurrentCylinder: LONG CARDINAL ← 0;
countQueueEmptyWhenRequestMade: LONG CARDINAL ← 0;
GetSchedule: PROCEDURE [req: DiskChannel.IORequestHandle]
RETURNS [DiskDriverShared.ScheduleHandle] = -- Fancy loophole
INLINE BEGIN RETURN[LOOPHOLE[DiskChannelBackend.GetDrive[req.channel]]]; END;
GetNextPendingRequest: PUBLIC PROCEDURE [
schedule: DiskDriverShared.ScheduleHandle]
RETURNS [req: DiskChannel.IORequestHandle] =
-- Pick next request off of queue
BEGIN
IF (req ← schedule.first) = NIL THEN
BEGIN
countQueueEmptyWhenRequestMade ← countQueueEmptyWhenRequestMade + 1;
-- IF collectStats THEN RememberRequest[remove, 0];
RETURN;
END;
schedule.first ← req.next;
-- make sure that previousRequest isn't pointing to something that's been removed
-- from the queue
-- IF schedule.first = NIL OR req = schedule.previousRequest THEN
-- schedule.previousRequest ← NIL;
-- IF collectStats THEN RememberRequest[remove, req.diskPage];
END;
InsertRequest: PUBLIC PROCEDURE [req: DiskChannel.IORequestHandle] =
-- using a somewhat odd implementation of the elevator algorithm (FIFO NOW)
BEGIN
-- InsertBefore: PROCEDURE [
-- action: {firstLarger, firstSmaller},
-- startingPlaceForInsertion: LONG POINTER TO DiskChannel.IORequestHandle] =
-- find the correct place in the queue for the request
-- INLINE
-- BEGIN
-- last: LONG POINTER TO DiskChannel.IORequestHandle ←
-- startingPlaceForInsertion;
-- current: DiskChannel.IORequestHandle;
-- DO
-- current ← last↑;
-- IF current = NIL OR req.address.cylinder = current.address.cylinder THEN
-- { InsertWithinCylinder[last]; RETURN };
-- IF
-- (action = firstSmaller AND req.address.cylinder >
-- current.address.cylinder) OR
-- (action = firstLarger AND req.address.cylinder <
-- current.address.cylinder) THEN
-- { last↑ ← req; req.next ← current; RETURN };
-- last ← @current.next;
-- ENDLOOP;
-- END;
-- InsertWithinCylinder: PROCEDURE [
-- startingPlaceForInsertion: LONG POINTER TO DiskChannel.IORequestHandle] =
-- linear insert into correct position amongst entries on current cylinder
-- BEGIN
-- last: LONG POINTER TO DiskChannel.IORequestHandle ←
-- startingPlaceForInsertion;
-- current: DiskChannel.IORequestHandle;
-- DO
-- current ← last↑;
-- IF current = NIL OR req.address.cylinder ~= current.address.cylinder OR
-- req.address.head < current.address.head OR
-- (req.address.head = current.address.head AND req.address.sector <
-- current.address.sector) THEN
-- { last↑ ← req; req.next ← current; RETURN };
-- last ← @current.next;
-- ENDLOOP;
-- END;
schedule: DiskDriverShared.ScheduleHandle = GetSchedule[req];
-- currentCylinderOfDrive: DiskChannel.Cylinder = schedule.currentCylinder;
-- IF collectStats THEN RememberRequest[insert, req.diskPage];
-- req.next ← NIL;
-- SELECT TRUE FROM
-- schedule.first = NIL =>
-- this case is also caught below, but it's useful to keep this statistic independently
-- BEGIN
-- schedule.first ← req;
-- countQueueEmptyWhenRequestArrived ←
-- countQueueEmptyWhenRequestArrived+1;
-- END;
-- catch the typical case of sequential requests
-- schedule.previousRequest ~= NIL AND
-- req.address.cylinder = schedule.previousRequest.address.cylinder AND
-- req.diskPage = schedule.previousRequest.diskPage + 1 =>
-- BEGIN
-- InsertWithinCylinder[@schedule.previousRequest.next];
-- countSequentialRequestsOnSameCylinder ←
-- countSequentialRequestsOnSameCylinder+1;
-- END;
-- req.address.cylinder = currentCylinderOfDrive =>
-- this case happens so seldom, it could probably be removed (allowing
-- InsertWithinCylinder to become an INLINE)
-- BEGIN
-- InsertWithinCylinder[@schedule.first];
-- countOtherRequestsOnCurrentCylinder ←
-- countOtherRequestsOnCurrentCylinder + 1;
-- END;
-- ENDCASE =>
-- insert before the first queue entry with a smaller (or larger) cylinder value
-- (merge with entries with equal cylinder value)
-- BEGIN
-- InsertBefore[
-- IF req.address.cylinder > currentCylinderOfDrive THEN firstLarger
-- ELSE firstSmaller, @schedule.first];
-- countRequestsNotOnCurrentCylinder ← countRequestsNotOnCurrentCylinder+1;
-- END;
-- schedule.previousRequest ← req;
-- the above, commented out, is the elevator algorithm. Below is a very simple disk
-- scheduler that provides first come, first serve service. This is believed to be
-- sufficient due to the presence of runs of pages
prevReq: DiskChannel.IORequestHandle ← NIL;
req.next ← NIL;
totalNumberOfRequests ← totalNumberOfRequests+1;
-- Insert at the end of the queue
FOR c: DiskChannel.IORequestHandle ← schedule.first, c.next
WHILE c ~= NIL DO
prevReq ← c;
ENDLOOP;
IF prevReq = NIL THEN
BEGIN -- empty queue
countQueueEmptyWhenRequestArrived ← countQueueEmptyWhenRequestArrived+1;
schedule.first ← req;
END
ELSE prevReq.next ← req;
END;
PeekNextPendingRequest: PUBLIC PROCEDURE [
schedule: DiskDriverShared.ScheduleHandle]
RETURNS [req: DiskChannel.IORequestHandle] =
-- Pick next request without removing it from queue
BEGIN RETURN[schedule.first] END;
-- Temporary statistics gathering stuff: commented out
-- collectStats: BOOLEAN = TRUE;
-- RequestDirection: TYPE = {insert, remove};
-- maxStatsRequests: CARDINAL = 64;
-- currentIndex: CARDINAL ← 0;
-- totalReqs: CARDINAL ← 0;
-- pgs: ARRAY [0..maxStatsRequests) OF DiskChannel.DiskPageNumber;
-- dirs: ARRAY [0..maxStatsRequests) OF RequestDirection;
-- RememberRequest: PROCEDURE [
-- dir: RequestDirection, pNum: DiskChannel.DiskPageNumber] =
-- BEGIN
-- IF currentIndex >= maxStatsRequests THEN currentIndex ← 0;
-- pgs[currentIndex] ← pNum;
-- dirs[currentIndex] ← dir;
-- currentIndex ← currentIndex + 1;
-- totalReqs ← totalReqs + 1;
-- END;
END.
LOG
Time: January 17, 1979 4:40 PM By: Horsley Action: Create file
Time: March 13, 1979 6:28 PM By: Horsley Action: RememberRequest no longer remembers physical address
Time: July 24, 1979 2:23 PM By: Gobbel Action: Change format of IORequest
Time: August 17, 1979 9:39 AM By: Redell Action: Add USINGs; remove use of old Temporary interface
Time: February 1, 1980 9:22 AM By: McJones Action: Changes to DiskChannel, DiskChannelBackend, DiskDriverShared
Time: December 10, 1980 3:44 PM By: Luniewski Action: Comment out elevator algorithm and statistics gathering code (except for simple counts).