Copyright (C) 1994, Digital Equipment Corp.
StubProt.m3
UNSAFE MODULESince clients ofStubProt EXPORTSStubLib ,StubLibPrivate ; IMPORT NetObj, NetObjRep, NetObjRT, Protocol, Transport, TransportUtils, WireRep; IMPORT AtomList, Thread, Rd, Wr, RTType; IMPORT RdClass, WrClass; (* UnsafeWr *) FROM Protocol IMPORT Header, CallHeader, Op;
Conn
must avoid accessing them concurrently,
we operate on the embedded streams without locking them.
EXCEPTION FatalError; <* FATAL FatalError *>
REVEAL RdClass.Private <: MUTEX; REVEAL WrClass.Private <: MUTEX;
TYPE ObjectStack = RECORD pos: CARDINAL := 0; objs: REF ARRAY OF NetObj.T := NIL; END; CONST DefaultObjStackSize = 8; REVEAL Conn = Transport.Conn BRANDED OBJECT objStack: ObjectStack := ObjectStack {}; inObj: BOOLEAN := FALSE; END;The field
t.objStack
is used to record the set of network objects
marshalled during any single method invocation (at either client or
server). This record is required for cleanup at the termination of
the call. The t.objStack
field is managed by the network object
runtime and should not be modified by any transport implementation.
REVEAL Transport.T = TransportUtils.Public BRANDED OBJECT OVERRIDES serviceCall := ServiceCall; END; PROCEDUREexports to StubLibServiceCall (<*UNUSED*> tt: Transport.T; c: Conn) : BOOLEAN RAISES {Thread.Alerted} = BEGIN TRY VAR dispatcher: Dispatcher; obj: NetObj.T; prot: StubProtocol; rd := c.rd; h := LOOPHOLE(ADR(rd.buff[rd.st+rd.cur-rd.lo]), UNTRACED REF CallHeader); BEGIN IF rd.hi - rd.cur < BYTESIZE(CallHeader) OR h.hdr.private # ORD(Op.MethodCall) THEN RaiseUnmarshalFailure(); END; INC(rd.cur, BYTESIZE(CallHeader)); IF h.hdr.intFmt # NativeRep.intFmt THEN IF NOT NativeEndian(h.hdr) THEN prot := Swap32(h.prot); END; END; obj := NetObjRT.FindTarget(h.obj, prot, dispatcher); TRY c.objStack.pos := 0; dispatcher(c, obj, h.hdr, prot); IF (c.objStack.pos # 0) THEN (* take this out, later *) (* UnsafeWr.FastPutChar(c.wr, '\000'); *) c.wr.nextMsg(); IF NOT rd.nextMsg() OR rd.hi - rd.cur < BYTESIZE(Header) THEN RETURN FALSE; END; VAR hh := LOOPHOLE(ADR(rd.buff[rd.st+rd.cur-rd.lo]), UNTRACED REF Header)^; BEGIN INC(rd.cur, BYTESIZE(Header)); IF hh.private # ORD(Op.ResultAck) THEN RETURN FALSE; END; END; ELSE c.wr.nextMsg(); END; FINALLY IF (c.objStack.pos # 0) THEN NetObjRT.Unpin(SUBARRAY(c.objStack.objs^, 0, c.objStack.pos)); FOR i := 0 TO c.objStack.pos-1 DO c.objStack.objs[i] := NIL; END; END; END; END; EXCEPT | Rd.Failure, Wr.Failure => RETURN FALSE; | NetObj.Error(ec) => TRY (* this test checks whether we have started marshalling results *) IF c.wr.cur = 0 THEN VAR wr := c.wr; h := LOOPHOLE(ADR(wr.buff[wr.st+wr.cur-wr.lo]), UNTRACED REF Header); BEGIN h^ := NativeRep; h.private := ORD(Op.CallFailed); INC(wr.cur, BYTESIZE(Header)); END; OutRef(c, ec); END; c.wr.nextMsg(); EXCEPT | Wr.Failure => RETURN FALSE; END; END; RETURN TRUE; END ServiceCall;
PROCEDUREStartCall (obj: NetObj.T; stubProt: StubProtocol) : Conn RAISES {NetObj.Error, Wr.Failure, Thread.Alerted} = VAR c := NARROW(obj.r, Transport.Location).new(); BEGIN c.objStack.pos := 0; c.inObj := FALSE; VAR wr := c.wr; h := LOOPHOLE(ADR(wr.buff[wr.st+wr.cur-wr.lo]), UNTRACED REF CallHeader); BEGIN <* ASSERT (wr.hi - wr.cur >= BYTESIZE(CallHeader)) *> INC(wr.cur, BYTESIZE(CallHeader)); h.hdr := NativeRep; h.hdr.private := ORD(Op.MethodCall); h.prot := stubProt; h.obj := obj.w; END; RETURN c; END StartCall; PROCEDUREAwaitResult (c: Conn) : DataRep RAISES {NetObj.Error, Rd.Failure, Wr.Failure, Thread.Alerted} = VAR hdr: Header; rd := c.rd; BEGIN c.wr.nextMsg(); TRY IF NOT rd.nextMsg() OR rd.hi - rd.cur < BYTESIZE(Header) THEN RaiseUnmarshalFailure(); END; hdr := LOOPHOLE(ADR(rd.buff[rd.st+rd.cur-rd.lo]), UNTRACED REF Header)^; INC(rd.cur, BYTESIZE(Header)); EXCEPT | Thread.Alerted => RAISE NetObj.Error(AtomList.List1(NetObj.Alerted)); END; CASE hdr.private OF | ORD(Op.Return) => | ORD(Op.CallFailed) => RAISE NetObj.Error(InRef(c, hdr, TYPECODE(AtomList.T))); ELSE RaiseUnmarshalFailure(); END; RETURN hdr; END AwaitResult; PROCEDUREEndCall (c: Conn; reUse: BOOLEAN) RAISES {NetObj.Error, Rd.Failure, Wr.Failure, Thread.Alerted} = BEGIN TRY IF c.objStack.pos # 0 THEN NetObjRT.Unpin(SUBARRAY(c.objStack.objs^, 0, c.objStack.pos)); FOR i := 0 TO c.objStack.pos-1 DO c.objStack.objs[i] := NIL; END; END; IF reUse AND c.inObj (* OR NOT UnsafeRd.FastEOF(c.rd) *) THEN VAR wr := c.wr; h := LOOPHOLE(ADR(wr.buff[wr.st+wr.cur-wr.lo]), UNTRACED REF Header); BEGIN h^ := NativeRep; h.private := ORD(Op.ResultAck); INC(wr.cur, BYTESIZE(Header)); wr.nextMsg(); END; END; FINALLY c.loc.free(c, reUse); END; END EndCall; PROCEDUREStartResult (c: Conn) RAISES {Wr.Failure, Thread.Alerted} = VAR wr := c.wr; h := LOOPHOLE(ADR(wr.buff[wr.st+wr.cur-wr.lo]), UNTRACED REF Header); BEGIN h^ := NativeRep; h.private := ORD(Op.Return); INC(wr.cur, BYTESIZE(Header)); END StartResult; PROCEDUREOutObject (c: Conn; o: NetObj.T) RAISES {Wr.Failure, Thread.Alerted} = VAR s: REF ARRAY OF NetObj.T; BEGIN IF o = NIL THEN OutBytes(c, WireRep.NullT.byte); ELSE OutBytes(c, NetObjRT.InsertAndPin(o).byte); s := c.objStack.objs; IF s = NIL THEN s := NEW(REF ARRAY OF NetObj.T, DefaultObjStackSize); c.objStack.objs := s; ELSIF c.objStack.pos = NUMBER(s^) THEN s := NEW(REF ARRAY OF NetObj.T, 2 * c.objStack.pos); SUBARRAY(s^, 0, c.objStack.pos) := c.objStack.objs^; c.objStack.objs := s; END; s[c.objStack.pos] := o; INC(c.objStack.pos); END; END OutObject; PROCEDUREInObject (c: Conn; tc: INTEGER := -1): NetObj.T RAISES {NetObj.Error, Rd.Failure, Thread.Alerted} = VAR w: WireRep.T; o: NetObj.T; BEGIN InBytes(c, w.byte); IF w = WireRep.NullT THEN RETURN NIL END; o := NetObjRT.Find(w, c.loc); IF tc # -1 AND NOT RTType.IsSubtype(TYPECODE(o), tc) THEN RaiseUnmarshalFailure(); END; c.inObj := TRUE; RETURN o; END InObject; BEGIN END StubProt.