-- 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.
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.