<> <> <> <> <> <> <> <> <<>> 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] = { pName: Rope.ROPE = IF atom=NIL THEN NIL ELSE Atom.GetPName[atom]; RETURN[MarshalRope[pName, 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 _ IF pName=NIL THEN NIL ELSE 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; }. <> <> <> <> <<>> <<>> <<>> <> <> <> <> <> <> <> <> <> <<>>