//processb.bc - Lampson&Metcalfe Process Primitives - BCPL
// get "PROCSYMS"
// PROCSYMS - Symbols for process handling in BCPL
//Define process control block structure (PCB)
structure PCB:
[
//Dummy frame at base of process's stack
DummyF word 2 //Dummy frame at top of process's stack
//Interrupts come here directly for context switch
Save3 word //Instruction to save ac 3 below
JSRProcessSave word //Go to shared context switch code
//State of process if not running
Saved0 word //Machine context
Saved1 word
Saved2 word
Saved3 word
SavedCarry word
SavedPC word
SavedStackMinimum word //Saved stack minimum
SavedInterruptsActive word
//PCB pointer for process interrupted by ours
PreviousPCBPointer word
Previous3 word //Used during context switch
Previous2 word
//Address of shared context switching code
AdrProcessSave word //Points to shared context switch code
StackLow word //Will contain lowest stack pointer yet
ProcessNumber word
State word //0 running, 1 suspended, 2 blocked
PCBPointer word
LinkPointer word //For stringing PCB's
]
manifest PCBSize=((size PCB)+15)/16
manifest StackMinimum=#335
manifest msb=#100000
//Define BCPL frame structure for following manipulations
structure Frame:
[
CallersF word
SavedReturn word
Temp word
ExtraArgs word
Formals word
]
//Queue stuff
structure Queue:
[
Head word //Pointer to first item
Tail word //Pointer to last item
]
//Scheduler stuff
structure Schedule:
[
LinkPointer word //For SchedQueue
Predicate word //Called with S, boolean returned
Action word //If predicate true, called with S
Arg1 word //Arguments to Predicate and Action
Arg2 word
Arg3 word
]
// Outgoing externals
external [
BeginProcessInit; BCPLStackHandler
]
// Incoming externals
external [
GetStackPointer
BMOVE
SWAT
]
// Incoming statics
external [
PCBTemplate
ProcessSave
]
//Create process context and return running in it
let BeginProcessInit(ProcNum,Stack,Size)=valof
[
//Compute and check space provided is enough for now
let MyF=GetStackPointer()
let CallersF=MyF>>Frame.CallersF
let CallersFSize=(CallersF>>Frame.CallersF)-CallersF
if (Size ls (CallersFSize+PCBSize)) then
SWAT("PCB and starting frame no fit")
//Move process control block template into space
let NewPCB=Stack+Size-PCBSize //Process Control Block
BMOVE(PCBTemplate,NewPCB,PCBSize-1)
//Copy frame of caller for initial process context
let ProcessF=NewPCB-CallersFSize //A copy
BMOVE(CallersF,ProcessF,CallersFSize-1)
//Link copied frame to dummy in new PCB
let PCBF=lv (NewPCB>>PCB.DummyF) //Frame in PCB
ProcessF>>Frame.CallersF=PCBF
PCBF>>Frame.CallersF=CallersF //For EndProcessInit
PCBF>>Frame.SavedReturn=SWAT-1 //SWAT if process returns
//Finish setting up new PCB
NewPCB>>PCB.PCBPointer=NewPCB //For CurrentPCB
NewPCB>>PCB.SavedStackMinimum=Stack
NewPCB>>PCB.Saved2=ProcessF //Context is copied frame
NewPCB>>PCB.AdrProcessSave=ProcessSave
NewPCB>>PCB.ProcessNumber=ProcNum
NewPCB>>PCB.SavedInterruptsActive=(1 lshift ProcNum)-1
NewPCB>>PCB.StackLow=-1 //Mark unrecorded
NewPCB>>PCB.State=2 //Mark process blocked
NewPCB>>PCB.PreviousPCBPointer=0 //No previous (yet)
if PCBTemplate>>PCB.ProcessNumber eq 0 then [
PCBTemplate>>PCB.PCBPointer=PCBTemplate //For CurrentPCB
PCBTemplate>>PCB.ProcessNumber=-1
PCBTemplate>>PCB.StackLow=-1 //Mark unrecorded
PCBTemplate>>PCB.State=0 //Mark process running
PCBTemplate>>PCB.PreviousPCBPointer=0 //None
PCBTemplate>>PCB.AdrProcessSave=SWAT-1 //Never blocks
]
//Switch to process's context for initalization
MyF>>Frame.CallersF=ProcessF //Process's context
NewPCB>>PCB.SavedStackMinimum=@StackMinimum
@StackMinimum=Stack //So init can call things
resultis lv (NewPCB>>PCB.Save3) //Int vec
]
and BCPLStackHandler() be
[
manifest [ AdrGetFrame=#370]
manifest [ CallSWAT=#77400]
@((@AdrGetFrame)+30)=CallSWAT
]