-- FileTaskImpl.mesa (last edited by: Luniewski on: February 5, 1981 10:04 AM) DIRECTORY DiskChannel USING [ CompletionStatus, DiskPageNumber, IORequest, IORequestHandle, Label], Environment USING [Base, PageCount, PageNumber, wordsPerPage], File USING [PageCount], FilePageTransfer USING[Operation], FileInternal USING [ReadOnlyFilePtr, Operation], FileCache USING [ReturnFilePtrs], FilerPrograms USING[], FileTask USING[], Inline USING [DIVMOD, HighHalf, LowHalf], PilotDisk USING [Label], Process USING [DisableAborts], ResidentHeap USING [first64K, FreeNode, MakeNode], ResidentMemory USING [Allocate], RuntimeInternal USING [WorryCallDebugger], System USING [GetClockPulses, MicrosecondsToPulses, Pulses], Utilities USING [ShortCARDINAL], VM USING [Interval], Zone USING [Status]; FileTaskImpl: MONITOR IMPORTS FileCache, Inline, Process, ResidentHeap, ResidentMemory, RuntimeInternal, System, Utilities EXPORTS FileTask, FilePageTransfer, FilerPrograms = BEGIN ErrorHalt: PROC = BEGIN DO RuntimeInternal.WorryCallDebugger["Error in FileTaskImpl"L]; ENDLOOP; END; -- The value of minConcurrency was chosen so the task table would take 1 page: minConcurrency: CARDINAL = 2; table: Environment.Base = ResidentHeap.first64K; -- File Task Table maxConcurrency: PUBLIC CARDINAL; taskTableDeadlockTimeout: System.Pulses; taskCount, taskMax: CARDINAL _ 0; -- temp measurement counters TaskPtr: TYPE = LONG POINTER TO Task; TaskHandle: TYPE = Environment.Base RELATIVE POINTER TO Task; nil: TaskHandle = LOOPHOLE[0]; Task: TYPE = RECORD [ label: DiskChannel.Label, next: TaskHandle, operationClass: OperationClass, fromHeap: BOOLEAN, memPage: Environment.PageNumber, pageCount: File.PageCount, countOK: File.PageCount, -- number of pages transferred successfully filePtr: FileInternal.ReadOnlyFilePtr, var: SELECT OVERLAID * FROM disk => [request: DiskChannel.IORequest], xwire => NULL, -- ??? -- ENDCASE]; OperationClass: TYPE = {dataOperation, labelOperation}; doneD, doneL, free: CONDITION; doneDQ, doneLQ, freeQ: TaskHandle; -- -- FileTask DiskStart: PUBLIC ENTRY PROC [ mPage: Environment.PageNumber, count: File.PageCount, fPtr: FileInternal.ReadOnlyFilePtr, operation: FileInternal.Operation] RETURNS [DiskChannel.IORequestHandle] = BEGIN taskH: TaskHandle; taskP: TaskPtr; startTime: System.Pulses; startTime _ System.GetClockPulses[]; DO IF freeQ ~= nil THEN EXIT; IF System.GetClockPulses[]-startTime > taskTableDeadlockTimeout THEN BEGIN -- apparent deadlock so allocate one out of the resident heap s: Zone.Status; [freeQ, s] _ ResidentHeap.MakeNode[SIZE[Task], a4]; -- a4 for quadword labels IF s ~= okay THEN ERROR; table[freeQ].next _ nil; table[freeQ].fromHeap _ TRUE; GO TO Exit; END; WAIT free; REPEAT Exit => NULL; ENDLOOP; taskH _ freeQ; taskP _ @table[taskH]; freeQ _ taskP.next; taskMax _ MAX[taskMax, taskCount _ taskCount + 1]; BEGIN OPEN taskP; operationClass _ IF operation IN FilePageTransfer.Operation THEN dataOperation ELSE labelOperation; memPage _ mPage; pageCount _ count; filePtr _ fPtr; request.label _ @label; request.tag _ LOOPHOLE[taskH]; -- store handle in request for DiskFinish RETURN[@request] END; END; DiskFinish: PUBLIC ENTRY PROC [reqH: DiskChannel.IORequestHandle] = BEGIN taskH: TaskHandle = LOOPHOLE[reqH.tag]; -- go directly to task using Handle taskP: TaskPtr = @table[taskH]; taskP.countOK _ reqH.countDone; IF taskP.operationClass = dataOperation THEN BEGIN taskP.next _ doneDQ; doneDQ _ taskH; NOTIFY doneD; FileCache.ReturnFilePtrs[1, taskP.filePtr]; END ELSE BEGIN taskP.next _ doneLQ; doneLQ _ taskH; NOTIFY doneL END; END; -- EtherStart: PUBLIC ENTRY PROC [mPage: Environment.PageNumber, fPtr: FileInternal.ReadOnlyFilePtr] = -- BEGIN -- Real version must handle duplicates, retransmissions, etc. ...will probably need a fancier key... -- END; -- EtherFinish: PUBLIC ENTRY PROC [mPage: Environment.PageNumber, other args...] = -- BEGIN -- Real version must handle duplicates, retransmissions, etc. ...will probably need a fancier key... -- END; -- -- FilePageTransfer Wait: PUBLIC ENTRY PROC RETURNS [interval: VM.Interval] = BEGIN taskH: TaskHandle; taskP: TaskPtr; WHILE doneDQ = nil DO WAIT doneD ENDLOOP; taskH _ doneDQ; taskP _ @table[taskH]; doneDQ _ taskP.next; -- Since this is I/O to/from a run of VM pages, countOK must be only as big as an -- Environment.PageCount interval _ VM.Interval[taskP.memPage, Utilities.ShortCARDINAL[taskP.countOK]]; IF taskP.request.status ~= goodCompletion THEN HandleError[@taskP.request]; IF taskP.fromHeap THEN -- Delete the Task allocated to handle the deadlock {IF ResidentHeap.FreeNode[taskH] ~= okay THEN ERROR} ELSE BEGIN taskP.next _ freeQ; freeQ _ taskH; END; taskCount _ taskCount - 1; NOTIFY free; END; -- -- FileTask LabelWait: PUBLIC ENTRY PROC [ label: POINTER TO PilotDisk.Label, handleErrors: BOOLEAN] RETURNS [countValid: File.PageCount, status: DiskChannel.CompletionStatus] = BEGIN taskH: TaskHandle; taskP: TaskPtr; WHILE doneLQ = nil DO WAIT doneL ENDLOOP; taskH _ doneLQ; taskP _ @table[taskH]; doneLQ _ taskP.next; label^ _ taskP.label; countValid _ taskP.countOK; IF (status _ taskP.request.status) ~= goodCompletion AND handleErrors THEN HandleError[@taskP.request]; IF taskP.fromHeap THEN -- Delete the Task allocated to handle the deadlock {IF ResidentHeap.FreeNode[taskH] ~= okay THEN ERROR} ELSE BEGIN taskP.next _ freeQ; freeQ _ taskH; END; taskCount _ taskCount - 1; NOTIFY free; END; HandleError: PROC [req: DiskChannel.IORequestHandle] = BEGIN hardErrorString: STRING _ [35]; diskPage: DiskChannel.DiskPageNumber _ req.diskPage; SELECT req.status FROM -- must clearly get smarter goodCompletion => RETURN; labelDoesNotMatch => hardErrorString _ "Disk label check"; ENDCASE => -- Kludge! This should be fixed to report the actual page. IF Inline.HighHalf[diskPage] ~= 0 THEN hardErrorString _ "Unrecoverable disk error on large disk page" ELSE BEGIN i: CARDINAL (0..5]; num: CARDINAL _ Inline.LowHalf[diskPage]; dig: CARDINAL; hardErrorString _ "Unrecoverable disk error on page XXXXX"; FOR i IN (0..5] DO [num, dig] _ Inline.DIVMOD[num, 10]; hardErrorString[hardErrorString.length-i] _ IF dig=0 AND num=0 AND i#1 THEN ' ELSE '0+dig; ENDLOOP; END; DO RuntimeInternal.WorryCallDebugger[hardErrorString] ENDLOOP; END; -- -- Initialization BEGIN taskPages: Environment.PageCount _ (minConcurrency*SIZE[Task]+Environment.wordsPerPage-1)/ Environment.wordsPerPage; taskH: TaskHandle; taskH _ LOOPHOLE[Inline.LowHalf[ResidentMemory.Allocate[first64K, taskPages]]]; maxConcurrency _ (taskPages*Environment.wordsPerPage)/SIZE[Task]; freeQ _ taskH; THROUGH [0..maxConcurrency-1) DO table[taskH].next _ taskH + SIZE[Task]; table[taskH].fromHeap _ FALSE; taskH _ table[taskH].next; ENDLOOP; table[taskH].next _ nil; table[taskH].fromHeap _ FALSE; doneDQ _ doneLQ _ nil; END; Process.DisableAborts[@doneD]; Process.DisableAborts[@doneL]; Process.DisableAborts[@free]; taskTableDeadlockTimeout _ System.MicrosecondsToPulses[10*1000000]; -- 10 seconds to deadlock END. LOG Time: February 28, 1979 11:33 AM By: Redell Action: Created file from old TransferImpl.mesa Time: March 7, 1979 6:04 PM By: Redell Action: Converted to Mesa 5.0; removed reference to old FilePageTransferInternal. Time: March 26, 1979 4:59 PM By: Redell Action: Added check for label error on data transfer (For now, fatal error => Call Debugger). Time: August 20, 1979 12:19 PM By: Redell Action: Removed LOOPHOLEs to DiskChannel types. Time: November 26, 1979 12:31 PM By: Gobbel Action: Added count to FTTEntry and Wait. Time: December 16, 1979 3:32 PM By: Redell Action: Moved task tabel to hyperspace, changed linear searches to LIFO queues, removed Alto machinery, general cleanup. Time: January 29, 1980 1:29 PM By: Gobbel Action: Merge Redell's changes with changes for new LabelTransfer (countValid added to LabelWait), change VM.Interval to FileInternal.Interval. Time: December 10, 1980 2:33 PM By: Luniewski Action: Dynamically compute FileTask.maxConcurrency based upon minConcurrency so as to most fully use an integral number of pages Time: January 13, 1981 3:45 PM By: Luniewski Action: Move disk error handling into here. Dynamically allocate file tasks when detect deadlock. (635)\6320i27I906i1I Time: February 3, 1981 4:57 PM By: McJones Action: Add missing "-1" in initialization  Time: February 5, 1981 10:04 AM By: Luniewski Action: Use FileInternal.ReadOnlyFilePtr.