* This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation. * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * If you do not have a copy of the GNU Library General Public * License, write to The Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. * * For more information on this program, contact Blair MacIntyre * (bm@cs.columbia.edu) or Steven Feiner (feiner@cs.columbia.edu) * at the Computer Science Dept., Columbia University, * 500 W 120th St, Room 450, New York, NY, 10027. * * Copyright (C) Blair MacIntyre 1995, Columbia University 1995 * * Author : Blair MacIntyre * Created On : Tue Aug 8 16:29:55 1995 * Last Modified By: Blair MacIntyre * Last Modified On: Sun Feb 18 15:02:20 1996 * Update Count : 24 * * SCCS Status : %W% %G% * * HISTORY
TODO: create picklers that will not duplicate the obliq object when passed to a host more than once. Simply send a receive the real object first. If it already exists, there will be a proxy, which can just be used.
MODULEWhen a new proxied object is created, we first want to check to see if there already is a proxied obj. If so, just use it. This can happen if the obliq value is pickled across the network. If the shared object exists, it will be returned from the pickle reader. Thus, we should use the existing proxy, too.; IMPORT ObCommand, ObLib, ObLoader, ObValue, Obliq, Env, ObEmbProxiedObj, SynLocation, SharedObj, SharedObjRT, Text, ObText, ObInt, Thread, IP, ObjectSpace, ObError; ObSharedObj
REVEAL T = ObEmbProxiedObj.T BRANDED "ObSharedObj.T" OBJECT END; PROCEDURE*************************************************************************** Setup procedures ***************************************************************************GetArg (args : ObValue.ArgArray; idx : INTEGER; package : ObLib.T; opCode : ObLib.OpCode; loc : SynLocation.T) : SharedObj.T RAISES {ObValue.Error, ObValue.Exception} = BEGIN WITH raw = Obliq.ObjectSelect (args[idx], "raw") DO TYPECASE raw OF | T (node) => RETURN node.po; ELSE ObValue.BadArgType (idx, pkgname, package.name, opCode.name, loc); RETURN NIL; (* ... only to suppress compiler warning *) END; END; END GetArg;
PROCEDURE*************************************************************************** Execution machinery ***************************************************************************SetupPackage () = PROCEDURE NewOpCode (name: TEXT; arity: INTEGER; code: Code) : OpCode = BEGIN RETURN NEW (OpCode, name := name, arity := arity, code := code); END NewOpCode; VAR opCodes: REF ObLib.OpCodes; BEGIN opCodes := NEW(REF ObLib.OpCodes, NUMBER(Code)); opCodes^ := ObLib.OpCodes{ NewOpCode ("Error", -1, Code.Error), NewOpCode ("Fatal", -1, Code.Fatal), NewOpCode ("AcquireGlobalLock", 1, Code.AcquireGlobalLock), NewOpCode ("ReleaseGlobalLock", 1, Code.ReleaseGlobalLock), NewOpCode ("Own", 2, Code.Own), NewOpCode ("Disown", 1, Code.Disown), NewOpCode ("SetTimeliness", 2, Code.SetTimeliness), NewOpCode ("SetNodeName", 1, Code.SetNodeName), NewOpCode ("SetDefaultSequencer", 2, Code.SetDefaultSequencer), NewOpCode ("DebugLevel", 1, Code.DebugLevel), NewOpCode ("PullObject", 1, Code.PullObject) }; errorException := Obliq.NewException("SharedObj_Error"); fatalException := Obliq.NewException("SharedObj_Fatal"); ObLib.Register(NEW(Package, name:=pkgname, opCodes:=opCodes)); ObLib.RegisterHelp (pkgname, Help); END SetupPackage; PROCEDURESetupModule (loader: ObLoader.T) = BEGIN pkgloader := loader; pkgloader.load ("SharedObj.obl"); END SetupModule;
TYPE Code = {Error, Fatal, AcquireGlobalLock, ReleaseGlobalLock, Own, Disown, SetTimeliness, SetNodeName, SetDefaultSequencer, DebugLevel, PullObject}; OpCode = ObLib.OpCode OBJECT code: Code; END; Package = ObLib.T OBJECT OVERRIDES Eval := Eval; END; CONST pkgname = "SharedObj"; VAR nodename: TEXT;PullObject uses a very cute trick. The theory is this. By obtaining the
raw
field, and
from it the proxy, if the object is remote we will now have
a locate copy, created when the modula-3 object is pickled
across, a new one is created and the appropriate mkproxy is
called. If the object is locate, we will return the same
obliq object as before.
Unlike the anim3D ObProxiedObj.Extend, we do not allow the object to be extended: the various copies would them potentially become different.
One of the two methods will end up being more useful. I'll kill one eventually.
PROCEDURE*************************************************************************** Help ***************************************************************************Eval (self: Package; opCode: ObLib.OpCode; <* UNUSED *> arity : ObLib.OpArity; READONLY args: ObValue.ArgArray; <* UNUSED *> temp: BOOLEAN; loc: SynLocation.T) : ObValue.Val RAISES {ObValue.Error, ObValue.Exception} = BEGIN TRY CASE NARROW(opCode, OpCode).code OF | Code.Error => RETURN errorException; | Code.Fatal => RETURN fatalException; | Code.AcquireGlobalLock => WITH obj = GetArg(args, 1, self, opCode, loc) DO SharedObj.AcquireGlobalLock(obj); END; RETURN ObValue.valOk; | Code.ReleaseGlobalLock => WITH obj = GetArg(args, 1, self, opCode, loc) DO SharedObj.ReleaseGlobalLock(obj); END; RETURN ObValue.valOk; | Code.Own => WITH obj = GetArg(args, 1, self, opCode, loc), arg1 = ObInt.GetArg(args, 2, self, opCode, loc) DO IF arg1 < FIRST(SharedObj.Timeliness) OR arg1 > LAST(SharedObj.Timeliness) THEN ObValue.BadArgVal(2, "invalid timeliness", self.name, opCode.name, loc); END; SharedObj.Own(obj, arg1); END; RETURN ObValue.valOk; | Code.Disown => WITH obj = GetArg(args, 1, self, opCode, loc) DO SharedObj.Disown(obj); END; RETURN ObValue.valOk; | Code.SetTimeliness => WITH obj = GetArg(args, 1, self, opCode, loc), arg1 = ObInt.GetArg(args, 2, self, opCode, loc) DO IF arg1 < FIRST(SharedObj.Timeliness) OR arg1 > LAST(SharedObj.Timeliness) THEN ObValue.BadArgVal(2, "invalid timeliness", self.name, opCode.name, loc); END; SharedObj.SetTimeliness(obj, arg1); END; RETURN ObValue.valOk; | Code.SetNodeName => nodename := ObText.GetArg(args, 1, self, opCode, loc); IF Text.Equal(nodename, "") THEN nodename := IP.GetCanonicalByAddr(IP.GetHostAddr()); END; SharedObjRT.ExportSpace(nodename); RETURN ObText.M3ToObliq(nodename); | Code.SetDefaultSequencer => VAR space: ObjectSpace.T; host := ObText.GetArg(args, 1, self, opCode, loc); name := ObText.GetArg(args, 2, self, opCode, loc); BEGIN IF Text.Equal("", host) THEN WITH defhost = Env.Get("SEQUENCERHOST") DO IF defhost # NIL THEN host := defhost; END; END; END; IF Text.Equal("", name) THEN WITH defname = Env.Get("SEQUENCERNAME") DO IF defname # NIL THEN name := defname; END; END; END; IF NOT Text.Equal("", host) OR NOT Text.Equal("", name) THEN space := SharedObjRT.ImportSpace(host, name); IF space = NIL THEN ObValue.RaiseException(errorException, self.name & "_" & opCode.name & ": node " & name & "@" & host & " is unavailable", loc); END; ELSE space := SharedObjRT.LocalSpace(); END; SharedObjRT.SetDfltSequencer(space); END; RETURN ObValue.valOk; | Code.DebugLevel => WITH arg1 = ObInt.GetArg(args, 1, self, opCode, loc) DO SharedObjRT.DebugLevel(arg1); END; RETURN ObValue.valOk; | Code.PullObject => WITH po = GetArg (args, 1, self, opCode, loc) DO RETURN po.proxy.obj; END; ELSE ObValue.BadOp(self.name, opCode.name, loc); RETURN NIL; (* to shut up warning in compiler about no return value *) END; EXCEPT | IP.Error(ec) => ObValue.RaiseException(ObValue.netException, self.name & "_" & opCode.name & ": " & ObError.AtomListToText(ec), loc); RETURN NIL; (* to shut up warning in compiler about no return value *) | Thread.Alerted => ObValue.RaiseException(ObValue.threadAlerted, self.name & "_" & opCode.name & ": ", loc); RETURN NIL; (* to shut up warning in compiler about no return value *) | SharedObj.Error(ec) => ObValue.RaiseException(errorException, self.name & "_" & opCode.name & ": " & ObError.AtomListToText(ec), loc); RETURN NIL; (* to shut up warning in compiler about no return value *) END; END Eval;
PROCEDUREHelp (self : ObCommand.T; arg : TEXT; <* UNUSED *> data : REFANY) = BEGIN IF pkgloader # NIL THEN pkgloader.help (self, arg, pkgname); END; END Help; VAR pkgloader: ObLoader.T := NIL; BEGIN END ObSharedObj.