DIRECTORY Atom USING [MakeAtom, GetPName], Basics USING [DivMod], LupineRuntime USING [CheckPktLength, CopyFromPkt, CopyToPkt, NilHeader, RopeHeader, Words, WordsForChars], PrincOpsUtils USING [LongCopy], Process USING [Pause], Rope USING [ InlineFlatten, NewText, ROPE, Text ], RPCLupine USING [DataLength, maxDataLength, MaxPacketBufferListSize, maxShortStringLength, PacketBufferCacheListRec, MaxPacketBufferIntervalInRec, ReceiveExtraPkt, RejectUnbound, RPCPkt, SendPrelimPkt ], RPC USING [CallFailed, Zones], SafeStorage USING [GetSystemZone], UnsafeStorage USING [GetSystemUZone], VM USING [AddressForPageNumber, Allocate, CantAllocate, Free, Interval, MakeUnchanged, nullInterval, PageCount, PageNumber, PageNumberForAddress, PagesForWords, SwapIn], VMInternal USING [partitions]; LupineRuntimeImpl: MONITOR LOCKS PacketBufferLock IMPORTS Atom, Basics, Lupine: LupineRuntime, PrincOpsUtils, Process, Rope, RpcPrivate: RPCLupine, RpcPublic: RPC, SafeStorage, UnsafeStorage, VM, VMInternal EXPORTS LupineRuntime, RPCLupine SHARES Rope = { Words: TYPE = LupineRuntime.Words; PacketBufferLock: PUBLIC MONITORLOCK; TranslationError: PUBLIC ERROR = CODE; BindingError: PUBLIC ERROR = CODE; RuntimeError: PUBLIC ERROR = CODE; MarshalingError: PUBLIC PROC = {ERROR}; MarshalingExprError: PUBLIC PROC RETURNS [never: UNSPECIFIED] = { RETURN[ERROR]}; UnmarshalingError: PUBLIC PROC = { ERROR RpcPublic.CallFailed[why: stubProtocol]}; UnmarshalingExprError: PUBLIC PROC RETURNS [never: UNSPECIFIED] = { ERROR RpcPublic.CallFailed[why: stubProtocol]}; DispatchingError: PUBLIC PROC RETURNS [never: UNSPECIFIED] = { ERROR RpcPrivate.RejectUnbound}; defaultZones: PUBLIC RPC.Zones _ [ gc: SafeStorage.GetSystemZone[], heap: UnsafeStorage.GetSystemUZone[], mds: NIL--??-- ]; Checking: BOOLEAN _ TRUE; FinishThisPkt: PUBLIC PROC [pkt: RpcPrivate.RPCPkt, pktLength: RpcPrivate.DataLength ] RETURNS [--zeroPktLength:-- RpcPrivate.DataLength] = { Lupine.CheckPktLength[pkt: pkt, lastPkt: FALSE, pktLength: pktLength]; [] _ RpcPrivate.ReceiveExtraPkt[prevPkt: pkt]; RETURN[0]; }; StartNextPkt: PUBLIC PROC [ pkt: RpcPrivate.RPCPkt, pktLength: RpcPrivate.DataLength ] RETURNS [--zeroPktLength:-- RpcPrivate.DataLength] = { RpcPrivate.SendPrelimPkt[pkt: pkt, length: pktLength]; RETURN[0]; }; CopyToMultiplePkts: PUBLIC PROC [ pkt: RpcPrivate.RPCPkt, pktLength: RpcPrivate.DataLength, dataAdr: LONG POINTER, dataLength: Words ] RETURNS [--newPktLength:-- RpcPrivate.DataLength] = { initialWords: Words = RpcPrivate.maxDataLength - pktLength; wholePkts: CARDINAL _ NULL; finalWords: Words _ NULL; IF Checking AND NOT ( pktLength IN [0..RpcPrivate.maxDataLength] AND dataLength > 0 AND pktLength+dataLength > RpcPrivate.maxDataLength ) THEN ERROR; [quotient: wholePkts, remainder: finalWords] _ Basics.DivMod[ num: dataLength-initialWords, ------------------------ den: RpcPrivate.maxDataLength ]; PrincOpsUtils.LongCopy[ from: dataAdr, to: @pkt.data[pktLength], nwords: initialWords]; dataAdr _ dataAdr + initialWords; THROUGH [0..wholePkts) DO RpcPrivate.SendPrelimPkt[pkt: pkt, length: RpcPrivate.maxDataLength]; PrincOpsUtils.LongCopy[ from: dataAdr, to: @pkt.data[0], nwords: RpcPrivate.maxDataLength]; dataAdr _ dataAdr + RpcPrivate.maxDataLength; ENDLOOP; IF finalWords > 0 THEN { RpcPrivate.SendPrelimPkt[pkt: pkt, length: RpcPrivate.maxDataLength]; PrincOpsUtils.LongCopy[from: dataAdr, to: @pkt.data[0], nwords: finalWords]; RETURN[finalWords]; } ELSE RETURN[RpcPrivate.maxDataLength]; }; CopyFromMultiplePkts: PUBLIC PROC [ pkt: RpcPrivate.RPCPkt, pktLength: RpcPrivate.DataLength, dataAdr: LONG POINTER, dataLength: Words ] RETURNS [--newPktLength:-- RpcPrivate.DataLength] = { firstDataAdr: LONG POINTER = dataAdr; { ENABLE UNWIND => IF dataLength > 0 THEN { firstDataAdr^ _ 0; PrincOpsUtils.LongCopy[ from: firstDataAdr, to: firstDataAdr+1, nwords: dataLength-1 ]; }; initialWords: Words = RpcPrivate.maxDataLength - pktLength; wholePkts: CARDINAL _ NULL; finalWords: Words _ NULL; IF Checking AND NOT ( pktLength IN [0..RpcPrivate.maxDataLength] AND dataLength > 0 AND pktLength+dataLength > RpcPrivate.maxDataLength ) THEN ERROR; [quotient: wholePkts, remainder: finalWords] _ Basics.DivMod[ num: dataLength-initialWords, ------------------------ den: RpcPrivate.maxDataLength ]; PrincOpsUtils.LongCopy[ to: dataAdr, from: @pkt.data[pktLength], nwords: initialWords]; dataAdr _ dataAdr + initialWords; THROUGH [0..wholePkts) DO Lupine.CheckPktLength[ pkt: pkt, lastPkt: FALSE, pktLength: RpcPrivate.maxDataLength ]; [] _ RpcPrivate.ReceiveExtraPkt[prevPkt: pkt]; PrincOpsUtils.LongCopy[ to: dataAdr, from: @pkt.data[0], nwords: RpcPrivate.maxDataLength]; dataAdr _ dataAdr + RpcPrivate.maxDataLength; ENDLOOP; IF finalWords > 0 THEN { Lupine.CheckPktLength[ pkt: pkt, lastPkt: FALSE, pktLength: RpcPrivate.maxDataLength ]; [] _ RpcPrivate.ReceiveExtraPkt[prevPkt: pkt]; PrincOpsUtils.LongCopy[to: dataAdr, from: @pkt.data[0], nwords: finalWords]; RETURN[finalWords]; } ELSE RETURN[RpcPrivate.maxDataLength]; }; -- ENABLE UNWIND. }; MarshalRope: PUBLIC PROC[ rope: Rope.ROPE, pkt: RpcPrivate.RPCPkt, pktLength: RpcPrivate.DataLength, assertShortRope: BOOL] RETURNS[newLength: RpcPrivate.DataLength] = { textRope: Rope.Text; IF pktLength+2 > RpcPrivate.maxDataLength THEN pktLength _ StartNextPkt[pkt: pkt, pktLength: pktLength]; pkt.data[pktLength] _ rope=NIL; newLength _ pktLength+1; IF rope=NIL THEN RETURN; textRope _ Rope.InlineFlatten[r: rope]; IF assertShortRope AND textRope.length > RpcPrivate.maxShortStringLength THEN MarshalingError; pkt.data[newLength] _ textRope.length; newLength _ newLength+1; newLength _ Lupine.CopyToPkt[ pkt: pkt, pktLength: newLength, dataAdr: BASE[DESCRIPTOR[textRope.text]], dataLength: Lupine.WordsForChars[textRope.length], alwaysOnePkt: FALSE]; }; UnmarshalRope: PUBLIC PROC[pkt: RpcPrivate.RPCPkt, pktLength: RpcPrivate.DataLength, assertShortRope: BOOL] RETURNS[rope: Rope.ROPE_NIL, newLength: RpcPrivate.DataLength] = { ropeIsNIL: Lupine.NilHeader; ropeLength: Lupine.RopeHeader; textRope: Rope.Text; IF pktLength+2 > RpcPrivate.maxDataLength THEN pktLength _ FinishThisPkt[pkt: pkt, pktLength: pktLength]; ropeIsNIL _ pkt.data[pktLength]; newLength _ pktLength+1; IF ropeIsNIL THEN RETURN; ropeLength _ pkt.data[newLength]; newLength _ newLength+1; IF assertShortRope AND ropeLength > RpcPrivate.maxShortStringLength THEN UnmarshalingError; rope _ textRope _ Rope.NewText[size: ropeLength]; newLength _ Lupine.CopyFromPkt[ pkt: pkt, pktLength: newLength, dataAdr: BASE[DESCRIPTOR[textRope.text]], dataLength: Lupine.WordsForChars[ropeLength], alwaysOnePkt: FALSE]; }; MarshalAtom: PUBLIC PROC[ atom: ATOM, pkt: RpcPrivate.RPCPkt, pktLength: RpcPrivate.DataLength] RETURNS[newLength: RpcPrivate.DataLength] = { IF atom=NIL THEN atom _ Atom.MakeAtom[""]; RETURN[MarshalRope[Atom.GetPName[atom], pkt, pktLength, FALSE]]; }; UnmarshalAtom: PUBLIC PROC[pkt: RpcPrivate.RPCPkt, pktLength: RpcPrivate.DataLength] RETURNS[atom: ATOM, newLength: RpcPrivate.DataLength] = { pName: Rope.ROPE; [pName, newLength] _ UnmarshalRope[pkt, pktLength, FALSE]; atom _ Atom.MakeAtom[pName]; }; MaxPacketBufferListSize: INT = RPCLupine.MaxPacketBufferListSize; -- Maximum size kept in the cache cacheAllocCount: INT _ 0 ; allocRover: VM.PageNumber _ 0; MaxPacketBufferIntervalInRec: INT = RPCLupine.MaxPacketBufferIntervalInRec; PacketBufferCacheListRec: TYPE = RPCLupine.PacketBufferCacheListRec; PacketBufferCacheList: PUBLIC ARRAY [1..MaxPacketBufferListSize] OF REF PacketBufferCacheListRec _ ALL[NIL]; Alloc: PUBLIC PROC [nWords: CARDINAL] RETURNS [address: LONG POINTER TO WORD] = { nPages: VM.PageCount = MAX[1, VM.PagesForWords[nWords]]; interval: VM.Interval _ VM.nullInterval; IF nPages > MaxPacketBufferListSize THEN { DO interval _ VM.Allocate[count: nPages ! VM.CantAllocate => CONTINUE;]; IF interval.page # 0 THEN { VM.SwapIn[interval]; EXIT; }; Process.Pause[1]; ENDLOOP; address _ VM.AddressForPageNumber[interval.page]; RETURN; } ELSE { found: BOOL; [found, address] _ getFromCache[nPages]; IF ~found THEN { IF cacheAllocCount > 10 THEN cacheAllocCount _ 0; IF cacheAllocCount = 0 THEN allocRover _ VMInternal.partitions[normalVM].page; cacheAllocCount _ cacheAllocCount + 1; DO interval _ VM.Allocate[count: nPages, start: allocRover ! VM.CantAllocate => CONTINUE;]; IF interval.page # 0 THEN EXIT; Process.Pause[1]; ENDLOOP; allocRover _ interval.page; address _ VM.AddressForPageNumber[interval.page]; }; }; }; DeAlloc: PUBLIC PROC[address: LONG POINTER TO WORD, nWords: CARDINAL] = { nPages: VM.PageCount = MAX[1, VM.PagesForWords[nWords]]; interval: VM.Interval _ [page: VM.PageNumberForAddress[address], count: nPages]; IF LOOPHOLE[address, INT] # 0 THEN { IF nPages > MaxPacketBufferListSize THEN { VM.Free[interval]; RETURN; } ELSE { putIntoCache[interval]; }; }; }; getFromCache: ENTRY PROC [nPages: VM.PageCount] RETURNS [found: BOOL, address: LONG POINTER TO WORD] = INLINE { putIndex: INT _ PacketBufferCacheList[nPages].putIndex; IF putIndex > 1 THEN { putIndex_ putIndex - 1; address _ VM.AddressForPageNumber[PacketBufferCacheList[nPages].intervalStarts[putIndex]]; PacketBufferCacheList[nPages].putIndex _ putIndex; found _ TRUE; } ELSE { IF PacketBufferCacheList[nPages].prev = NIL THEN found _ FALSE ELSE { PacketBufferCacheList[nPages] _ PacketBufferCacheList[nPages].prev; address _ VM.AddressForPageNumber[ PacketBufferCacheList[nPages].intervalStarts[MaxPacketBufferIntervalInRec]]; PacketBufferCacheList[nPages].putIndex _ MaxPacketBufferIntervalInRec; found _ TRUE; }; }; }; putIntoCache: ENTRY PROC [interval: VM.Interval] = INLINE { count: INT = interval.count; putIndex: INT _ PacketBufferCacheList[count].putIndex; VM.MakeUnchanged[interval]; -- by making the pages "unchanged", we retain the physical memory associated with this interval (decreases page faults); however we also make the page "clean" in that if it is reclaimed it will not be written to the backing file IF putIndex > MaxPacketBufferIntervalInRec THEN { putIndex _ 1; IF PacketBufferCacheList[count].next = NIL THEN { PacketBufferCacheList[count].next _ NEW [PacketBufferCacheListRec _ [prev: PacketBufferCacheList[count]]]; PacketBufferCacheList[count].next.prev _ PacketBufferCacheList[count]; }; PacketBufferCacheList[count] _ PacketBufferCacheList[count].next; PacketBufferCacheList[count].putIndex _ 1; }; PacketBufferCacheList[count].intervalStarts[putIndex] _ interval.page; PacketBufferCacheList[count].putIndex _ putIndex + 1; }; IF NIL # LOOPHOLE[0, POINTER] THEN ERROR; FOR i: INT IN [1..MaxPacketBufferListSize] DO PacketBufferCacheList[i] _ NEW[PacketBufferCacheListRec _ [prev: NIL]]; ENDLOOP; }. €LupineRuntimeImpl.mesa - used at runtime for marshaling and other common functions Copyright c 1985 by Xerox Corporation. All rights reserved. BZM on 12-May-82 19:17:55. Birrell, September 12, 1983 2:07 pm Swinehart, February 8, 1985 8:37:39 am PST Bob Hagmann May 13, 1985 12:57:04 pm PDT Russ Atkinson (RRA) February 28, 1985 2:05:04 am PST Polle Zellweger (PTZ) August 2, 1985 2:30:18 pm PDT Lupine's Packet Buffer Monitor. Lupine's errors. These procedures map into ERRORs (for now). These procedures map into RpcRuntime ERRORs. Default parameter storage zones. Parameter marshaling routines. Turning this off is okay; critical runtime checks are always on. Preconditions: Put initial data at the end of the current pkt. Put intermediate data into whole pkts. Put final data at the beginning of a fresh pkt. If there's a fault, zero everything. This ensures that any REF-containing fields are NIL and not chaos-causing garbage. Preconditions: Get initial data from the end of the current pkt. Get intermediate data from whole pkts. Get final data from the beginning of a fresh pkt. Packet Buffers Note that there are inline routines in RPCLupine. Packet Buffers Data Packet Buffers Exported Procedures Packet Buffers Internal Procedures Module initialization. CopyTo/FromMultiplePkts assume that zero is the representation of NIL. Bob Hagmann February 8, 1985 3:35:26 pm PST changes to: DIRECTORY Bob Hagmann February 11, 1985 9:51:22 am PST changes to: LupineRuntimeImpl, PacketBufferLock, Packet, MaxPacketBufferListSize, PacketBufferCacheList, DIRECTORY, MaxPacketBufferIntervalInRec, PacketBufferCacheListRec Bob Hagmann March 15, 1985 4:40:18 pm PST changes to: LupineRuntimeImpl Bob Hagmann May 13, 1985 12:48:26 pm PDT add VM.SwapIn call changes to: Alloc Bob Hagmann May 13, 1985 12:56:13 pm PDT changes to: DIRECTORY Polle Zellweger (PTZ) August 2, 1985 2:25:46 pm PDT changes to: MarshalRope Ê A˜codešœR™RKšœ Ïmœ1™Kšžœ˜ K˜K˜——Kšœ ™ ˜šœžœžœ ˜"Kšœ ˜ Kšœ%˜%KšœžÏc˜Kšœ˜—K˜K˜—Kšœ™K˜˜šœ žœžœ˜Kšœ@™@K˜K˜—š Ÿ œžœžœ<žœ œžœ˜Kšœ)žœ˜FK˜.Kšžœ˜ Kšœ˜K˜—š Ÿ œžœžœ=žœ œžœ˜K˜6Kšžœ˜ Kšœ˜K˜K˜—šŸœžœžœFžœžœžœ œžœ˜¼K˜;Kšœ žœžœ˜Kšœžœ˜šžœ žœžœ˜Kšœ™Kšœ žœž˜.Kšœž˜K˜1Kšžœžœ˜ —šœ=˜=˜Kš ˜—K˜ —Kšœ/™/šœ˜K˜?—K˜!Kšœ&™&šžœž˜K˜Ešœ˜K˜C—K˜-Kšžœ˜—Kšœ/™/šžœ˜šžœ˜K˜EKšœL˜LKšžœ ˜Kšœ˜—Kšžœžœ˜&—Kšœ˜K˜—šŸœžœžœFžœžœžœ œžœ˜¾Kšœžœžœ ˜%šœžœžœ˜Kšœ;™;Kšœ<™<šžœžœ˜K˜šœ˜K˜?—Kšœ˜——K˜;Kšœ žœžœ˜Kšœžœ˜šžœ žœžœ˜Kšœ™Kšœ žœž˜.Kšœž˜K˜1Kšžœžœ˜ —šœ=˜=˜Kš ˜—K˜ —Kšœ1™1šœ˜K˜?—K˜!Kšœ&™&šžœž˜˜Kšœžœ(˜@—K˜.šœ˜K˜C—K˜-Kšžœ˜—Kšœ1™1šžœ˜šžœ˜˜Kšœžœ(˜@—K˜.KšœL˜LKšžœ ˜Kšœ˜—Kšžœžœ˜&—Kšœ ˜Kšœ˜K˜—š Ÿ œž œ žœMžœžœ&˜©K˜˜/J˜9—Kšœžœ˜K˜Kšžœžœžœžœ˜K˜'Kšžœžœ3žœ˜^K˜@šœ˜Kšœ)žœž œ˜IKšœAžœ˜H—K˜K˜—šŸ œžœžœLžœžœ žœžœ'˜®Kšœ˜Kšœ˜Kšœ˜šžœ'˜)Kšžœ;˜?—Kšœ ˜ Kšœ˜Kšžœ žœžœ˜Kšœ;˜;Kšžœžœ.žœ˜[Kšœ1˜1šœ˜Kšœ)žœž œ˜IKšœ<žœ˜C—Kšœ˜K˜—šŸ œž œžœ;žœ&˜Kšžœžœžœ˜*Kšžœ2žœ˜@K˜K˜—šŸ œž œ:žœžœ'˜ŽKšœ žœ˜Kšœ3žœ˜:K˜K˜K˜——™K™1™Kšœžœ' "˜eKšœžœ˜Kšœ žœ˜Kšœžœ*˜KKšœžœ&˜DKš œž œžœžœžœžœ˜lK˜—™"šŸœžœžœ žœžœ žœžœžœžœ˜QKšœžœ žœžœ˜8Kšœ žœ žœ˜(šžœ"žœ˜*šž˜Kšœ žœžœžœ˜Ešžœž˜Kšœ˜Kšžœ˜K˜—K˜Kšžœ˜—Kšœ žœ%˜1Kšžœ˜K˜—šœžœ˜Kšœžœ˜ Kšœ(˜(šžœžœ˜Kšžœžœ˜1Kšžœžœ3˜NK˜&šž˜Kšœ žœ-žœžœ˜XKšžœžœžœ˜K˜Kšžœ˜—Kšœ˜Kšœ žœ%˜1K˜—K˜—K˜K˜—šŸœžœžœ žœžœžœžœ žœ˜IKšœžœ žœžœ˜8Kšœ žœžœ/˜Pšžœžœ žœžœ˜$šžœ"žœ˜*Kšžœ˜Kšžœ˜K˜—šœžœ˜Kšœ˜K˜—K˜—Kšœ˜K˜——™"šÏb œžœžœ žœ žœ žœ žœžœžœžœžœ˜qKšœ žœ*˜7šžœžœ˜Kšœ˜Kšœ žœN˜ZKšœ2˜2Kšœžœ˜ K˜—šœžœ˜Kšžœ&žœžœ ž˜>šœžœ˜KšœC˜CKšœ žœc˜oKšœF˜FKšœžœ˜ K˜—K˜—K˜—K˜š ¡ œžœžœ žœ žœ˜;Kšœžœ˜Kšœ žœ)˜6Kšžœ ä˜€šžœ)žœ˜1Kšœ ˜ šžœ%žœžœ˜1Kšœ$žœC˜jKšœF˜FK˜—KšœA˜AKšœ*˜*K˜—KšœF˜FKšœ5˜5K˜——K˜—Kšœ™˜KšœF™FKš žœžœžœžœžœžœ˜)šžœžœžœž˜-Kšœžœ#žœ˜GKšžœ˜——Kšœ˜K˜™+Kšœ Ïr ™—™,Kšœ ¢ž™ª—K™K™K™™)Kšœ ¢™—™(K™Kšœ ¢™—™(Kšœ ¢ ™—™3Kšœ ¢ ™—K™—…—)Ì=