<> <> DIRECTORY BootStartList USING [ EntryPointer, Enumerate, IndexToEntryPointer, IndexToSpaceEntryPointer, Proc, SpaceEntryPointer], File USING [Handle, PageCount, PageNumber, Read], Process USING [Detach], VM USING [Interval, MakeReadOnly, PageNumberToAddress]; ReadInBootFile: MONITOR IMPORTS BootStartList, File, Process, VM = BEGIN maxProcesses: NAT = 2; processesInUse: NAT _ 0; processAvailable: CONDITION _ [timeout: 0]; bootFileHandle: File.Handle; ForkedRead: PROC [from: File.PageNumber, nPages: File.PageCount, to: LONG POINTER] = { File.Read[file: bootFileHandle, from: from, nPages: nPages, to: to]; NotifyProcessAvailable[]; }; WaitForAProcess: ENTRY PROC = { WHILE processesInUse = maxProcesses DO WAIT processAvailable ENDLOOP; processesInUse _ processesInUse + 1; }; NotifyProcessAvailable: ENTRY PROC = { processesInUse _ processesInUse - 1; NOTIFY processAvailable; }; WaitUntilDone: ENTRY PROC = { UNTIL processesInUse = 0 DO WAIT processAvailable ENDLOOP; }; SwapIn: BootStartList.Proc = { OPEN BootStartList; entry: EntryPointer = IndexToEntryPointer[index]; WITH e: entry SELECT FROM space => IF ~e.bootLoaded THEN { WaitForAProcess[]; Process.Detach[FORK ForkedRead[ from: [e.backingPage.LONG], nPages: e.pages, to: VM.PageNumberToAddress[e.vmpage.LONG] ]]; }; swapUnit => NULL; ENDCASE => ERROR; }; MakeReadOnly: BootStartList.Proc = { OPEN BootStartList; entry: EntryPointer = IndexToEntryPointer[index]; WITH e: entry SELECT FROM swapUnit => { parent: SpaceEntryPointer = IndexToSpaceEntryPointer[e.parent]; IF ~parent.bootLoaded AND e.info.readOnly THEN VM.MakeReadOnly[VM.Interval[parent.vmpage.LONG+e.base, e.pages]]; }; space => NULL; ENDCASE => ERROR; }; BootStartList.Enumerate[SwapIn]; BootStartList.Enumerate[MakeReadOnly]; WaitUntilDone[]; END.