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;
PROCEDURE ServiceCall (<*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;
exports to StubLib
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.