// PupSubrs.bcpl. The Interlisp-D Pup package
// Last change October 12, 1981 11:30 PM by Bill van Melle
// Last change August 3, 1981 3:54 AM by Beau Sheil
// Last change July 20, 1981 10:28 PM by Beau Sheil
// Last change July 13, 1981 12:44 AM by Beau Sheil
// Last change March 16, 1981 12:28 PM by Beau Sheil
// Last change February 13, 1981 6:24 PM by Beau Sheil
// This file contains Pup subrs called from Lisp. It also has the entry
// which starts up the pup package and enqueue its contexts onto ContextQ
get "Pup0.decl"
get "Pup1.decl"
external [ // procedures defined
OPENSOCKET // Subr: () -> socket
READPUP // Subr: (soc, head, buf, lim) -> ?
WRITEPUP // Subr: (soc, head, buf)
CLOSESOCKET // Subr: (soc)
OpenSoc; CloseSoc; StartPup
// procedures used
MkSmallPos; EqNIL; @XGetBase // other Lisp externals
MoveWords; SmallUnbox; EmAddr; RAIDCode
Enqueue; Dequeue; Block; Min // OS procs
InitializeZone; Allocate; Free; Zero; InitializeContext
// statics used
@ContextQ; maxPupDataBytes; @lvNIL; @lvKT
OpenLevel1Socket; InitPupLevel1; CompletePup // Pup stuff
socketQ; GetPBI; CloseLevel1Socket; ReleasePBI
]
manifest [ pupHdrWords = pupOvWords-1 // Size of pup header in words
]
static [ PupZone // zone for pup allocations
XtraQ // queue of "extra" output PBIs
XUses = 0 // how many xtras are used
]
let OPENSOCKET(hi, lo) = MkSmallPos(OpenSoc(SmallUnbox(hi), SmallUnbox(lo)))
and OpenSoc(hi, lo) = valof // OpenSoc split out for Raid
[ let s = Allocate(PupZone, lenPupSoc)
let lclPort = vec lenPort
Zero(lclPort, lenPort)
lclPort>>Port.socket↑1=hi
lclPort>>Port.socket↑2=lo
OpenLevel1Socket(s, lclPort)
resultis s
]
and READPUP(soc, head, buf, lim; numargs na) = valof
[ let s = Socket(soc)
unless s resultis lvNIL
let pb = Dequeue(lv s>>PupSoc.iQ)
unless pb do resultis lvNIL
let pup = lv pb>>PBI.pup
let n = (pup>>Pup.length+1) rshift 1
test (na ls 3) % EqNIL(buf)
ifso [ // contiguous pup
MoveWords(EmAddr(pup), head, n)
]
ifnot [ // old style, two pieces
MoveWords(EmAddr(pup), head, pupHdrWords)
n = Min(n - pupOvWords, SmallUnbox(lim))
MoveWords(EmAddr(lv pup>>Pup.words↑1), buf, n)
]
ReleasePBI(pb)
resultis MkSmallPos(n)
]
and WRITEPUP(soc, head, buf; numargs na) = valof
[ let s = Socket(soc)
unless s resultis lvNIL
let nwords = (XGetBase(head) + 1) rshift 1
// first word of pup (head) is byte len
if nwords gr (pupOvWords+(maxPupDataBytes rshift 1))
then resultis RAIDCode ("Pup too long", head)
let pb = nil // get a PBI to transmit this
[
pb = GetPBI(s, true) // return if none left
test pb
ifso break
ifnot [ pb = GetExtraPBI(s)
test pb ifso break ifnot Block() ]
] repeat
let pup = lv pb>>PBI.pup
test (na ls 3) % EqNIL(buf)
ifso [ // contiguous pup
MoveWords(head, EmAddr(pup), nwords)
]
ifnot [ // old style, two pieces
MoveWords(head, EmAddr(pup), pupHdrWords)
MoveWords(buf, EmAddr(lv pup>>Pup.words↑1), nwords-pupHdrWords)
]
test SocHeadChk(s, pb)
ifso [ CompletePup(pb); resultis lvKT ]
ifnot [ ReleasePBI (pb); resultis lvNIL]
]
and CLOSESOCKET(soc) = valof [ CloseSoc(Socket(soc)); resultis lvNIL ]
and CloseSoc(s) be [ CloseLevel1Socket(s); Free(PupZone, s) ]
and StartPup(zone, zoneLength) be
[ PupZone = InitializeZone(zone, zoneLength)
InitPupLevel1(PupZone, ContextQ, 22)
XtraQ = Allocate(PupZone, 2)
Zero(XtraQ, 2) // extra output pbis
let lPBI = (pupOvBytes+maxPupDataBytes)/2 + lenPBIOverhead
for i=1 to 3 do Enqueue(XtraQ, Allocate(PupZone, lPBI))
]
and Socket(soc) = valof
[ let t = SmallUnbox(soc)
let s = socketQ
[ s = s>>PupSoc.link
if s eq t then resultis t ] repeatwhile s
RAIDCode("Not an open socket", soc)
resultis false
]
and SocHeadChk(s, pb) = valof
[ let bs = lv s>>PupSoc.lclPort // Socket's local port spec
let bpb = lv pb>>PBI.pup.sPort // local port of pup
for i=(offset Port.socket/16) to lenPort-1 // skip over poss. 0 net addr
do unless bs!i eq bpb!i
do [ ReleasePBI(pb)
resultis RAIDCode("Socket/header mismatch for socket", MkSmallPos(s))
]
resultis true
]
and GetExtraPBI(soc) = valof // from a secret stash, for output
[ let pb = Dequeue(XtraQ)
if pb then [ Zero(pb, lenPBIOverhead+pupOvWords) // clear header
pb>>PBI.socket = soc
pb>>PBI.queue = XtraQ // so it comes back
XUses = XUses + 1 // count it
]
resultis pb
]