<> <> <> <> <<>> DIRECTORY Allocator USING [NHeaderP, NormalHeader], Basics USING [BITAND, bytesPerWord], Checksum USING [ComputeChecksum], CommBuffer USING [Direction, Encapsulation], CommDriver USING [AllocBuffer, Buffer, BufferObject, FreeBuffer, GetNetworkChain, Network], Endian USING [bytesPerFWord, bytesPerHWord, CardFromH, HFromCard, HWORD], PrincOpsUtils USING [LongMove], Process USING [Detach, DisableTimeout, EnableAborts, MsecToTicks, Pause, priorityBackground, SecondsToTicks, SetPriority, SetTimeout, Ticks], SafeStorage USING [EnableFinalization, EstablishFinalization, FinalizationQueue, FQNext, NewFQ], XNS USING [Address, broadcastHost, broadcastNet, GetThisHost, Host, Net, Socket, unknownAddress, unknownNet, unknownSocket], XNSBuf USING [Buffer, BufferObject, hdrBytes, maxBodyBytes, maxBodyFWords, maxBodyHWords], XNSErrorBuf USING [Buffer, hdrBytes], XNSErrorTypes USING [badChecksumErr, ErrorType, noSocketErr, nullParam, resourceLimitsErr, unspecifiedInRouteErr], XNSRouterPrivate USING [Route], XNSSocket USING [dontWait, Milliseconds, waitForever], XNSSocketBackdoor USING [ReceiveProc], XNSWKS USING [last]; XNSSocketImpl: CEDAR MONITOR LOCKS handle USING handle: Handle IMPORTS Basics, Checksum, CommDriver, Endian, XNS, XNSRouterPrivate, PrincOpsUtils, Process, SafeStorage EXPORTS XNSRouterPrivate, XNSSocket, XNSSocketBackdoor ~ { Address: TYPE ~ XNS.Address; Net: TYPE ~ XNS.Net; Host: TYPE ~ XNS.Host; Socket: TYPE ~ XNS.Socket; Buffer: TYPE ~ XNSBuf.Buffer; Network: TYPE ~ CommDriver.Network; Milliseconds: TYPE ~ XNSSocket.Milliseconds; ReceiveProc: TYPE ~ XNSSocketBackdoor.ReceiveProc; Direction: TYPE ~ CommBuffer.Direction; HWORD: TYPE ~ Endian.HWORD; bytesPerHWord: NAT ~ Endian.bytesPerHWord; bytesPerFWord: NAT ~ Endian.bytesPerFWord; bytesPerWord: NAT ~ Basics.bytesPerWord; thisHost: Host ~ XNS.GetThisHost[]; <> RealDriverBuffer: PROC [b: Buffer] RETURNS [CommDriver.Buffer] = TRUSTED INLINE { nhp: Allocator.NHeaderP _ LOOPHOLE[b, Allocator.NHeaderP]-SIZE[Allocator.NormalHeader]; nhp.type _ CODE[CommDriver.BufferObject]; b.ovh.direction _ none; b.ovh.socket _ NIL; RETURN[LOOPHOLE[b]]; }; TempDriverBuffer: PROC [b: Buffer] RETURNS [CommDriver.Buffer] = TRUSTED INLINE { RETURN[LOOPHOLE[b]]; }; RealXNSBuffer: PROC [b: CommDriver.Buffer, d: Direction] RETURNS [Buffer] = TRUSTED INLINE { nhp: Allocator.NHeaderP _ LOOPHOLE[b, Allocator.NHeaderP]-SIZE[Allocator.NormalHeader]; nhp.type _ CODE[XNSBuf.BufferObject]; b.ovh.next _ NIL; b.ovh.direction _ d; RETURN[LOOPHOLE[b]]; }; Next: PROC [b: Buffer] RETURNS [Buffer] = TRUSTED INLINE { RETURN[LOOPHOLE[b.ovh.next]]; }; <> Handle: TYPE ~ REF Object; Object: PUBLIC TYPE ~ MONITORED RECORD [ local, remote: Address, sendBuffersInUse: CARDINAL _ 0, sendBuffersAllocated: CARDINAL, recvBuffersInUse: CARDINAL _ 0, recvBuffersAllocated: CARDINAL, routingCache: Routing _ NIL, receiveProc: ReceiveProc _, receiveClientData: REF ANY _ NIL, sendChecksum, recvChecksum: BOOL _ TRUE, dead, noErrors: BOOL _ FALSE, dontWait: BOOL _ FALSE, waitForInput, waitForSendBuffer: CONDITION, firstInput, lastInput: Buffer _ NIL, next: Handle _ NIL ]; Routing: TYPE ~ REF RoutingInfo; RoutingInfo: TYPE ~ RECORD [ network: Network, immediate: Host, -- Not Necessary ???? encap: CommBuffer.Encapsulation ]; <> numHashHeaders: CARDINAL ~ 64; HashIndex: TYPE ~ [0 .. numHashHeaders); ObjectTable: TYPE ~ REF ObjectTableRep; ObjectTableRep: TYPE ~ ARRAY HashIndex OF Handle; objectTable: ObjectTable ~ NEW[ObjectTableRep]; objectTableLock: Handle ~ NEW[Object _ [local~, remote~, sendBuffersAllocated~, recvBuffersAllocated~, receiveProc~NIL]]; Hash: PROC [socket: Socket] RETURNS [HashIndex] ~ INLINE { RETURN [socket.b MOD numHashHeaders] }; AddNewHandle: ENTRY PROC [handle: Handle _ objectTableLock, newHandle: Handle] ~ { <> i: HashIndex ~ Hash[newHandle.local.socket]; newHandle.next _ objectTable^[i]; objectTable^[i] _ newHandle; }; RemoveOldHandle: ENTRY PROC [handle: Handle _ objectTableLock, oldHandle: Handle] ~ { <> i: HashIndex ~ Hash[oldHandle.local.socket]; IF oldHandle = objectTable^[i] THEN { objectTable^[i] _ oldHandle.next } ELSE { prev: Handle; FOR prev _ objectTable^[i], prev.next WHILE prev.next # oldHandle DO NULL ENDLOOP; prev.next _ oldHandle.next }; oldHandle.next _ NIL; -- Help finalization of oldHandle.next^ }; FindHandle: PROC [localSocket: Socket] RETURNS [Handle] ~ { i: HashIndex ~ Hash[localSocket]; FOR handle: Handle _ objectTable^[i], handle.next UNTIL handle = NIL DO -- ATOMIC IF handle.local.socket = localSocket THEN RETURN[handle]; ENDLOOP; RETURN[NIL] }; <> uniqueSocketLock: Handle ~ NEW[Object _ [local~[net~, host~, socket~XNSWKS.last], remote~, sendBuffersAllocated~, recvBuffersAllocated~, receiveProc~NIL]]; NextLocalSocket: ENTRY PROC [handle: Handle _ uniqueSocketLock] RETURNS [Socket] ~ TRUSTED { temp: HWORD _ LOOPHOLE[uniqueSocketLock.local.socket]; temp _ Endian.HFromCard[Endian.CardFromH[temp] + 1]; RETURN [uniqueSocketLock.local.socket _ LOOPHOLE[temp]] }; <> noChecksum: Endian.HWORD ~ 0FFFFH; -- Should move to XNSBuf ???? GetBytesRounded: PROC [b: Buffer] RETURNS [CARDINAL] ~ INLINE { <> RETURN[Basics.BITAND[(1+Endian.CardFromH[b.hdr1.length]),0FFFEH]]; }; InlineSetChecksum: PROC [b: Buffer, bytes: CARDINAL, computed: BOOL _ TRUE] ~ TRUSTED INLINE { <> <> <> IF computed THEN { words: CARDINAL _ (bytes - bytesPerHWord) / bytesPerWord; checksumLoc: LONG POINTER _ @b.hdr1.checksum; checksumLoc^ _ Checksum.ComputeChecksum[0, words, @b.hdr1.length] } ELSE { b.hdr1.checksum _ noChecksum }; }; InlineTestChecksum: PROC [b: Buffer, bytes: CARDINAL] RETURNS [BOOL] ~ TRUSTED INLINE { <> <> <> <> IF b.hdr1.checksum # noChecksum THEN { words: CARDINAL ~ (bytes - bytesPerHWord) / bytesPerWord; myChecksum: HWORD ~ Checksum.ComputeChecksum[0, words, @b.hdr1.length]; RETURN [ b.hdr1.checksum = myChecksum ] } ELSE RETURN[TRUE]; }; <<>> SetChecksum: PUBLIC PROC [b: Buffer] ~ { InlineSetChecksum[b, GetBytesRounded[b]] }; <> Create: PUBLIC PROC [ remote: Address _ XNS.unknownAddress, sendBuffers: NAT _ 1, recvBuffers: NAT _ 5, getTimeout: Milliseconds _ 10000, local: Socket _ XNS.unknownSocket ] RETURNS [handle: Handle] ~ { network: Network; network _ XNSRouterPrivate.Route[remote].network; IF network = NIL THEN network _ CommDriver.GetNetworkChain[]; IF local = XNS.unknownSocket THEN local _ NextLocalSocket[]; handle _ NEW [Object _ [ local~[net~network.xns.net, host~thisHost, socket~local], remote~remote, sendBuffersAllocated~sendBuffers, recvBuffersAllocated~recvBuffers, receiveProc~NormalReceive ] ]; TRUSTED { Process.EnableAborts[@handle.waitForInput]; Process.EnableAborts[@handle.waitForSendBuffer] }; SetGetTimeout[handle, getTimeout]; AddNewHandle[newHandle~handle]; SafeStorage.EnableFinalization[handle]; }; GetLocalAddress: PUBLIC PROC [handle: Handle] RETURNS [Address] ~ { RETURN[handle.local]; }; GetRemoteAddress: PUBLIC PROC [handle: Handle] RETURNS [Address] ~ { RETURN[handle.remote]; }; SetRemoteAddress: PUBLIC PROC [handle: Handle, address: Address] ~ { handle.remote _ address; }; SetGetTimeout: PUBLIC PROC [handle: Handle, ms: Milliseconds] ~ { handle.dontWait _ FALSE; SELECT ms FROM XNSSocket.dontWait => handle.dontWait _ TRUE; XNSSocket.waitForever => TRUSTED { Process.DisableTimeout[@handle.waitForInput]; }; < CARDINAL.LAST => TRUSTED { Process.SetTimeout[@handle.waitForInput, Process.MsecToTicks[ms] ]; }; ENDCASE => TRUSTED { Process.SetTimeout[@handle.waitForInput, Process.SecondsToTicks[ms/1000] ]; }; }; <<>> SetSoftwareChecksumming: PUBLIC PROC [handle: Handle, send, recv: BOOL] ~ { handle.sendChecksum _ send; handle.recvChecksum _ recv; }; <<>> SetNoErrors: PUBLIC PROC [handle: Handle, noErrors: BOOL _ TRUE] ~ { handle.noErrors _ noErrors; }; Kick: PUBLIC ENTRY PROC [handle: Handle] ~ { NOTIFY handle.waitForInput; }; <<>> Destroy: PUBLIC ENTRY PROC [handle: Handle] ~ { handle.dead _ TRUE; UNTIL handle.firstInput = NIL DO b: Buffer _ handle.firstInput; handle.firstInput _ Next[b]; handle.recvBuffersInUse _ handle.recvBuffersInUse - 1; CommDriver.FreeBuffer[RealDriverBuffer[b]]; ENDLOOP; handle.lastInput _ NIL; -- Help Buffer finalization. IF handle.noErrors OR (handle.recvBuffersInUse # 0) OR (handle.sendBuffersInUse # 0) THEN TRUSTED { Process.Detach[FORK DestroyDally[handle]]; RETURN }; <> }; DestroyDally: PROC [handle: Handle] ~ { oneSecond: Process.Ticks = Process.SecondsToTicks[10]; Process.SetPriority[Process.priorityBackground]; IF handle.noErrors THEN Process.Pause[10*oneSecond]; WHILE (handle.recvBuffersInUse # 0) OR (handle.sendBuffersInUse # 0) DO Process.Pause[oneSecond]; ENDLOOP; <> }; <> AllocBuffer: PUBLIC PROC [handle: Handle] RETURNS [b: Buffer] ~ { InnerAllocBuffer[handle]; b _ RealXNSBuffer[CommDriver.AllocBuffer[], send]; b.ovh.next _ NIL; b.ovh.socket _ handle; -- needed for finalization }; <<>> InnerAllocBuffer: ENTRY PROC [handle: Handle] ~ { ENABLE UNWIND => NULL; UNTIL handle.sendBuffersInUse < handle.sendBuffersAllocated DO WAIT handle.waitForSendBuffer; ENDLOOP; handle.sendBuffersInUse _ handle.sendBuffersInUse + 1; }; SetUserBytes: PUBLIC PROC [b: Buffer, bytes: [0 .. XNSBuf.maxBodyBytes]] ~ { b.hdr1.length _ Endian.HFromCard[bytes + XNSBuf.hdrBytes]; }; SetUserHWords: PUBLIC PROC [b: Buffer, hWords: [0 .. XNSBuf.maxBodyHWords]] ~ { b.hdr1.length _ Endian.HFromCard[hWords*bytesPerHWord + XNSBuf.hdrBytes]; }; SetUserFWords: PUBLIC PROC [b: Buffer, fWords: [0 .. XNSBuf.maxBodyFWords]] ~ { b.hdr1.length _ Endian.HFromCard[fWords*bytesPerFWord + XNSBuf.hdrBytes]; }; SetUserSize: PUBLIC PROC [b: Buffer, sizeUnits: NAT] ~ { b.hdr1.length _ Endian.HFromCard[sizeUnits*bytesPerWord + XNSBuf.hdrBytes]; -- Fix when BYTES[...] is implemented }; <<>> Broadcast: PUBLIC PROC [handle: Handle, b: Buffer, socket: Socket] ~ { bytes: CARDINAL ~ GetBytesRounded[b]; b.hdr1.transportCtl _ [trace~FALSE, filler~0, hopCount~0]; b.hdr1.dest.socket _ socket; b.hdr1.dest.host _ XNS.broadcastHost; b.hdr1.source _ handle.local; FOR network: Network _ CommDriver.GetNetworkChain[], network.next UNTIL network = NIL DO b.ovh.encap _ network.xns.getEncapsulation[network, XNS.broadcastHost]; b.hdr1.dest.net _ network.xns.net; b.hdr1.source.net _ network.xns.net; InlineSetChecksum[b, bytes, handle.sendChecksum]; network.xns.send[network, TempDriverBuffer[b], bytes]; ENDLOOP; FreeBuffer[handle, b]; }; Put: PUBLIC PROC [handle: Handle, b: Buffer] ~ { Send[handle, b, handle.remote]; -- What if it's UNKNOWN??? }; <<>> Send: PUBLIC PROC [handle: Handle, b: Buffer, dest: Address] ~ { bytes: CARDINAL = GetBytesRounded[b]; network: Network; immediate: Host; IF (dest.net = XNS.broadcastNet) AND (dest.host = XNS.broadcastHost) THEN { Broadcast[handle, b, dest.socket]; RETURN; }; b.hdr1.transportCtl _ [trace~FALSE, filler~0, hopCount~0]; b.hdr1.dest _ dest; b.hdr1.source _ handle.local; [network, immediate] _ XNSRouterPrivate.Route[dest]; IF network # NIL THEN { b.ovh.encap _ network.xns.getEncapsulation[network, immediate]; InlineSetChecksum[b, bytes, handle.sendChecksum]; network.xns.send[network, TempDriverBuffer[b], bytes]; }; FreeBuffer[handle, b]; }; <> PutCached: PUBLIC PROC [handle: Handle, b: Buffer] ~ { bytes: CARDINAL = GetBytesRounded[b]; network: Network; immediate: Host; routingCache: Routing _ handle.routingCache; IF routingCache = NIL THEN { [network, immediate] _ XNSRouterPrivate.Route[handle.remote]; IF network = NIL THEN RETURN; handle.routingCache _ routingCache _ NEW [RoutingInfo _ [network~network, immediate~immediate, encap~network.xns.getEncapsulation[network, immediate]]]; }; b.hdr1.transportCtl _ [trace~FALSE, filler~0, hopCount~0]; b.hdr1.dest _ handle.remote; b.hdr1.source _ handle.local; b.ovh.encap _ routingCache.encap; InlineSetChecksum[b, bytes, handle.sendChecksum]; routingCache.network.xns.send[routingCache.network, TempDriverBuffer[b], bytes]; }; FlushCache: PUBLIC PROC [handle: Handle] ~ { handle.routingCache _ NIL; }; <> Get: PUBLIC ENTRY PROC [handle: Handle] RETURNS [b: Buffer] ~ { ENABLE UNWIND => NULL; IF (handle.firstInput = NIL) AND NOT handle.dontWait THEN WAIT handle.waitForInput; IF (b _ handle.firstInput) # NIL THEN { handle.firstInput _ Next[b]; b.ovh.socket _ handle; -- needed for finalization }; }; <<>> GetUserBytes: PUBLIC PROC [b: Buffer] RETURNS [bytes: [0 .. XNSBuf.maxBodyBytes]] ~ { bytes _ Endian.CardFromH[b.hdr1.length] - XNSBuf.hdrBytes; }; GetUserHWords: PUBLIC PROC [b: Buffer] RETURNS [hWords: [0 .. XNSBuf.maxBodyHWords]] ~ { bytes: [0 .. XNSBuf.maxBodyBytes] _ Endian.CardFromH[b.hdr1.length] - XNSBuf.hdrBytes; hWords _ bytes/bytesPerHWord; }; GetUserFWords: PUBLIC PROC [b: Buffer] RETURNS [fWords: [0 .. XNSBuf.maxBodyFWords]] ~ { bytes: [0 .. XNSBuf.maxBodyBytes] _ Endian.CardFromH[b.hdr1.length] - XNSBuf.hdrBytes; fWords _bytes/bytesPerFWord; }; GetUserSize: PUBLIC PROC [b: Buffer] RETURNS [sizeUnits: NAT] ~ { bytes: [0 .. XNSBuf.maxBodyBytes] _ Endian.CardFromH[b.hdr1.length] - XNSBuf.hdrBytes; sizeUnits _ bytes/bytesPerWord; -- Fix when BYTES[...] is implemented. }; FreeBuffer: PUBLIC ENTRY PROC [handle: Handle, b: Buffer] ~ { SELECT b.ovh.direction FROM send => { handle.sendBuffersInUse _ handle.sendBuffersInUse - 1; NOTIFY handle.waitForSendBuffer }; recv => handle.recvBuffersInUse _ handle.recvBuffersInUse - 1; ENDCASE => ERROR; CommDriver.FreeBuffer[RealDriverBuffer[b]]; }; <<>> FixupSourceAndDest: PUBLIC PROC [b: Buffer] ~ { network: Network _ NARROW[b.ovh.network]; IF b.hdr1.source.net = XNS.unknownNet THEN b.hdr1.source.net _ network.xns.net; IF b.hdr1.dest.net = XNS.unknownNet THEN b.hdr1.dest.net _ network.xns.net; IF b.hdr1.dest.host = XNS.broadcastHost THEN b.hdr1.dest.host _ thisHost; }; <<>> useOldReturn: BOOL _ TRUE; -- DEBUG ReturnToSender: PUBLIC PROC [handle: Handle, b: Buffer] ~ { <> <> bytes: CARDINAL ~ GetBytesRounded[b]; sendChecksum: BOOL ~ IF handle = NIL THEN TRUE ELSE handle.sendChecksum; network: Network ~ NARROW[b.ovh.network]; FixupSourceAndDest[b]; b.hdr1.transportCtl _ [trace~FALSE, filler~0, hopCount~0]; { temp: Address ~ b.hdr1.source; b.hdr1.source _ b.hdr1.dest; b.hdr1.dest _ temp }; InlineSetChecksum[b, bytes, sendChecksum]; <> IF useOldReturn THEN { network: Network; immediate: Host; [network, immediate] _ XNSRouterPrivate.Route[b.hdr1.dest]; IF network # NIL THEN { b.ovh.encap _ network.xns.getEncapsulation[network, immediate]; network.xns.send[network, TempDriverBuffer[b], bytes] }; IF handle # NIL THEN FreeBuffer[handle, b]; RETURN }; network.xns.return[network, TempDriverBuffer[b], bytes]; IF handle # NIL THEN FreeBuffer[handle, b]; }; <<>> ReturnError: PUBLIC PROC [handle: Handle, b: Buffer, type: XNSErrorTypes.ErrorType] ~ { bodyBytes: CARDINAL ~ 42; -- Should be XNSErrorBuf.minBytesToCopy ???? eb: XNSErrorBuf.Buffer; IF (b.hdr1.type = error) OR (b.hdr1.dest.host = XNS.broadcastHost) THEN { IF handle # NIL THEN FreeBuffer[handle, b]; -- Hack for internal use RETURN; }; b.hdr1.type _ error; TRUSTED { -- ???? WORD-SIZE DEPENDENT ???? eb _ LOOPHOLE[b]; PrincOpsUtils.LongMove[ from: @b.hdr1, nwords: bodyBytes*2, to: @eb.body]; }; eb.hdr2.type _ type; eb.hdr2.param _ XNSErrorTypes.nullParam; SetUserBytes[b, XNSErrorBuf.hdrBytes + bodyBytes]; ReturnToSender[handle, b]; }; <<>> <> SetDirectReceive: PUBLIC ENTRY PROC [handle: Handle, receiveProc: ReceiveProc, clientData: REF ANY] ~ { handle.receiveProc _ (IF receiveProc # NIL THEN receiveProc ELSE NormalReceive); handle.receiveClientData _ clientData; }; <> <> <> errorTooShort: INT _ 0; errorNoGateway: INT _ 0; errorNoSocket: INT _ 0; errorDeadSocket: INT _ 0; errorBadChecksum: INT _ 0; errorBuffersFull: INT _ 0; TakeThis: PUBLIC PROC [network: Network, buffer: CommDriver.Buffer, bytes: NAT] RETURNS [CommDriver.Buffer] ~ { b: Buffer _ RealXNSBuffer[buffer, recv]; bytesNeeded: CARDINAL ~ GetBytesRounded[b]; dest: Address _ b.hdr1.dest; localSocket: Socket ~ dest.socket; handle: Handle; receiveProc: ReceiveProc; receiveClientData: REF ANY; BEGIN IF (bytes < bytesNeeded) OR (Endian.CardFromH[b.hdr1.length] < XNSBuf.hdrBytes) THEN { errorTooShort _ errorTooShort.SUCC; GOTO Out; }; IF b.hdr1.dest.host # thisHost AND b.hdr1.dest.host # XNS.broadcastHost THEN { errorNoGateway _ errorNoGateway.SUCC; ReturnError[NIL, b, XNSErrorTypes.unspecifiedInRouteErr]; -- What's the RIGHT error to use here? GOTO Out; }; handle _ FindHandle[localSocket]; IF handle = NIL THEN { errorNoSocket _ errorNoSocket.SUCC; ReturnError[NIL, b, XNSErrorTypes.noSocketErr]; GOTO Out; }; IF handle.dead THEN { errorDeadSocket _ errorDeadSocket.SUCC; IF NOT handle.noErrors THEN ReturnError[NIL, b, XNSErrorTypes.noSocketErr]; GOTO Out; }; IF handle.recvChecksum AND NOT InlineTestChecksum[b, bytesNeeded] THEN { errorBadChecksum _ errorBadChecksum.SUCC; ReturnError[NIL, b, XNSErrorTypes.badChecksumErr]; GOTO Out; }; b.ovh.next _ NIL; [receiveProc, receiveClientData] _ GetReceiveProc[handle]; IF receiveProc # NIL THEN { b _ receiveProc[handle, b, receiveClientData]; IF b = NIL THEN GOTO OutNIL; DecrementRecvBuffersInUse[handle]; GOTO Out; }; errorBuffersFull _ errorBuffersFull.SUCC; IF NOT handle.noErrors THEN ReturnError[NIL, b, XNSErrorTypes.resourceLimitsErr]; GOTO Out; EXITS Out => RETURN[RealDriverBuffer[b]]; OutNIL => RETURN[NIL]; END; }; <<>> GetReceiveProc: ENTRY PROC [handle: Handle] RETURNS [ReceiveProc, REF ANY] ~ { IF handle.recvBuffersInUse >= handle.recvBuffersAllocated THEN RETURN [NIL, NIL]; handle.recvBuffersInUse _ handle.recvBuffersInUse.SUCC; RETURN [handle.receiveProc, handle.receiveClientData]; }; NormalReceive: PUBLIC ENTRY ReceiveProc ~ { IF handle.firstInput = NIL THEN handle.firstInput _ b ELSE handle.lastInput.ovh.next _ b; handle.lastInput _ b; NOTIFY handle.waitForInput; RETURN[NIL]; }; DecrementRecvBuffersInUse: ENTRY PROC [handle: Handle] ~ { handle.recvBuffersInUse _ handle.recvBuffersInUse.PRED; }; <> <> droppedSockets: INT _ 0; finishedSockets: INT _ 0; droppedBuffers: INT _ 0; ofq: SafeStorage.FinalizationQueue ~ SafeStorage.NewFQ[]; -- for Objects bfq: SafeStorage.FinalizationQueue ~ SafeStorage.NewFQ[]; -- for Buffers ObjectFinalizer: PROC = { Process.SetPriority[Process.priorityBackground]; DO handle: Handle _ NARROW[SafeStorage.FQNext[ofq]]; IF NOT handle.dead THEN { -- User forgot to call Destroy SafeStorage.EnableFinalization[handle]; Destroy[handle]; droppedSockets _ droppedSockets.SUCC; } ELSE { -- Normal end of life RemoveOldHandle[oldHandle~handle]; finishedSockets _ finishedSockets.SUCC; }; handle _ NIL; ENDLOOP; }; BufferFinalizer: PROC = { <> Process.SetPriority[Process.priorityBackground]; DO b: Buffer _ NARROW[SafeStorage.FQNext[bfq]]; handle: Handle _ NARROW[b.ovh.socket]; SafeStorage.EnableFinalization[b]; FreeBuffer[handle, b]; b _ NIL; droppedBuffers _ droppedBuffers.SUCC; ENDLOOP; }; SafeStorage.EstablishFinalization[type: CODE[Object], npr: 1, fq: ofq]; SafeStorage.EstablishFinalization[type: CODE[XNSBuf.BufferObject], npr: 1, fq: bfq]; TRUSTED { Process.Detach[FORK ObjectFinalizer[]] }; TRUSTED { Process.Detach[FORK BufferFinalizer[]] }; }.