INSERT[MesaPDefs]; :TITLE[MesaP]; % Ed Fiala 11 May 1982: Fix bug that PSB not refetched after ExitM2 call by MXWait. Ed Fiala 2 February 1982: rearranged RSSaveStack to avoid PStore4 after tasking and RSLoadAndFreeState; fix noninterlocked overwrite of PFetch4 at RSSaveProcess. Ed Fiala 22 September 1981: P4Ret edits; Idle loop change; minimal stack error check bugfix; bum 3 mi. Ed Fiala 5 May 1981: Bum 1 mi; move prTime and prTicks out of RM 0-77 by expending 6 mi. Ed Fiala 21 April 1981 Bum 14b mi. Ev Neely March 26, 1981 4:31 PM Add test of condition.abortable to MXW. Ev Neely March 24, 1981 10:36 AM Added tasking. Ed Fiala 23 March 1981 Change xfBrkByte value. Jim Frandeen February 21, 1981 4:37 PM Add Calls and replace some Tasks with calls to fix All Memory Task Gotcha (number 17). Ev Neely February 19, 1981 12:42 PM Moved definitions to MesaPDefs.mc because MesaP.mc has gotten to large for bravo editing. Ev Neely February 13, 1981 7:18 AM Handle nil source for Requeue Op. Ev Neely January 30, 1981 12:21 PM Big Stack. Ev Neely January 28, 1981 8:56 AM Fix AR 6958 & co. Ev Neely January 14, 1981 10:02 AM Fault Notification . Ev Neely December 18, 1980 4:57 PM Change Reschedule to use StateAllocTable. Set PSB.waiting in Wait and clear it in WakeHead and TimeoutScan. Jim Frandeen October 20, 1980 11:06 AM Fix timeout. Check for minimal stack. Fix trap bug caused by not saving state after every requeue. Johnsson October 10, 1980 6:01 PM fixup trap code Johnsson September 29, 1980 10:53 AM fixup trap code Jim Frandeen September 22, 1980 4:32 PM Remove Task before PStore4 at RequeueExit just in case another WorstGotcha appears. Jim Frandeen September 17, 1980 10:09 AM Jim Frandeen July 16, 1980 2:11 PM Created from Jim Sandman's original MesaP to change the PSB format. % (1795) @ME:e12 *Monitor Entry. Stack contains long or short pointer to Monitor.l4512d4268(0,13504) prFlags _ MEFlags, GoTo[LongOrShortMonitor], OpCode[1]; l13760d4268 @MRE:e12(1795) *Monitor Re-Entry. Stack contains long or short pointer to Condition and long or short pointer to Monitor.l4512d4268(0,13504) prFlags _ MREFlags, GoTo[CheckLongOrShort2], OpCode[2]; l13760d4268 P4PopToT: T _ Stack&-1, Return;e12(1795) @MXW:e12 *Monitor Exit and Wait. Stack contains time, long or short pointer to Condition, and long or short pointer to Monitor.l4512d4268(0,13504) prFlags _ MXWFlags, Call[P4PopToT], OpCode[3]; l13760d4268 prTimeout _ T, GoTo[CheckLongOrShort2]; l13760d4268 @MXD:e12(1795) *Monitor Exit and Depart. Stack contains long or short pointer to Monitor.l4512d4268(0,13504) prFlags _ MXDFlags, GoTo[LongOrShortMonitor], OpCode[4]; l13760d4268 @NOTIFY:e12(1795) *Notify. Stack contains long or short pointer to Condition.l4512d4268(0,13504) prFlags _ NOTIFYFlags, GoTo[LongOrShortCondition], OpCode[5]; l13760d4268 @BCAST:e12(1795) *Broadcast. Stack contains long or short pointer to Condition.l4512d4268(0,13504) prFlags _ BCASTFlags, OpCode[6]; l13760d4268 LongOrShortCondition:e12(1795) T _ 375C, Call[FixConditionQueue]; *Check for stack pointer = 2.l13760d4268(0,13504) prConditionQ _ T, Call[GetCondition];l13760d4268 PStore1[prConditionQ,prCondition,0]; *Trigger write protect fault if protectedl13760d4268 ProcessOps:e12(1795) T _ 377C;l13760d4268(0,13504) LU _ (NStkP) XOR T; *Check for minimal stack.l13760d4268 GoTo[StackEmpty,ALU=0]; *IF stack is emptyl13760d4268 LoadPageExternal[FaultPage];l13760d4268 GoToExternal[StackErrorLoc]; *Stack error KFCB trapl13760d4268 StackEmpty:e12(1795) LoadPage[prPage], T _ prCurrentPsb; *Prepare to fetch CurrentPsb.l13760d4268(0,13504) Dispatch[prFlags,5,4], GoTo[ProcessDispatch];l13760d4268 l13760d4268 P4Ret: Return;e12(1795) @REQUEUE:e12 *Requeue. Stack contains a Psb index, a long or short pointer to a source queue, and a long or short pointer to a destination queue. Put the source queue in MonitorQueue, destination queue in ConditionQueue.l4512d4268(0,13504) prFlags _ REQFlags, Call[P4PopToT], OpCode[7]; l13760d4268 prPsbIndex _ T; l13760d4268 CheckLongOrShort2:e12(1795) T _ 373C, Call[FixConditionQueue]; *Check for stack pointer = 4.l13760d4268(0,13504) prConditionQ _ T, Call[GetCondition];l13760d4268 PStore1[prConditionQ,prCondition,0]; *Trigger write protect fault if protected. l13760d4268 LongOrShortMonitor:e12(1795) T _ 375C; *Check for stack pointer = 2.l13760d4268(0,13504) LU _ (NStkP) XOR T, Call[FixMonitor]; *Check for short or long pointer.l13760d4268 LU _ (prMonitorQhi) OR T; *Check for nil long pointer.l13760d4268 prMonitorQ _ T, GoTo[MonitorFetch,ALU#0];l13760d4268 *Come here when MonitorQ is nil. If RequeueOp, treat as nil source and don't fetch Monitor; otherwise allow address fault. l4512d4268 LU _ (prFlags) XOR (REQFlags); *Check for RequeueOp.l13760d4268 prFlags _ (prFlags) OR (SourceQNil),l13760d4268 GoTo[ProcessOps,ALU=0]; *Don't fetch if RequeueOpl13760d4268 Nop; *Needed because of multiple conditonal gotos. No need for speed as will fault anyway.l13760d4268 l4512d4268 MonitorFetch:e12(1795) *If the Monitor is write protected the following instruction pair will cause a write protect fault before changes to the stack or memory make it unrecoverable. l4512d4268(0,13504) PFetch1[prMonitorQ,prMonitor,0], Call[P4Ret];l13760d4268 PStore1[prMonitorQ,prMonitor,0], GoTo[ProcessOps]; *OK fetch it for real. Watch out for Gotcha#1. l13760d4268 FixConditionQueue:e12(1795) LU _ (NStkP) XOR T; *Check for short or long pointer.l13760d4268(0,13504) LU _ LdF[Stack,0,12], Skip[ALU=0]; *Check for map out of bounds.l13760d4268 T _ MDShi, GoTo[FixShortConditionQueue];l13760d4268 *All we use ConditionQ for is to fetch and store one word, so we don't need to create a perfect base register.l4522d4268 T _ LSh[Stack&-1,10], Skip[ALU=0]; *Long pointerl13760d4268 T _ (Zero) - 1; *Cause map out of bounds.l15030d5538 FixShortConditionQueue:e12(1795) prConditionQhi _ T, GoTo[P4PopToT];l13760d4268(0,13504) GetCondition:e12(1795) PFetch1[prConditionQ,prCondition,0], GoTo[P4Ret]; l13760d4268(0,13504) FixMonitor:e12(1795) LU _ LDF[Stack,0,12], Skip[ALU=0]; *Check for map out of bounds.l13760d4268(0,13504) T _ MDShi, GoTo[FixShortMonitorQueue];l13760d4268 *All we use MonitorQ for is to fetch and store one word, so we don't need to create a perfect base register.l4522d4268 T _ LSH[Stack&-1,10], Skip[ALU=0]; *Long pointerl13760d4268 T _ (Zero) - 1; *Cause map out of bounds.l15030d5538 FixShortMonitorQueue:e12(1795) prMonitorQhi _ T, GoTo[P4PopToT];l13760d4268(0,13504) l13760d4268 OnPage[prPage];l13760d4268e12 ProcessDispatch:e12(1795) PFetch4[prPda,prPsbLink], Disp[MEnter]; *Fetch CurrentPsbl13760d4268(0,13504) PrTail:e12(1795) LoadPage[opPage0], GoTo[PrExit];l13760d4268(0,13504) PrTailx:(1795) LoadPage[opPage0], GoTo[PrExit];l13760d4268(0,13504) PrExit:(1795) GoTo[P4Tail];l13760d4268(0,13504) e12(1795) MEnter:e12 %Monitor Entry is executed by an entry procedure of a Mesa monitor. It returns TRUE on the stack if the monitor was not locked; otherwise the running process is put on the monitor queue, and the stack is left empty. l4512d4268(0,13504) Input:l4512d4268(0,9152) MonitorQ base register pair points to Monitorl8086d5538 Monitor contains MonitorQ^l8086d5538 PsbLink four-word buffer contains CurrentPsbl8086d5538 Exits:l4512d4268 PrTail if enter successfull8086d5538 EntryFailed if enter not successfull8086d5538 %l4512d4268(0,13504) GoTo[EntryFailed,R Odd], *Monitor.locked THEN GoTo EntryFailedl13760d4268 prMonitor _ (prMonitor) OR (monitorLock), *Monitor.lock _ locked l13760d4268 AT[ProcessDisp,MEloc];l13760d4268 PushTrue:e12(1795) Stack&+1 _ 1C; *Push[TRUE].l13760d4268(0,13504) LockMonitor&Exit:e12(1795) PStore1[prMonitorQ,prMonitor,0], *Store Monitorl13760d4268(0,13504) GoTo[PrTail]; *No need to Call ReSchedule because no requeue has occurred.l13760d4268 EntryFailed:e12(1795) %Come here if monitor is already locked. Set EnterFailed. Move the current process from the ready queue to the monitor lock queue. PsbLink will be updated by Requeue when the Psb is stored at exit.l4512d4268(0,13504) Exit:l4512d4268(0,9152) RequeueOp l8086d5538 %l4512d4268(0,13504) prPsbLink _ (prPsbLink) OR (EnterFailed); *CurrentPsb.link.enterFailed _ TRUE.l13760d4268 EntryFailedx:e12(1795) T _ prCurrentPsb; *Prepare to requeue CurrentPsb.l13760d4268(0,13504) prPsbIndex _ T, GoTo[Requeue&ReSchedule]; *Dequeue the CurrentPsb from the ReadyQ. l13760d4268 e12(0,5056)(1,6848)(2,9152)(3,11200)(4,14528) MREnter:e12(1795) %Monitor Re-Entry is used to re-enter a monitor which a process has exited in order to wait on a condition variable queue. If the monitor is locked, the process is placed on the monitor lock queue as in the ME instruction. l4512d4268(0,13504)(1,65535)(2,65535)(3,65535)(4,65535) Input:l4512d4268(0,9152) MonitorQ base register pair points to Monitorl8086d5538 Monitor contains MonitorQ^l8086d5538 ConditionQ base register pair points to Conditionl8086d5538 Condition contains ConditionQ^l8086d5538 PsbLink four-word buffer contains CurrentPsbl8086d5538 Subroutines called:l4512d4268 CleanUpQueue if enter successfull8086d5538 Exits:l4512d4268 PrTail if enter successfull8086d5538 EntryFailed if enter not successfull8086d5538 PRTrap if abortPending and abortablel8086d5538 %l4512d4268(0,13504) GoTo[ReEntryFailed,R Odd], *THEN GoTo ReEntryFailedl13760d4268 prMonitor _ (prMonitor) OR (monitorLock), *Monitor.lock _ locked l13760d4268 *IF monitor.locked l13760d4268 AT[ProcessDisp,MREloc];l13760d4268 NOP; *Placement constraintl13760d4268 UseCTask, Call[CleanUpQueue]; * Clean up the condition queue.l13760d4268 prPsbFlags _ (prPsbFlags) AND NOT T, *Return with PsbIndexMask in T.l13760d4268 Call[StoreCurrentPsb]; *Zero Flags.CleanupLink.l13760d4268 l13760d4268 LU _ (prPsbFlags) AND (AbortPending); *If ~flags.abortPendingl13760d4268 LU _ (prCondition) AND (abortable),l13760d4268 Skip[ALU#0];l13760d4268 Stack&+1 _ 1C, GoTo[LockMonitor&Exit]; *THEN {Push[TRUE];exit}. No need to Call ReSchedule because no requeue has occurred.l13760d4268 T _ (sProcessTrap), *If condition.abortablel13760d4268 GoTo[PRTrap,ALU#0]; *THEN trap.l13760d4268 Stack&+1 _ 1C, *Push[TRUE];l13760d4268 GoTo[LockMonitor&Exit]; *and exitl13760d4268 PRTrap:e12(1795) RTemp _ T, LoadPage[opPage0]; l13760d4268(0,13504) T _ SStkp, GoToP[BackSPPCandTrap]; l13760d4268 ReEntryFailed:e12(1795) prPsbLink _ (prPsbLink) OR (EnterFailed), l13760d4268(0,13504) GoTo[EntryFailedx];l13760d4268 e12(0,5056)(1,6848)(2,9152)(3,11200)(4,14528) MXDepart:e12(1795) %Monitor Exit and Depart is executed at the end of an entry procedure of a Mesa monitor. It unlocks the monitor and if the monitor queue is non-empty its first (i.e., highest priority) entry is moved to the ready queue. l4512d4268(0,13504)(1,65535)(2,65535)(3,65535)(4,65535) Input:l4512d4268(0,9152) MonitorQ base register pair points to Monitorl8086d5538 Monitor contains MonitorQ^l8086d5538 PsbLink four-word buffer contains CurrentPsbl8086d5538 Subroutines called:l4512d4268 ExitMon l8086d5538 Exits:l4512d4268 ReSchedule l8086d5538 %l4512d4268(0,13504) UseCTask, Call[ExitMon], AT[ProcessDisp, MXDloc];l4268 LU _ (prFlags) AND (RequeueOccurred), l13760d4268 GoTo[ReScheduleIfRequeueOccurred];l13760d4268 ExitMon:e12 %ExitMonitor subroutine. l4512d4268 Input:l4512d4268(0,6816) MonitorQ base register pair points to Monitorl8086d5538(0,9152)(1,9152) Monitor contains MonitorQ^l8086d5538 PsbLink four-word buffer contains CurrentPsbl8086d5538(1,65535) Output:l4512d4268(0,6816) PsbIndex PsbIndex pointed to by Monitor.taill8086d5538(0,9152) PsbLink four-word buffer contains Psb to be requeued from MonitorQ to ReadyQ.l9152d5538 Subroutines called:l4512d4268(0,6816) RequeueSub l8086d5538 Exits:l4512d4268 Return to caller l8086d5538 %l4512d4268(0,13504) T _ APC&APCTask, Call[SaveReturnInReturnLink]; l4268 prMonitor _ (prMonitor) AND NOT (monitorLock); *Monitor.lock _ unlocked.l13760d4268 PStore1[prMonitorQ,prMonitor,0],l4268 Call[TGetsPsbIndexMask];l4268 T _ (prMonitor) AND T; *T _ monitor.tail.l13760d4268 PFetch1[prPda,prPsbIndex], *IF monitor.tail # nil THEN fetch monitor.tail^. l13696d4268 GoTo[RequeueMonitorQtoReadyQ, ALU#0];l13696d4268 APC&APCTask _ prReturnLink, l13696d4268 GoTo[PrRet]; *IF monitor.tail = nil THEN exit. l13760d4268 e12(0,5056)(1,6848)(2,9152)(3,11200)(4,14528) MXWait:e12(1795) %Monitor Exit and Wait is executed within a monitor when it is desirable to wait on a condition variable. It unlocks the monitor, and if the monitor queue is non-empty, its first entry is moved to the ready queue. If there is not a wakeup waiting or an abort pending, then the process executing the MXW is moved to the condition variable queue; otherwise it remains on the ready list. Timeout contains timeout. l4512d4268(0,13504)(1,65535)(2,65535)(3,65535)(4,65535) Input:l4512d4268(0,9152) MonitorQ base register pair points to Monitorl9152d5538 Monitor contains MonitorQ^l9152d5538 ConditionQ base register pair points to Conditionl9152d5538 Condition contains ConditionQ^l9152d5538 Timeout contains time out value. This is the same register as WW.l9152d5538 PsbLink four-word buffer contains CurrentPsbl8086d5538 Output:l9152d4268 PsbIndex CurrentPsb for Requeuel9152d5538 PsbLink four-word buffer contains CurrentPsbl8086d5538 Subroutines called:l9152d4268 CleanUpQueue l9152d5538 ExitMon l9152d5538 Exits:l9152d4268 ReSchedule l9152d5538 %l4512d4268(0,13504) UseCTask, Call[CleanUpQueue], AT[ProcessDisp, MXWloc]; l4268 UseCTask, Call[ExitMon];l13760d4268 l13760d4268 *Refetch the CurrentPsb since ExitMon may have called Requeue and wiped out the previous contents. l4512d4268 T _ prCurrentPsb;l13760d4268 PFetch4[prPda,prPsbLink], Call[PrRet];l13760d4268 LU _ (prPsbFlags) AND (AbortPending);l13760d4268 LU _ (prCondition) AND (abortable),l13760d4268 GoTo[MXWait1,ALU = 0]; *If ~abortPendingl13760d4268 GoTo[MXWAbort,ALU#0]; *Goto MXWAbort when PsbFlags.abortPending and Condition.abortable.l13760d4268 NOP; *Placement Constraintl13760d4268 MXWait1:e12(1795) prCondition _ (prCondition) AND NOT (wakeup), *Condition.wakeup _ FALSE.l13760d4268(0,13504) GoTo[MonitorOntoCV, R Even]; *IF prior ~condition.wakeup, GoTo MonitorOntoCV ELSEl13760d4268 PStore1[prConditionQ, prCondition, 0], *Store condition.l13760d4268 GoTo[MXWExit];l13760d4268 MonitorOntoCV:e12 prPsbFlags _ (prPsbFlags) OR (waiting); *Psb.waiting _ TRUE.l13760d4268 prPsbIndex _ T; *Set up PsbIndex for Requeue.l13760d4268 T _ prTimeout; *Put timeout in Psb.l13760d4268 prPsbTimeout _ T, GoTo[ZeroTimeout,ALU=0]; *IF Timeout = 0l13760d4268 prSaveStkP _ IP[prTicks]C, Call[prStkPSave]; *Use StkP to address prTicks (outside RM 0-77)l13760d4268 T _ Stack, Call[prStkPSwap]; *Restore StkPl13760d4268 prPsbTimeout _ (prPsbTimeout) + T; *Timeout _ MAX[1, Ticks + Timeout]l13760d4268 prFlags _ RHMask[prFlags], *Save Requeue bitl13760d4268 GoTo[RequeueToConditionQ,ALU#0];l13760d4268 prPsbTimeout _ 1C, GoTo[RequeueToConditionQ];l13760d4268 prStkPSave:e12 T _ (SStkP&NStkP) xor (377C);l13760d4268 prStkPSwap:e12 prSaveStkP _ T, StkP _ prSaveStkP, NoRegILockOK, Return;l13760d4268 ZeroTimeout:e12 prFlags _ RHMask[prFlags];l13760d4268 *PsbTimeout will be updated when the entire Psb is stored at exit from Requeue. Set up prFlags so we will requeue from the ReadyQ to the ConditionQ. Initially, we were set up to move from the MonitorQ to the ReadyQ. l4512d4268 RequeueToConditionQ:e12 prFlags _ (prFlags) OR (RequeueReadyQtoConditionQ);l13760d4268 Requeue&ReSchedule:e12(1795) UseCTask, Call[RequeueSubPsbFetched]; l13760d4268(0,13504) T _ prCurrentPsb, GoTo[ReSchedule];l13760d4268 MXWExit:e12 MXWAbort: LU _ (prFlags) AND (RequeueOccurred), l13760d4268 GoTo[ReScheduleIfRequeueOccurred];l13760d4268 e12(0,5056)(1,6848)(2,9152)(3,11200)(4,14528) NotifyBroadcast:e12(1795) %Notify moves the first entry of a condition variable queue to the ready queue. Broadcast moves all entries of a condition variable queue to the ready queue. l4512d4268(0,13504)(1,65535)(2,65535)(3,65535)(4,65535) Input:l4512d4268(0,9152) ConditionQ base register pair points to Conditionl8086d5538 Condition contains ConditionQ^l8086d5538 PsbLink four-word buffer contains CurrentPsbl8086d5538 Exits:l4512d4268 ReSchedule l8086d5538 %l4512d4268(0,13504) UseCTask, Call[CleanUpQueue], AT[ProcessDisp, NotifyBroadcastLoc];l13760d4268 T _ prCondition _ (prCondition) AND T,l4268 GoTo[NotifyTestCondition]; l4268 NotifyLoop:e12(1795) PFetch1[prConditionQ,prCondition,0], l4268(0,13504) Call[TGetsPsbIndexMask];l13760d4268 T _ prCondition _ (prCondition) AND T; l4268 NotifyTestCondition:e12(1795) GoTo[NotifyExit,ALU=0]; *IF condition.tail = nil Then Exitl13760d4268(0,13504) UseCTask, Call[WakeHead];l13760d4268 LU _ (prFlags) AND (RequeueOccurred),l13760d4268 DblGoTo[NotifyLoop,ReScheduleIfRequeueOccurred,R<0]; *Loop IF broadcastl13760d4268 NotifyExit:e12 LU _ (prFlags) AND (RequeueOccurred),l13760d4268 GoTo[ReScheduleIfRequeueOccurred]; l13760d4268 WakeHead:e12(1795) %Move the first Psb on ConditionQueue to the ready queue. l4512d4268(0,13504) WakeHead is called:l4512d4268 1. by Broadcast or Notify.l5782d5538 2. by Interrupt processing when an I/O controller has set a bit in NWW that corresponds to a condition in Pda.Interrupt.l6304d5538 Input:l4512d4268(0,6816) ConditionQ base register pair points to Conditionl8086d5538 Condition contains ConditionQ^ not nill8086d5538 Output:l4512d4268 PsbIndex Condition.tail^ for Requeuel8086d5538(0,9152) PsbLink four-word buffer contains Psb pointed to by PsbIndexl9152d5538 Subroutines called:l4512d4268(0,6816) RequeueSub l8086d5538 Exits:l4512d4268 Return to caller from RequeueSubl8086d5538 %l4512d4268(0,13504) T _ APC&APCTask, l4268 Call[SaveReturnInReturnLink]; *Returns with PsbIndexMask in T.l13760d4268 T _ (prCondition) AND T; l4268 PFetch1[prPda,prPsbIndex], *Fetch condition.tail^ into PsbIndex for Requeue.l13760d4268 Call[TGetsPsbIndexMask]; l13760d4268 T _ prPsbIndex _ (prPsbIndex) AND T,l13760d4268 Call[FetchPsb]; *Fetch PsbIndex^ into 4-word Psb buffer.l13760d4268 prPsbFlags _ (prPsbFlags) AND NOT (waiting); *Psb.waiting _ FALSE.l13760d4268 prPsbTimeout _ 0C, *Zero timeoutl13760d4268 GoTo[RequeuePsbFetched]; *Timeout will be updated when Psb is stored at exit from Requeue. l13760d4268 e12(1795) RequeueOp:e12 %Requeue, given a PsbIndex two queue pointers, moves the process from the source queue and inserts it according to priority into the destination queue. l4512d4268(0,13504) Input:l4512d4268(0,9152) ConditionQ base register pair points to Dest queue l8086d5538 MonitorQ base register pair points to Source queuel8086d5538 PsbIndex points to Psb to be requeuedl8086d5538 Exits:l4512d4268 ReSchedule l8086d5538 %l4512d4268(0,13504) UseCTask, Call[RequeueSub], AT[ProcessDisp, REQloc]; l13760d4268 T _ prCurrentPsb, GoTo[ReSchedule];l13760d4268 %Requeue is called:l4268e12 1. by EnterFail to move a Psb from the ready queue to a monitor queue.l6304d5538 2. by ExitMon: if the monitor queue is not empty, to move a Psb from the monitor queue to the ready queue.l6304d5538 3. by Exit&Wait to move a Psb from the ready queue to a condition queue.l6304d5538 4. by WakeHead to move a Psb from a condition queue to the ready queue. WakeHead may have been called by Interrupt.l6304d5538 5. by TimeOut to move a Psb from an unknown condition queue (the source queue points to the first condition in the ConditionVector of the PDA) to the ready queue.l6304d5538 6. by RequeueOp to move a Psb from the source queue (we use MonitorQ) to the dest queue (we use ConditionQ).l6304d5538 Input:l4512d4268(0,9152) prFlags indicates source and dest queuesl8086d5538 PsbIndex PsbIndex of Psb to be requeuedl8086d5538 Output:l4512d4268 prFlags set to indicate requeue occurredl8086d5538 Ready Contains ReadyQueue^l8086d5538 Temps:l4512d4268 PsbLink 4-word buffer contains PsbIndex^ l8086d5538 PsbLink.next Next link of PsbLink l8086d5538 PrevPsbIndex Points to previous Psbl9152d5538 PrevPsbLink PrevPsbIndex^.l9152d5538 PsbPriority Priority of Psb to be requeuedl9152d5538 QTemp Base register pair used to reference source and dest queuesl9152d5538 Queue Contains QTemp^l9152d5538 NextPsb Used by Enqueue to chain Psb according to priorityl9152d5538 Exits:l4512d4268 Return to callerl8086d5538 %l4268(0,13504) RequeueMonitorQtoReadyQ:e12 T _ prPsbIndexMask, GoTo[Requeue]; *Come here from ExitMon.l13696d4268 RequeueSub:e12 T _ APC&APCTask, Call[SaveReturnInReturnLink]; *Returns with PsbIndexMask in Tl13760d4268 Requeue:e12 prPsbIndex _ T _ (prPsbIndex) AND T, l13760d4268 Call[FetchPsb]; *Fetch PsbIndex^ into PsbLink 4-word buffer.l13760d4268 GoTo[RequeuePsbFetched];l13760d4268 RequeueSubPsbFetched:e12 T _ APC&APCTask, Call[SaveReturnInReturnLink]; *Returns with PsbIndexMask in Tl13760d4268 RequeuePsbFetched:e12 Dispatch[prFlags,SourceQbit,2], l4268 Call[SetQTemp]; *Set QTemp to SourceQ. Returns with PsbIndexMask in T.l13760d4268 *First, traverse the source queue looking for the Psb immediately before the Psb pointed to by PsbIndex so that this Psb can be bypassed in the linked queue structure. This starts with the last Psb of a queue since the process instructions always remove the first Psb and the last entry always points to the first. l4512d4268 T _ LDF[prPsbLink,1,3]; *Load PsbLink.priorityl13760d4268 prPsbPriority _ T, *Save priority of Psb to be requeued.l13760d4268 Call[TGetsPsbIndexMask];l13760d4268 *See if Psb to be requeued points to itself. If so, we won't need to unchain it from the previous Psb. l4512d4268e12 T _ (prPsbLink) AND T; *T _ PsbLink.nextl13760d4268 prPsbLink.next _ T;l13760d4268 LU _ (prPsbIndex) - T; *IF prPsbIndex = PsbLink.nextl13760d4268 LU _ (prFlags) AND (SourceQNil), Skip[ALU#0];l13760d4268 prPrevPsbIndex _ Zero, GoTo[SetCleanupLink]; *THEN prev _ nil. We won't need to unchain Psb.l13760d4268 *Continue if the Psb does not point to itself. We must remove it from the source queue. Search for the preceding Psb in the queue. When we are through, PrevPsbIndex will point to the Psb preceding the Psb we wish to dequeue, and PrevPsbLink will contain the Link word of the preceding Psb. Start our search from the tail of the source queue if we know what queue we are on; otherwise search from the Psb being dequeued.l4512d4268 prPrevPsbIndex _ T, *IF source queue nil THEN l13760d4268 GoTo[FetchPrev, ALU # 0]; *PrevPsbIndex _ Link.nextl13760d4268 PFetch1[prQTemp,prQueue,0]; *Fetch SourceQ^ into Queue.l4512d4268 T _ prPsbIndexMask; *ELSE PrevLink _ queue.taill4268 T _ (prQueue) AND T;l4268 FindPrev:e12 prPrevPsbIndex _ T;l13760d4268 FetchPrev: PFetch1[prPda,prPrevPsbLink], *Fetch PrevPsbIndex^ into PrevPsbLink.l13760d4268 Call[TGetsPsbIndexMask];l13760d4268 T _ (prPrevPsbLink) AND T; l13760d4268 LU _ (prPsbIndex) - T; *IF PrevPsbLink.next # PsbIndex l13760d4268 GoTo[FindPrev, ALU#0]; *THEN prPrevPsbIndex _ PrevPsbLink.nextl13760d4268 *Continue when we have found the preceding Psb. Move the next pointer of the Psb being dequeued to the next pointer of the previous Psb.l4512d4268e12 prPrevPsbLink _ (prPrevPsbLink) AND NOT T; *PrevPsbLink.next _ 0l13760d4268 T _ prPsbLink.next, *T _ PsbLink.next l13760d4268 Call[PrevLinkOrT]; *PrevPsbLink.next _ PsbLink.nextl13760d4268 T _ prPrevPsbIndex, TASK;l13760d4268 PStore1[prPda,prPrevPsbLink]; *Store PrevPsbLink.l13760d4268 SetCleanupLink:e12 *Now we have removed the Psb pointed to by PsbIndex from the source queue. If we don't know what queue we are on, set the cleanup link.l4512d4268 PRFlags, GoTo[SourceNotNil, R Even];l13760d4268 *Continue if source is nil. We don't know what queue we are on, so we must set the cleanup link. Take PsbLink.next (of the psb being dequeued) and put it in the cleanup link.l4512d4268e12 T _ prPsbIndexMask; l13760d4268 prPsbFlags _ (prPsbFlags) AND NOT T; *Flags.cleanup _ 0l4268 T _ prPsbLink.next; *Flags.cleanup _ PsbLink.nextl13760d4268 prPsbFlags _ (prPsbFlags) OR T, GoTo[Enqueue];l13760d4268 SourceNotNil:e12 *Come here if the source queue is not nil. We know what queue we are on. If SourceQueue points to the Psb being dequeued, change it to point to the previous Psb.l4512d4268 PFetch1[prQTemp,prQueue,0]; *Fetch SourceQ^ into Queue.l4512d4268 T _ prPsbIndexMask;l13760d4268 T _ (prQueue) AND T; *T _ SourceQ.taill13760d4268 LU _ (prPsbIndex) - T; *IF SourceQ.tail # PsbIndexl13760d4268 prQueue _ (prQueue) AND NOT T,l13760d4268 GoTo[Enqueue,ALU#0]; *THEN GoTo Enqueue; queue.tail _ 0l13760d4268 T _ prPrevPsbIndex;l13760d4268 prQueue _ (prQueue) OR T; *Queue.tail _ PrevPsbIndexl13760d4268 PStore1[prQTemp,prQueue,0]; *Store Queue.taill4268 Enqueue:e12 *Now we are ready to insert the Psb into the dest queue. l4512d4268 Dispatch[prFlags,DestQbit,2], l4268 Call[SetQTemp]; *Set QTemp to DestQl4268 PFetch1[prQTemp,prQueue,0],l4268 Call[TGetsPsbIndexMask];l13760d4268 T _ (prQueue) AND T; *T _ DestQueue.taill13760d4268 prPrevPsbIndex _ T,l13760d4268 GoTo[DestQueueNotNil,ALU#0]; *IF DestQueue.tail # nil THEN GoTo RQDestQueueNotNill13760d4268 *Continue if dest queue is nil. Set the Psb being enqueued to point to itself. Then set DestQ to point to the Psb being enqueued.l4512d4268 T _ prPsbIndexMask;l4512d4268 prPsbLink _ (prPsbLink) AND NOT T; *PsbLink.next _ 0l4512d4268 T _ prPsbIndex;l4512d4268 prPsbLink _ (prPsbLink) OR T; *PsbLink.next _ PsbIndexl4512d4268 T _ prPsbIndexMask, Call[MakeDestQueuePointToPsb];l13760d4268 PFetch1[prPda,prReady,pdaReady!]; *Fetch ReadyQ^ into Ready. l13760d4268 RequeueExit:e12 prFlags _ (prFlags) OR (RequeueOccurred);l13760d4268 T _ prPsbIndex;l13760d4268 Pstore4[prPda, prPsbLink], *Update Psbl13760d4268 GoTo[ReturnLinkRet];l13760d4268 DestQueueNotNil:e12 *Dest queue is not nil. PrevPsbIndex and T contain DestQueue.tail. We must insert the Psb into the DestQueue according to priority. First see if the priority of the Psb is less than or equal to the priority of the last Psb in the DestQueue. If so, we can insert the Psb at the end of the DestQueue.l4512d4268 Pfetch1[prPda,prPrevPsbLink], Call[PrRet]; *Fetch DestQueue.tail^ into PrevPsbLink.l13760d4268 T _ LDF[prPrevPsbLink,1,3]; *T = PrevPsbLink.priorityl13760d4268 LU _ (prPsbPriority) - T - 1; *IF PrevPsbLink.priority >= Psb.priorityl13760d4268 GoTo[ChainToEndOfQueue,ALU < 0], *THEN GoTo ChainToEndOfQueuel13760d4268 T _ prPsbIndexMask;l13760d4268 *Continue if priority of Psb being enqueued is greater than or equal to priority of the Psb at the end of the queue. This means we cannot add it to the end of the queue. We will need to search through the queue and find a place to insert it.l4512d4268e12 T _ (prPrevPsbLink) AND T; *T _ PrevPsbLink.nextl13760d4268 InsertByPriority:l12490d2998 PFetch1[prPda,prNextPsbLink],Call[PrRet]; *Fetch PrevPsbLink.next^ into NextPsbLinkl13760d4268 T _ LDF[prNextPsbLink,1,3]; *T _ NextPsbLink.priorityl13760d4268 LU _ (prPsbPriority) - T - 1; *IF Psb.priority > NextPsbLink.priorityl13760d4268 T _ prPsbIndexMask, l13760d4268 GoTo[InsertPsb, ALU>=0]; *THEN GoTo InsertPsbl13760d4268 T _ (prPrevPsbLink) AND T; *T _ PrevPsbLink.nextl13760d4268 prPrevPsbIndex _ T;l13760d4268 T _ prNextPsbLink;l13760d4268 prPrevPsbLink _ T;l13760d4268 T _ (prPsbIndexMask) AND T, GoTo[InsertByPriority];l13760d4268 ChainToEndOfQueue:e12 *Come here the priority of the Psb to be enqueued is less than or equal to the priority of the last item in the queue. Change the queue head to point to the Psb being enqueued. We chain the new Psb onto the end of the queue.l4512d4268 prQueue _ (prQueue) AND NOT T, *DestQueue.tail _ 0l4512d4268 Call[MakeDestQueuePointToPsbx];l13760d4268 InsertPsb:e12 *Come here when the priority of the Psb to be inserted is greater than the priority of the Psb pointed to by PrevPsbLink.next. Move PrevLink.next to the next field of the Psb being inserted. Change PrevLink.next to point to the Psb being inserted.l4512d4268 prPsbLink _ (prPsbLink) AND NOT T; *PsbLink.next _ 0l13760d4268 T _ (prPrevPsbLink) AND T; *T _ PrevPsbLink.nextl13760d4268 prPsbLink _ (prPsbLink) OR T; *PsbLink.next _ PrevPsbLink.nextl13760d4268 PFetch1[prPda,prReady,pdaReady!]; *Fetch ReadyQ^ into Ready in preparation for exit. l13760d4268 *Now set PrevLink.next to point to Psb being enqueued.l4512d4268e12 T _ prPsbIndexMask,l13760d4268 Call[PrevLinkAndNotT]; *PrevPsbLink.next _ 0l13760d4268 T _ prPsbIndex,l13760d4268 Call[PrevLinkOrT]; *PrevPsbLink.next _ PsbIndexl13760d4268 T _ prPrevPsbIndex;l13760d4268 PStore1[prPda,prPrevPsbLink], *Store PrevPsbLinkl13760d4268 GoTo[RequeueExit];l13760d4268 MakeDestQueuePointToPsb:e12 *Queue contains DestQueue^, T contains PsbIndexMask. Change DestQueue.tail to point to Psb. l4512d4268 prQueue _ (prQueue) AND NOT T; *DestQueue.tail _ 0l4512d4268 MakeDestQueuePointToPsbx:e12 T _ prPsbIndex;l4512d4268 prQueue _ (prQueue) OR T;l4268 PStore1[prQTemp,prQueue,0], GoTo[TGetsPsbIndexMask];l4268 SetQTemp:l3242d2998e12 prQTemp _ 0C, Disp[.+1];l4512d4268 prQTempHi _ 400C, GoTo[TGetsPsbIndexMask], AT[QueueDisp,ReadyQbits];l4512d4268 T _ prMonitorQ, AT[QueueDisp,MonitorQbits];l4512d4268e12 prQTemp _ T;l4512d4268 T _ prMonitorQhi, GoTo[SetQTempHi];l4512d4268 T _ prConditionQ, AT[QueueDisp,ConditionQbits];l4512d4268e12 prQTemp _ T;l4512d4268 T _ prConditionQhi;l4512d4268 SetQTempHi:l3242d2998 prQTempHi _ T, GoTo[TGetsPsbIndexMask]; l4512d4268  CleanUpQueue:e12 %This procedure must be invoked before accessing a condition variable queue since the queue pointer may not be correct. This occurs when the last Psb of a CV queue has been moved to another queue and Requeue did not know which CV queue the Psb belonged to. (This happens when a process times out on a CV queue or is aborted.) When Requeue detects this situation, it causes the Psb's cleanup link to have the value of the Psb's old link field -- which should point to the front of the queue. The goal of this subroutine is to find the correct head of the CV queue, and therefore the tail -- to which the CV should point to. We follow the cleanup links til there are no more, declare the last Psb as the head, and then follow the usual links until the tail is found.l4512d4268 Input:l4512d4268(0,9152) ConditionQ base register pair points to Conditionl9152d5538 Condition contains ConditionQ^l9152d5538 Output:l9152d4268 Condition contains updated ConditionQ^l9152d5538 T contains PsbIndexMaskl9152d5538 Temps: Temps are shared with Requeue Tempsl9152d4268 CleanupLink used to fetch and store CleanupLink l9152d5538 ConditionTail contains Condition.tail l9152d5538 QueueHead contains new head of condition queue l9152d5538 QueueTail contains new tail of condition queue l9152d5538 Exits:l4512d4268 Return to callerl8086d5538 %l4256(0,6560) l13760d4268(0,13504) T _ APC&APCTask, l13760d4268 Call[SaveReturnInReturnLink]; *Returns with PsbIndexMask in T.l13760d4268 T _ (prCondition) AND T; *T _ condition.taill13760d4268 prConditionTail _ T, *Save condition.taill13760d4268 GoTo[ConditionQueueEmpty, ALU=0];l13760d4268 T _ (prConditionTail) + (psbFlags), l13760d4268 Call[FetchCleanupLink]; *Returns with PsbIndexMask in T.l13760d4268 T _ (prCleanupLink) AND T; *IF flags.cleanup = NIL THENl13760d4268 GoTo[CleanupLinkEmpty, ALU=0], *RETURNl13760d4268 LU _ (prConditionTail) - T; *IF Condition.tail = flags.cleanup l13760d4268 GoTo[RemoveSolePsb, ALU=0], *THEN GoTo RemoveSolePsbl13760d4268 prQueueHead _ T; *QueueHead _ flags.cleanupl13760d4268 FindCleanupHead:e12 *Search through the chain until we find a cleanup link that is nil. We then declare this to be the head of the queue. If we find a cleanup link that points to the tail of the queue, then the queue is now empty. l4512d4268 T _ (prQueueHead) + (psbFlags),l13760d4268 Call[FetchCleanupLink]; *Fetch flags word of the next entry in the cleanup link chain.l13760d4268 *T = PsbIndexMaskl13760d4268 T _ (prCleanupLink) AND T; *IF flags.cleanup = NIL THENl13760d4268 GoTo[FoundHead, ALU=0], *THEN GoTo FoundHeadl13760d4268 LU _ (prQueueHead) - T; *IF flags.cleanup = QueueHeadl13760d4268 GoTo[RemoveAllPsbs, ALU = 0]; *THEN GoTo RemoveAllPsbsl13760d4268 prQueueHead _ T, GoTo[FindCleanupHead];l13760d4268 FoundHead:e12 *Come here when QueueHead points to the head of the Psb chain.l4512d4268 T _ MNBR _ prQueueHead; *MNBR _ head of queuel13760d4268 FindQueueTail:e12 prQueueTail _ T, Call[FetchCleanupLink]; *Fetch next linkl13760d4268 prCondition _ (prCondition) AND NOT T; *condition.tail _ nill13760d4268 T _ (prCleanupLink) AND T; *T _ Link.nextl13760d4268 LU _ (MNBR) - T; *IF Link.next # headl13760d4268 GoTo[FindQueueTail, ALU#0];l13760d4268 prCondition _ (prCondition) OR T, *Set condition.taill4268 GoTo[UpdateConditionQueue];l4268 RemoveSolePsb:e12 *Come here if the cleanup link in the Psb points to itself. There was only one Psb in the queue, and we must remove it. We make the queue empty. l4512d4268 prCondition _ (prCondition) AND (abortable), *condition.wakeup _ FALSE. condition.tail _ nill13760d4268 GoTo[UpdateConditionQueue];l13760d4268 RemoveAllPsbs:e12 *Come here if the cleanup link in the Psb points to the last Psb in the Queue. We make the queue empty. l4512d4268 prCondition _ (prCondition) AND (abortable); *condition.wakeup _ FALSE. condition.tail _ nill13760d4268 UpdateConditionQueue: PStore1[prConditionQ,prCondition,0]; l13760d4268 ReturnLinkRet: ConditionQueueEmpty: APC&APCTask _ prReturnLink, GoTo[TGetsPsbIndexMask];l13760d4268 CleanupLinkEmpty: APC&APCTask _ prReturnLink, GoTo[TGetsPsbIndexMask];l13760d4268 FetchCleanupLink:e12 PFetch1[prPda,prCleanupLink], l13760d4268 GoTo[TGetsPsbIndexMask]; *Return with PsbIndexMask in T.l13760d4268 e12 %ReSchedule takes the first (i.e., highest priority) Psb of the ready queue and configures the machine to run that process. The scheduler is always invoked if Requeue has moved some process from or to the ready queue. A process can run until it fails to enter a monitor, waits on a conditon variable with no wakeups waiting, aborts, or an I/O interrupt causes a higher priority process to move to the front of the ready queue.l4512d4268 Input:l4512d4268(0,9152) Ready contains ReadyQueue^ if RequeueSub did a requeue.l9120d5538 LU prFlags AND RequeueOccurred is pendingl8086d5538 LOCAL points to local framel8086d5538 Output:l4512d4268 CurrentPsb updated to point to head of ready queuel8086d5538 xfMX dest link for Xferl8086d5538 xfMY set to zero for Xferl8086d5538 xfBrkByte set to 40400b for Xferl8086d5538 MemStat set to NoPushSD for Xferl8086d5538 Temps: The following are shared with RequeueSub temps.l9152d4268 PsbLink l8086d5538 State Base register pair used to reference Pda.statel9152d5538 StackPointer used to save stack pointer in SVl9152d5538 Frame used to save frame in SVl9152d5538 Subroutines called:l4512d4268 SavPCInFramel8086d5538 Exits:l4512d4268 PrTail if no reschedule necessaryl8086d5538 Xfer if reschedule occurredl8086d5538 Kfcr if wakeup errorl8086d5538 %l4268(0,13504) ReScheduleIfRequeueOccurred:e12 GoTo[PrTailx, ALU=0], *Enter here to reschedule only if requeue occurred.l13760d4268 l13760d4268 T _ prCurrentPsb;l13760d4268 ReSchedule:l12490d2998 *Always come here with T just set to prCurrentPsb. l4512d4268e12 prStateHi _ 400C, *Set up StateHi.l13760d4268 GoTo[RSFindRunnable,ALU=0]; *prCurrentPsb = 0 means not running. If not running, don't save process.l13760d4268 RSSaveProcess:l12490d2998e12 *Note that it is always necessary to save a running process, because its priority may have been changed. l4512d4268e12 PFetch4[prPda,prPsbLink]; *Fetch the running Psb into prPsbLink, prPsbFlags, prPsbContext, prPsbTimeout l13760d4268 T _ LOCAL, Task; l13760d4268 prFrame _ T; *Prepare to save LOCAL in state vector.l13760d4268 LU _ (prFlags) AND (SaveStack); *See if reschedule is due to an interrupt or fault.l13760d4268 prPsbContext _ (Zero) or T, *Prepare to save LOCAL in Psb; interlock PFetch4.l13760d4268 GoTo[RSSavePsb,ALU=0]; *Need only save the Psb when not preempted.l13760d4268 RSAllocState:l12490d2998e12 prPsbLink _ (prPsbLink) OR (vector); *Link.vector _ TRUEl13760d4268 T _ (pdaState), Call[SetState]; *Uses the current priority to return with: (1) T _ prCurrentSAT _ ptr to the StateAllocTable entry. (2) prPtrToSV _ ptr to the first stateVector. l13760d4268 T _ prPtrToSV; l13760d4268 prState _ T; *prPsbContext _ ptr to StateVector.l13760d4268 prPsbContext _ T, *prPsbContext _ ptr to StateVector.l13760d4268 GoTo[RSSVAvailable,ALU#0]; *If there is a StateVectorl13760d4268 *If the ptr to StateVector is 0, then no StateVector is available which is a fatal error. l4512d4268 RSSVError:l12490d2998e12 LoadPageExternal[0];l13760d4268 T _ NoStateVectorError, GoToExternal[CrashLoc]; *MPC = 0726.l13760d4268 RSSVAvailable:l12490d2998e12 PFetch1[prPda,prPtrToSV]; *Fetch ptr to next StateVector for this priority.l13760d4268 T _ prCurrentSAT, l13760d4268 Call[StorePtrToSV]; *Store ptr to next StateVector in StateAllocTable.l13760d4268 RSSaveStack:l12490d2998e12 *Even if the stack pointer is zero, we must save at least two words of the stack, so we do one PStore4. We could do subsequent PStores only if the stack pointer > 3, but time spent testing reduces the average gain and we are tight on space. l4512d4268 PStore2[prState,Stack12,svStack12!], OddOK; *Store Stack12..13l13760d4268 T _ 377C;l13760d4268 T _ (NStkP) xor T; *T _ stack pointerl13760d4268 prStackPointer _ T;l13760d4268 PStore4[prState,Stack0,svStack!], NonQuadOK, Task;l13760d4268 *Save Stack0..3 in StateVector.l13760d4268 T _ svData;l13760d4268 PStore2[prState,prData]; *Save Data in SV. Only meaningful for faults.l13760d4268 PStore4[prState,Stack4,svStack4!], NonQuadOK; *Store Stack4..7l13760d4268 PStore4[prState,Stack8,svStack8!], NonQuadOK, *Store Stack8..11l13760d4268 Call[PrRet]; *Allow write of T.l13760d4268 PStore2[prState,prStackPointer,svWord!]; *Save stack pointer and Local frame pointer in SV.l13760d4268 RSSavePsb:l12490d2998e12 LoadPage[OpPage3];l13760d4268 CallP[SavPCInFrame]; *Save PC in local frame. NOTE: This must be done after RSSaveStack because it clobers prData. Also clobers RTemp1l13760d4268 Stkp _ RZero; *Stack pointer _ 0.l13760d4268 Call[StoreCurrentPsb]; *Store prPsbLink, prPsbFlags, prPsbContext, prPsbTimeout into Current Psb.l13760d4268 RSFindRunnable:l12490d2998e12 PFetch1[prPda,prPsbLink,pdaReady!]; *Fetch ReadyQTailPtrl13760d4268 T _ (prPsbIndexMask),l13760d4268 Call[FetchNextPsb]; *Fetch Tail Psb.l13760d4268 T _ 0C; *To Test For Empty ReadyQl13760d4268 RSFRLoop:l12490d2998e12 LU _ (prReady) XOR T; *End of ReadyQ?l13760d4268 GoTo[NoneReady,ALU=0]; *Yes, and no runnable process found.l13760d4268 T _ prPsbIndexMask, Call[FetchNextPsb]; *Also sets prCurrentPsb.l13760d4268 T _ (pdaState), Call[SetState]; *Uses the current priority to return with: (1) T _ prCurrentSAT _ ptr to the StateAllocTable entry. (2) prPtrToSV _ ptr to the first stateVector. l13760d4268 prPsbLink _ (prPsbLink) AND NOT (vector), *Link.vector _ FALSEl13760d4268 GoTo[RSLoadAndFreeState, R ODD]; *IF Link.vector WAS TRUE THEN load state and run this process. l13760d4268 l4512d4268 *StateVector must be available at current priority to run the process. l4512d4268 LU _ (prPtrToSV); *StateVector available?l13760d4268 T _ (prCurrentPsb), l13760d4268 GoTo[RSFRLoop,ALU=0]; *No, get next process.l13760d4268 l4512d4268 *This process is runnable and doesn't need to LoadStack. l4512d4268 prPsbLink _ (prPsbLink) AND NOT (EnterFailed), *Link.enterFailed _ FALSEl13760d4268 GoTo[RSXfer,R>=0]; *If not enter failed, goto RSXfer l13760d4268 Stack&+1 _ 0C, *Push[FALSE]l13760d4268 GoTo[RSXfer];l13760d4268 RSLoadAndFreeState:l12490d2998e12 *Come here with T = prCurrentSAT. l4512d4268 ***Could move LoadPage down 2 mi, saving 1 mi.l13760d4268 LoadPage[OpPage1]; *Offload crowded prPagel13760d4268 PStore1[prPda,prPsbContext]; *Store ptr to saved StateVector in StateAllocTable.l13760d4268 OnPage[OpPage1]; *Offload crowded prPage l13760d4268 T _ prPsbContext;l13760d4268 prState _ T;l13760d4268 l13760d4268 l13760d4268 PFetch4[prPda,Stack0], NonQuadOK, *Load Stack0..3l13760d4268 Call[P5Ret]; *Alow write of prStatel13760d4268 PFetch2[prState,prStackPointer,svWord!]; *Fetch stack pointer and Frame pointer.l13760d4268 PFetch1[prState,prPsbContext,svFrame!], Call[P5Ret]; *Fetch Frame ptr again.l13760d4268 PFetch4[prState,Stack4,svStack4!], NonQuadOK, Call[P5Ret]; *Load Stack4..7l13760d4268 LU _ StkP _ prStackPointer; *Load stack pointer.l13760d4268 PStore1[prPda,prPtrToSV], Call[P5Ret]; *Store prev. content of SAT in first word of freed stateVector to add this stateVector to the chain. l13760d4268 PFetch4[prState,Stack8,svStack8!], NonQuadOK; *Load Stack8..11l13760d4268 LoadPage[prPage];l13760d4268 PFetch2[prState,Stack12,svStack12!], OddOK; *Load Stack12..Stack13l13760d4268 l13760d4268 OnPage[prPage]; l13760d4268 RSXfer:e12 LoadPage[OpPage2],T _ prPsbContext; *Frame pointer of CurrentPsbl13760d4268 xfMX _ T;l13760d4268 l13760d4268 OnPage[OpPage2]; *Offload crowded prPage l13760d4268 LOCAL _ T; *LOCAL _ destination link.l13760d4268 T _ prCurrentPsb;l13760d4268 PStore4[prPda,prPsbLink], Task;l13760d4268 MemStat _ NoPushSD;l13760d4268 xfBrkByte _ 40400C;l13760d4268 T _ xfMY _ 0C; *Source _ nill13760d4268 LoadPage[xfPage1];l13760d4268 PCB _ 1C, GoToP[Xfer]; *Set PCB to illegal value for Xfer.l13760d4268 l13760d4268 OnPage[prPage];l13760d4268 SetState:e12 *Enters with T set to the Pda relative offset of the beginning of the StateAllocTable. Establishes SAT entry using the current priority from prPsbLink. l4512d4268 *Returns with: (1) T _ prCurrentSAT _ ptr to the StateAllocTable entry. (2) prPtrToSV _ ptr to the first stateVector or 0 if no StateVector available. l4512d4268 T _ (LDF[prPsbLink,priBitPos,priFldSize]) + T; *T _ ptr to the StateAllocTable entry for the current priority.l13760d4268 prCurrentSAT _ T; *Save it in prCurrentSAT.l13760d4268 PFetch1[prPda,prPtrToSV]; *Fetch ptr to first StateVector this priority.l13760d4268 PrRet:l12490d2998 RETURN; l13760d4268 NoneReady:e12 LU _ (xfWDC) - 1, LoadPage[OpPage0]; *Test Wakeup Disable Countl13760d4268 T _ prCurrentPsb _ 0C, GoToP[.+3,ALU<0]; *set to not running. l13760d4268 OnPage[OpPage0];l13760d4268e12 LoadPage[opPage3];l13760d4268 T _ sWakeupError, GoToP[kfcr]; *IF wdc # 0 THEN WakeError l13760d4268 RTemp _ T, Call[.+1]; *Set up for MIPendl13760d4268 *Idle loope12 T _ RZero, GoTo[MIPendy,IntPending];l13760d4268 Return;l13760d4268 l12490d2998 e12 OnPage[PrPage];l4268e12 TGetsFlagsAndT:e12 T _ (prPsbFlags) AND T, RETURN; l13760d4268 TGetsPsbIndexMask:e12 T _ prPsbIndexMask, RETURN;l4268 FlagsOrT:e12 prPsbFlags _ (prPsbFlags) OR T, RETURN;l13760d4268 l4268 SaveReturnInReturnLink: prReturnLink _ T, GoTo[TGetsPsbIndexMask]; *Return with PsbIndexMask in T.l13760d4268 FetchNextPsb:e12 *Enters with T set to prPsbIndexMask. l4512d4268 T _ (prPsbLink) AND T; l13760d4268 prCurrentPsb _ T, Goto[FetchPsb];l4268e12 FetchCurrentPsb:e12 T _ prCurrentPsb;l13760d4268 FetchPsb: PFetch4[prPda,prPsbLink], Goto[PrRet];l13760d4268 StoreCurrentPsb:e12 T _ prCurrentPsb;l13760d4268 StorePsb: PStore4[prPda,prPsbLink], GoTo[PrRet];l13760d4268 StorePtrToSV:e12 PStore1[prPda,prPtrToSV], Goto[PrRet];l13760d4268 PrevLinkAndNotT:e12 prPrevPsbLink _ (prPrevPsbLink) AND NOT T, RETURN;l13760d4268 PrevLinkOrT:e12 prPrevPsbLink _ (prPrevPsbLink) OR T, RETURN;l13760d4268 e12 OnPage[OpPage0];l4268e12 prFault:e12 %l4512d4268 Come here on PageFault, WriteProtectFault or FrameFault.l4512d4268 Input:l4512d4268(0,9152) T FaultOffsetl8086d5538 prData Fault Parameterl8086d5538 Output:l4512d4268 prData(1) For PageFault and WriteProtectFault convert prData to LongPtr to faulted page (page portion a 16 bit -1 if MapOutOfBounds)l9152d5538 Temps:l4512d4268 prConditionQ(hi) Used as base-reg-ptr to Fault[fi].queue and Fault[fi].condition.l9152d5538 prFlags SrcQ and DestQ spec. for RequeueSub and NotifyWakeUp.l9152d5538 prPsbIndex Tell RequeueSub which Psb to requeue.l9152d5538 Subroutines called:l4512d4268 RequeueSubl8086d5538 NotifyWakeUpl8086d5538 Exit:l4512d4268 ReSchedule l8086d5538 %l13760d4268(0,13504) l13760d4268 prFlags _ FaultFlags, AT[prFaultLoc]; *Indicate SrcQ and DestQ for RequeueSub.l13760d4268 *Set prConditionQ to Fault[fi].queue (pda + offset).l4512d4268 T _ (prPda) + T, Task; *Add Pda to fault offset.l13760d4268 prConditionQ _ T;l13760d4268 prConditionQhi _ 400C; *ConditionQhi is PdaHi.l13760d4268 T _ prCurrentPsb, LoadPage[prPage];l13760d4268 prPsbIndex _ T, UseCTask,l13760d4268 Call[RequeueSub]; *Will requeue faulted process from ReadyQ to "ConditionQ" because of prFlags. l13760d4268 prFaultNW:e12 *Call NotifyWakeUp with prConditionQ pointing to Fault[fi].condition and prFlags set for requeue from ConditionQ to ReadyQ.l4512d4268 PFetch1[prPda,prReady,pdaReady!]; *This will be set to ReadyQueue^ if RequeueSub puts someone on the ReadyQueue.l13760d4268 prFlags _ InterruptFlags; *Set to requeue from ConditionQ to ReadyQ.l13760d4268 prConditionQ _ (prConditionQ) + 1, UseCTask,l13760d4268 Call[NotifyWakeUp];l13760d4268 l13760d4268 LU _ (prConditionQ) XOR (qFrameFaultCOS); *Does prConditionQ = Fault[frameFault].cond.l13760d4268 T _ LDF[prData,0,10], l13760d4268 GoTo[prFaultRS, ALU=0]; *Frame Fault doesn't convert prData.l13760d4268 l13760d4268 *Convert page number to long pointer in prData(1) for PageFault or WriteProtectFault.l4512d4268 prData1 _ T; l13760d4268 prData _ LSH[prData,10]; l13760d4268 prFaultRS:e12 prFlags _ (prFlags) OR (SaveStack);l13760d4268 LoadPage[prPage];l13760d4268 T _ prCurrentPsb, l13760d4268 GoToP[ReSchedule]; *Note: ReSchedule stores prData(1) in State.data.l13760d4268 e12 Interrupt:e12 %Come here from MesaX. MesaX has determined that NWW # 0 (there are wakeups waiting), and xfWDC = 0 (wakeups are not disabled). NWW has been set to zero, and WW has been set to the previous contents of NWW. Now we must translate bits in WW into naked notifies. This results in a process being moved from a condition variable queue to the ready queue or else the wakeupWaiting bit of the condition variable is set.l4512d4268 Input:l4512d4268(0,9152) WW previous contents of NWWl8086d5538 Output:l4512d4268 ConditionQ updated to point to a Condition in the Pdal8086d5538 Condition Contents of ConditionQ^l8086d5538 Time updated if timer interruptl8086d5538 Ticks updated if timer interruptl8086d5538 Link set to Condition.tail^ for Requeuel8086d5538 Temps:l4512d4268 PsbLink 4-word Psb bufferl8086d5538 Temp1 temporary (same register as prPsbFlags).l8086d5538 WW when all levels have been checked, we use this for a temporary.l9152d5538 Subroutines called:l4512d4268 RequeueSubl8086d5538 Exits:l4512d4268 ReSchedule l8086d5538 %l4268(0,13504) PFetch1[prPda,prReady,pdaReady!]; *This will be set to ReadyQueue^ if RequeueSub puts someone on the ReadyQueue.l13760d4268 prFlags _ InterruptFlags; *Set to requeue from ConditionQ to ReadyQ.l13760d4268 prConditionQ _ pdaLastInterrupt; *Start with the last interrupt level.l13760d4268 CheckForInterrupt:e12 prConditionQhi _ 400C, *ConditionQhi is the same as PdaHi.l13760d4268e12 Call[CheckLevel];l13760d4268 CheckLevel:e12 WW _ RSH[WW,1], GoTo[IntThisCV,R Odd]; *IF wakeup[intLevel]l13760d4268 GoTo[IntExit,ALU=0]; *Exit if all levels checkedl13760d4268 prConditionQ _ (prConditionQ) - (2C), Return; *Next levell13760d4268 IntThisCV:e12 *Come here if this level has an interrupt.l4512d4268 LU _ (prConditionQ) - (pdaInterrupt); *IF level = 0 THENl13760d4268 prSaveStkP _ IP[prTime]C, GoTo[CheckForTimeouts,ALU=0]; *Check for timeouts ELSEl13760d4268 UseCTask, Call[NotifyWakeUp];l13760d4268 NextLevel:e12 prConditionQ _ (prConditionQ) - (2C), *Next levell13760d4268 GoTo[CheckForInterrupt];l13760d4268 NotifyWakeUp:e12 T _ APCTask&APC; l13760d4268 PFetch1[prConditionQ,prCondition,0]; *Fetch condition.l13760d4268 LoadPage[prPage]; *Cleanup interrupt[level].conditionl13760d4268 prRtnLink2 _ T, UseCTask, Call[CleanUpQueue]; *Returns with PsbIndexMask in T.l13760d4268 LU _ (prCondition) AND T; *IF condition.tail = nil THENl13760d4268 GoTo[NWUQueueNil,ALU=0]; *GoTo QueueNill13760d4268 LoadPage[prPage];l13760d4268 UseCTask, Call[WakeHead];l13760d4268 NWUExit:e12 APCTask&APC _ prRtnLink2;l13760d4268 RETURN;l13760d4268 NWUQueueNil:e12 prCondition _ (prCondition) OR (wakeup); *condition.wakeup _ TRUEl13760d4268 PStore1[prConditionQ,prCondition,0], *Store conditionl13760d4268 GoTo[NWUExit];l13760d4268 l13760d4268 %prRtnLink2 _ T, LoadPage[prPage]; l13760d4268 PFetch1[prConditionQ,prCondition,0]; *Fetch Condition.l13760d4268 OnPage[prPage];l13760d4268 UseCTask, Call[CleanUpQueue]; *Cleanup interrupt[level].conditon;returns with PsbIndexMask in T.l13760d4268 LU _ (prCondition) AND T; *IF condition.tail # nil THENl13760d4268 APCTask&APC _ prRtnLink2, GoTo[WakeHead,ALU#0];l13760d4268 prCondition _ (prCondition) OR (wakeup); *condition.wakeup _ TRUEl13760d4268 APCTask&APC _ prRtnLink2;l4268 PStore1[prConditionQ,prCondition,0], *Store conditionl4268 Return;l13760d4268 OnPage[opPage0];%e12 CheckForTimeouts:e12 T _ (SStkP&NStkP) xor (377C);l4268 prSaveStkP _ T, StkP _ prSaveStkP, NoRegILockOK;l4268 Stack _ (Stack) - 1; *prTime _ (prTime) - 1l4268 PFetch1[prPda,WW,pdaCount!], Skip[ALU=0]; *Fetch Psb count into WWl13760d4268 StkP _ prSaveStkP, GoTo[IntExit];l4268 Stack _ 3C; *prTime _ tickSizel4268 Stack&+1, Task; Stack _ (Stack) + 1; *prTicks _ (prTicks) + 1l4268 *[prTicks is at prTime+1]l4268 *BEGIN TimeoutScan.l13760d4268e12 T _ prPsbIndex _ pdaBlock; *Index of first Psb.l13760d4268 CheckForTimeoutLoop:e12 PFetch4[prPda,prPsbLink], Call[P4Ret]; *Fetch Psb into 4-word bufferl13760d4268 T _ prPsbTimeout; *IF timeout = 0l13760d4268 LU _ (Stack) - T, GoTo[CheckEnd,ALU=0]; *THEN GoTo CheckEndl13760d4268 prPsbTimeout _ 0C, GoTo[Timeout,ALU=0]; *IF timeoutl13760d4268 WW _ (WW) - 1, GoTo[CheckEndx]; *Decrement countl4268e12 Timeout:e12 *Prepare to requeue the Psb pointed to by Link to the Ready queue. The timeout will be updated when the Psb is stored at the exit from Requeue.l4512d4268 prFlags _ (prFlags) OR (SourceQNil);l13760d4268 prPsbFlags _ (prPsbFlags) AND NOT (waiting); *Psb.waiting _ FALSE.l13760d4268 LoadPage[prPage];l13760d4268 UseCTask, Call[RequeueSubPsbFetched];l13760d4268 WW _ (WW) - 1, GoTo[CheckEndx];l13760d4268 CheckEnd:e12 WW _ (WW) - 1; *Decrement countl13760d4268 CheckEndx: T _ prPsbIndex _ (prPsbIndex) + (PsbSize),l13760d4268 GoTo[CheckForTimeoutLoop,ALU#0];l13760d4268 StkP _ prSaveStkP;l13760d4268 IntExit: LU _ prReady, LoadPage[prPage]; *Fetch ready queue into Templ13760d4268 prFlags _ (prFlags) OR (SaveStack), SkipP[ALU=0];l13760d4268 OnPage[prPage];l13760d4268 T _ prCurrentPsb, GoTo[ReSchedule];l13760d4268 GoTo[NoneReady];l13760d4268 *END TimeoutScan.l13760d4268e12 l4268 l13760d4268 :END[MesaP];l13760d4268e12