-- RTStartImpl.Mesa -- last edited 27-Oct-81 10:16:05 by Haugeland -- last edited September 9, 1982 10:39 am by Paul Rovner DIRECTORY CPSwapDefs USING[ProcessState], DeviceCleanup USING[Item, Reason, Await], Frame USING[MyLocalFrame, Free, GetReturnFrame, Alloc], Inline USING[COPY], MiscAlpha USING[alpha], PrincOps USING[StateVector, ControlLink, Frame, NullLink, FrameSizeIndex, FrameHandle], Process USING[priorityForeground, Yield], Processes, ProcessOperations USING[ReadPSB, Enter, Wait, ReEnter, Broadcast, Exit, Notify, HandleToIndex], PSB USING[PsbIndex, PsbHandle, ConditionVariable, PsbNull, ProcessStateBlock, NoTimeout], RTBasic USING[Pointer], RTMicrocode USING[aRECLAIMEDREF, aALTERCOUNT, opASSIGNREF, aGetReferentType, opASSIGNREFNEW, aRTMOVESTATUS, RTMOVESTATUS, aAllocateQuantizedNode, aAllocateHeapNode, aGetCanonicalReferentType, aFreeObject, aFreeQuantizedNode, aFreePrefixedNode], RTOS USING[UnregisterCedarProcess, RegisterCedarProcess], RTRefCounts USING[ClobberedOverflowTable, ReadUCodeRegsTrap, useUCodedGC, ReclaimedRefOutOfOverflowTable, RTMOVESTATUSTrap, AssignRefTrap, AssignRefNewTrap, CREATEOutOfOverflowTable, ALTERCOUNTOutOfOverflowTable, aCREATEREF], RTSD USING[SD, sAllocateQuantizedNodeTrap, sAllocateHeapNodeTrap, sGetCanonicalReferentType, sCheckForNarrowRefFault, sAssignRefTrap, sAssignRefNewTrap, sClobberedOverflowTable, sFork, sRaiseNarrowFault, sProcCheck, sAssignComposite, sAssignCompositeNew], RTStart USING[], RTStorageOps USING[AssignComposite, AssignCompositeNew, AssignRef, AssignRefNew], RTTypesBasicPrivate USING[CheckForNarrowRefFault, GetCanonicalReferentTypeTrap, GetReferentTypeTrap, GetCanonicalReferentTypeSDTrap], RTZones USING[AllocateQuantizedNodeSDTrap, AllocateHeapNodeSDTrap, FreeObjectTrap, CreateQuantizedObjectTrap, CreatePrefixedObjectTrap, FreeQuantizedNodeTrap, FreePrefixedNodeTrap], Runtime USING[GlobalFrame], RuntimeInternal USING[FrameSize], SafeStorage USING[NarrowFault], SpecialSpace USING[MakeCodeResident, MakeGlobalFrameResident], TrapSupport USING[opTrapTable]; RTStartImpl: PROGRAM IMPORTS DeviceCleanup, Frame, Inline, Process, ProcessOperations, RTMicrocode, RTOS, RTRefCounts, RTStorageOps, SafeStorage, RTTypesBasicPrivate, RTZones, Runtime, RuntimeInternal, SpecialSpace EXPORTS RTOS--End--, RTRefCounts, RTStart, SafeStorage SHARES Processes = BEGIN OPEN TrapSupport, RTMicrocode, RTRefCounts, RTSD, RTStorageOps; -- PUBLIC SIGNALS -- UnsafeProcAssignment: PUBLIC SAFE SIGNAL[proc: PROC ANY RETURNS ANY] = CODE; -- PUBLIC PROCEDURES -- StartRT: PUBLIC PROC = {NULL}; -- the start trap does it all --////////////// -- Cleanup stuff. Here 'cause its code must be pinned. -- ***************************** InitializeCleanup: PUBLIC PROC[gcStateBank: CARDINAL] = { DO item: DeviceCleanup.Item; reason: DeviceCleanup.Reason _ DeviceCleanup.Await[@item]; SELECT reason FROM turnOff, kill => IF useUCodedGC THEN [] _ RTMicrocode.RTMOVESTATUS[toMemory, 0--ignored--]; turnOn => IF useUCodedGC THEN [] _ RTMicrocode.RTMOVESTATUS[toUCodeRegisters, gcStateBank]; ENDCASE; ENDLOOP}; -- ***************************** --////////////// -- procedures for maintaining a registry of Cedar processes --PrincOps.--FsiFrame: TYPE = MACHINE DEPENDENT RECORD [ fsi (0): PrincOps.FrameSizeIndex, -- must be at 3 MOD 4 boundary. frame (1): local PrincOps.Frame]; ProcessState: TYPE = CPSwapDefs.ProcessState; pm: POINTER TO FRAME[Processes] = LOOPHOLE[Runtime.GlobalFrame[Process.Yield]]; ProcState: -- for access to ProcessState field. PROC[psbh: PSB.PsbHandle] RETURNS [ProcessState] = INLINE {RETURN[LOOPHOLE[pm.pda[psbh].flags.available, ProcessState]]}; End: PUBLIC --"ENTRY"-- PROCEDURE = -- When the top context of a process "returns", it Xfers to -- this procedure with its results on the stack. BEGIN OPEN PSB, ProcessOperations; sv: RECORD [filler: UNSPECIFIED, results: PrincOps.StateVector]; DyingFrameHandle: TYPE = POINTER TO dying PrincOps.Frame; frame: DyingFrameHandle; h: PsbHandle; sv.results _ STATE; -- save stack containing returned results. WHILE ~ProcessOperations.Enter[@pm.processLock] DO NULL ENDLOOP; frame _ LOOPHOLE[Frame.MyLocalFrame[]]; frame.state _ alive; h _ ProcessOperations.ReadPSB[]; --***-- RTOS.UnregisterCedarProcess[HandleToIndex[h]]; LOOPHOLE[pm.pda[h].flags.available, ProcessState].state _ frameReady; pm.pda[h].flags.abort _ FALSE; -- too late for Aborts: they no-op Broadcast[@pm.frameReady]; -- wake any parent process waiting to Join. -- Wait till this process is Detached or Joined: UNTIL ProcState[h].state = frameTaken OR ProcState[h].detached DO Wait[@pm.processLock, @pm.frameTaken, LOOPHOLE[pm.frameTaken, ConditionVariable].timeout]; WHILE ~ReEnter[@pm.processLock, @pm.frameTaken] DO NULL ENDLOOP; ENDLOOP; -- Free any frame left over from a previous dead detached process: IF pm.deadFrame ~= NIL THEN {Frame.Free[pm.deadFrame]; pm.deadFrame _ NIL}; IF ProcState[h].detached THEN pm.deadFrame _ frame; -- If detached, leave our frame for freeing. frame.state _ dead; -- tell Joiner that we're done. LOOPHOLE[pm.pda[h].flags.available, pm.ProcessState].state _ dead; Broadcast[@pm.dead]; -- tell parent our frame has been left for freeing. Wait[@pm.processLock, @pm.rebirth, LOOPHOLE[pm.rebirth, ConditionVariable].timeout]; -- This process is dead. Its PSB sits in the rebirth queue until -- it is recycled into a new process by Fork. -- Our current frame however, has one of two fates: -- (a) If this process was detached, the frame will simply be freed -- by the next process that finishes ("deadFrame"). -- (b) if this process is being Joined, the parent process will -- have acquired a pointer to our frame. The JOIN code will Xfer -- to our frame and the code below will be executed -- BY THE PARENT PROCESS. The parent process therefore -- MUST BE RUNNING IN THE SAME MDS as the child process! WHILE ~ReEnter[@pm.processLock, @pm.rebirth] DO NULL ENDLOOP; sv.results.dest _ LOOPHOLE[frame.returnlink, PrincOps.ControlLink]; -- (frame.returnlink was set by Join[] to point to the context of JOIN.) sv.results.source _ PrincOps.NullLink; Exit[@pm.processLock]; -- Reload returned results into stack, return to parent: RETURN WITH sv.results; END; CedarForker: --"ENTRY"-- PROCEDURE [--argsForRoot,-- root: PrincOps.ControlLink] RETURNS [childPsb: PSB.PsbIndex] = BEGIN OPEN PSB, ProcessOperations; PForkFrame: TYPE = POINTER TO FRAME[CedarForker]; ChildBuilder: PROC [--parent's locals--] RETURNS [--MUST BE NULL!--] = BEGIN pChild: LONG POINTER TO ProcessStateBlock _ @pm.pda.block[childPsb]; parentFrame: PForkFrame = LOOPHOLE[Frame.GetReturnFrame[]]; fsi: PrincOps.FrameSizeIndex = LOOPHOLE[ (parentFrame-1), POINTER TO FsiFrame].fsi; childFrame: PForkFrame = Frame.Alloc[fsi]; Inline.COPY[from: parentFrame-1, to: childFrame-1, nwords: RuntimeInternal.FrameSize[fsi] + SIZE[PrincOps.FrameSizeIndex] ]; --***-- LOOPHOLE[childFrame, PrincOps.FrameHandle].returnlink _ LOOPHOLE[End]; childFrame.identity _ child; pChild.link.failed _ FALSE; pChild.link.priority _ pm.pda[ReadPSB[]].link.priority; --***-- IF pChild.link.priority > Process.priorityForeground THEN ERROR; pChild.flags _ [available: LOOPHOLE[pm.ProcessState[state: alive, detached: FALSE]], cleanup: PsbNull, waiting: FALSE, abort: FALSE]; pChild.context _ [frame[LOOPHOLE[childFrame, PrincOps.FrameHandle]]]; -- TEMP until microcode uses timeout vector: -- pChild.mds _ Inline.HighHalf[LONG[LOOPHOLE[1, POINTER]]]; pChild.mds _ NoTimeout; pm.pda[pm.pda.timeout][childPsb] _ NoTimeout; --***-- RTOS.RegisterCedarProcess[childPsb]; Notify[@pm.rebirth]; -- starts the new process executing. Its PC -- is set to begin execution at the instruction after the call -- to ChildBuilder. Its stack is empty. Therefore, -- ChildBuilder MUST NOT RETURN ANY RESULTS! END; identity: {parent, child}; argsForChild: PrincOps.StateVector; -- ("root" is automatically popped off the stack first.) argsForChild _ STATE; -- must be first! identity _ parent; WHILE ~Enter[@pm.processLock] DO NULL ENDLOOP; WHILE LOOPHOLE[pm.rebirth, ConditionVariable].condition.tail = PsbNull DO Exit[@pm.processLock]; Process.Yield[]; WHILE ~Enter[@pm.processLock] DO NULL ENDLOOP; ENDLOOP; childPsb _ pm.pda.block[LOOPHOLE[pm.rebirth, ConditionVariable].condition.tail] .link.next; -- walk to tail, then to head. [] _ ChildBuilder[--my local vars--]; -- Both parent and child processes will execute the following code: SELECT identity FROM parent => { Exit[@pm.processLock]; RETURN[childPsb] }; -- return child handle to FORKing parent. child => BEGIN -- To simulate a procedure call, we must also store dest and -- source links *above* the stack since ReturnWithState doesn't. -- (stack pointer is *not* incremented.) argsForChild.stk[argsForChild.stkptr] _ root; argsForChild.dest _ root; -- Set child's top context to call End when it returns: argsForChild.stk[argsForChild.stkptr+1] _ End; argsForChild.source _ LOOPHOLE[End, PrincOps.ControlLink]; RETURN WITH argsForChild; -- "call" root procedure of child. END; ENDCASE; END; -- procedures for maintaining a registry of Cedar processes (end) --////////////// -- procedures for supporting the compiler --////////////// RaiseNarrowFault: PROC = { state: PrincOps.StateVector; kludge: LONG UNSPECIFIED; state _ STATE; -- incantation to clear the stack IF FALSE THEN kludge _ 0; ERROR SafeStorage.NarrowFault}; ProcCheck: PROC[proc: PROC ANY RETURNS ANY] RETURNS[PROC ANY RETURNS ANY] = { p: PrincOps.ControlLink = LOOPHOLE[proc]; IF p # PrincOps.NullLink AND ~p.tag THEN SIGNAL UnsafeProcAssignment[proc]; RETURN[proc]}; -- procedures for supporting the compiler (end) --////////////// -- ***************************** aREADREGS: MiscAlpha.alpha = 66B; -- temp for Dorado debugging -- START HERE opTrapTable.misc[aRECLAIMEDREF] _ LOOPHOLE[ReclaimedRefOutOfOverflowTable]; opTrapTable.misc[aRTMOVESTATUS] _ LOOPHOLE[RTMOVESTATUSTrap]; opTrapTable.main[opASSIGNREF] _ LOOPHOLE[AssignRefTrap]; opTrapTable.main[opASSIGNREFNEW] _ LOOPHOLE[AssignRefNewTrap]; opTrapTable.misc[aCREATEREF] _ LOOPHOLE[CREATEOutOfOverflowTable]; opTrapTable.misc[aALTERCOUNT] _ LOOPHOLE[ALTERCOUNTOutOfOverflowTable]; opTrapTable.misc[aAllocateQuantizedNode] _ LOOPHOLE[RTZones.CreateQuantizedObjectTrap]; opTrapTable.misc[aAllocateHeapNode] _ LOOPHOLE[RTZones.CreatePrefixedObjectTrap]; opTrapTable.misc[aFreeObject] _ LOOPHOLE[RTZones.FreeObjectTrap]; opTrapTable.misc[aFreeQuantizedNode] _ LOOPHOLE[RTZones.FreeQuantizedNodeTrap]; opTrapTable.misc[aFreePrefixedNode] _ LOOPHOLE[RTZones.FreePrefixedNodeTrap]; opTrapTable.misc[aGetCanonicalReferentType] _ LOOPHOLE[RTTypesBasicPrivate.GetCanonicalReferentTypeTrap]; opTrapTable.misc[aGetReferentType] _ LOOPHOLE[RTTypesBasicPrivate.GetReferentTypeTrap]; opTrapTable.misc[aREADREGS]_ LOOPHOLE[ReadUCodeRegsTrap]; IF SD[sFork] # 0 THEN ERROR; SD[sFork] _ LOOPHOLE[CedarForker, CARDINAL]; IF SD[sRaiseNarrowFault] # 0 THEN ERROR; SD[sRaiseNarrowFault] _ LOOPHOLE[RaiseNarrowFault, CARDINAL]; IF SD[sProcCheck] # 0 THEN ERROR; SD[sProcCheck] _ LOOPHOLE[ProcCheck, CARDINAL]; IF SD[sAssignRefTrap] # 0 THEN ERROR; SD[sAssignRefTrap] _ LOOPHOLE[AssignRef, CARDINAL]; IF SD[sAssignRefNewTrap] # 0 THEN ERROR; SD[sAssignRefNewTrap] _ LOOPHOLE[AssignRefNew, CARDINAL]; IF SD[sClobberedOverflowTable] # 0 THEN ERROR; SD[sClobberedOverflowTable] _ LOOPHOLE[ClobberedOverflowTable, CARDINAL]; IF SD[sAssignComposite] # 0 THEN ERROR; SD[sAssignComposite] _ LOOPHOLE[AssignComposite, CARDINAL]; IF SD[sAssignCompositeNew] # 0 THEN ERROR; SD[sAssignCompositeNew] _ LOOPHOLE[AssignCompositeNew, CARDINAL]; IF SD[sCheckForNarrowRefFault] # 0 THEN ERROR; SD[sCheckForNarrowRefFault] _ LOOPHOLE[RTTypesBasicPrivate.CheckForNarrowRefFault, CARDINAL]; IF SD[sGetCanonicalReferentType] # 0 THEN ERROR; SD[sGetCanonicalReferentType] _ LOOPHOLE[RTTypesBasicPrivate.GetCanonicalReferentTypeSDTrap, CARDINAL]; IF SD[sAllocateQuantizedNodeTrap] # 0 THEN ERROR; SD[sAllocateQuantizedNodeTrap] _ LOOPHOLE[RTZones.AllocateQuantizedNodeSDTrap, CARDINAL]; IF SD[sAllocateHeapNodeTrap] # 0 THEN ERROR; SD[sAllocateHeapNodeTrap] _ LOOPHOLE[RTZones.AllocateHeapNodeSDTrap, CARDINAL]; SpecialSpace.MakeCodeResident[Runtime.GlobalFrame[InitializeCleanup]]; SpecialSpace.MakeGlobalFrameResident[RTStartImpl]; END.