[e-cvs] cvs commit: e/src/jsrc/org/erights/e/elib/tests TestMultiQ.java TestMultiQMain.java

markm@eros.cs.jhu.edu markm@eros.cs.jhu.edu
Wed, 3 Oct 2001 11:18:30 -0400


markm       01/10/03 11:18:30

  Modified:    src/esrc/scripts elmer.e
               src/jsrc/org/erights/e/elib/tests TestMultiQ.java
                        TestMultiQMain.java
  Added:       src/jsrc/org/erights/e/elib/ref ExternalRef.java
  Removed:     src/jsrc/org/erights/e/elib/ref DeviceRef.java
  Log:
  DeviceRef renamed back to ExternalRef
  Pseudo-synchronous ops should replace
  Runner.now() and Runner.callNow()

Revision  Changes    Path
1.11      +8 -6      e/src/esrc/scripts/elmer.e

Index: elmer.e
===================================================================
RCS file: /cvs/e/src/esrc/scripts/elmer.e,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -r1.10 -r1.11
--- elmer.e	2001/10/03 04:41:02	1.10
+++ elmer.e	2001/10/03 15:18:29	1.11
@@ -7,16 +7,18 @@
 
 def group := EditGroupMaker new(true)
 def first := ElmerMainMaker new(group, EInterpAdapterMaker)
-for arg in interp getArgs() {
-    first menuOpen(<file: arg>)
-}
-first textArea() setText(
-"\
+def args := interp getArgs()
+if (args == []) {
+    first textArea() setText("\
 Elmer is a simple text editor that also executes embedded
 command line examples.  Try hitting enter below
 
     ? 2 + 3")
-    
+} else {
+    for arg in args {
+        first menuOpen(<file: arg>)
+    }
+}
 
 first setVisible(true)
 



1.1                  e/src/jsrc/org/erights/e/elib/ref/ExternalRef.java

Index: ExternalRef.java
===================================================================
package org.erights.e.elib.ref;

/*
The contents of this file are subject to the Electric Communities E Open
Source Code License Version 1.0 (the "License"); you may not use this file
except in compliance with the License. You may obtain a copy of the License
at http://www.communities.com/EL/.

Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
the specific language governing rights and limitations under the License.

The Original Code is the Distributed E Language Implementation, released
July 20, 1998.

The Initial Developer of the Original Code is Electric Communities.
Copyright (C) 1998 Electric Communities. All Rights Reserved.

Contributor(s): ______________________________________.
*/

import org.erights.e.elib.prim.E;
import org.erights.e.elib.prim.Runner;
import org.erights.e.elib.prim.StaticMaker;
import org.erights.e.elib.util.OneArgFunc;

/**
 * A TCB-internal, thread-safe, vat-crossing EVENTUAL reference to a target
 * object in some vat within this JVM.
 * <p>
 * A ExternalRef may be invoked from any vat, so it may not grab the vatLock of
 * its target's vat.  (This is possible now that a vat's queue has a separate
 * lock -- thanks Bill.)  (More recently, the queue's lock is the only lock.
 * The vatLock has disapeared -- thanks Dean.)
 * <p>
 * The arguments passed in must be objects that may validly be used from
 * multiple vats at once, such as transitively pass-by-copy objects, or
 * further DeviceRefs.  This constraint is not enforced, so only trusted code
 * may hold DeviceRefs.  Messages sent over DeviceRefs return a ExternalRef for
 * designating a return result in the target's vat.
 * <p>
 * Even if the target is or becomes BROKEN or PassByConstruction, ExternalRef
 * will not shorten.  It will continue delivering messages to the target in
 * its vat.  For more complex behavior (such as shortening), build other Refs
 * using ExternalRef as a component.
 * <p>
 * XXX Should the target vat be forcibly shut down, the DeviceRefs into it
 * should become BROKEN.  This behavior is not yet supported.
 *
 * @author <a href="mailto:markm@erights.org">Mark S. Miller</a>
 */
public class ExternalRef extends Ref {

    /**
     *
     */
    static private class Waiter implements OneArgFunc {

        /**
         *
         */
        private Object myLock;

        /**
         *
         */
        private boolean myIsDone;

        /**
         *
         */
        private Waiter() {
            myLock = new Object();
            myIsDone = false;
        }

        /**
         * Must only be called in the target's vat thread.
         */
        public Object run(Object ignored) {
            synchronized (myLock) {
                myIsDone = true;
                myLock.notifyAll();
            }
            return null; //keep compiler happy
        }

        /**
         * Must not be called in the target's vat thread
         */
        private void waitFor() {
            synchronized (myLock) {
                while (! myIsDone) {
                    try {
                        myLock.wait();
                    } catch (InterruptedException ie) {
                        //ignored, keep looping
                    }
                }
            }
        }
    }


    private final Runner myTargetsRunner;
    private final Object myTarget;

    /**
     * Make an EVENTUAL reference to target which will queue messages with
     * targetsRunner for delivery to target.  targetsRunner must be the vat
     * of target.
     */
    public ExternalRef(Runner targetsRunner, Object target) {
        myTargetsRunner = targetsRunner;
        myTarget = target;
    }

    /**
     * Blocks (if possible) until target is resolved, and the returns the
     * (hopefully) resolved target.
     * <p>
     * If called from inside the target's vat, it can't block, so it just
     * returns the current target, which might not be resolved.
     * <p>
     * If called from any other thread, it blocks that thread until target
     * resolves, and then returns target.  Note: It returns the target
     * itself, not a ExternalRef on target.  Unless you have special
     * knowledge, target should not be assumed to be thread safe for use
     * outside its vat.
     * <p>
     * Since this is a blocking operation, deadlock can easily result.  In
     * particular, two vats can block on each other.  Use with care.
     */
    public Object waitFor() {
        if (myTargetsRunner.isCurrentThreadInVat()) {
            //Can't wait.  Returns the current value.
            return myTarget;
        } else {
            //called from outside my target's vat's thread
            Waiter waiter = new Waiter();
            Object[] args = { waiter };
            myTargetsRunner.sendAllOnly(Ref.RefMaker,
                                        "whenResolvedOnly",
                                        args);
            waiter.waitFor();
            return myTarget;
        }
    }

    /**
     * @return null
     */
    public Throwable optProblem() {
        return null;
    }

    /**
     * @return the target
     */
    /*package*/ Ref resolutionRef() {
        return this;
    }

    /**
     * @return EVENTUAL
     */
    public String state() {
        return EVENTUAL;
    }

    /**
     * Invoke the target with verb and args as synchronously as we can.
     * <p>
     * If called in the target's vat's thread, this in just a normal
     * synchronous intra-vat 'target verb(args...)'.
     * <p>
     * If called from another thread, this does a
     * {@link #sendAll(String, Object[])} and a {@link #waitFor()} on the
     * result.
     */
    public Object callAll(String verb, Object[] args) {
        if (myTargetsRunner.isCurrentThreadInVat()) {
            return E.callAll(myTarget, verb, args);
        } else {
            ExternalRef outcome = (ExternalRef)sendAll(verb, args);
            return outcome.waitFor();
        }
    }

    /**
     * Causes the described message to be E.sent to the target in the
     * target's vat. <p>
     *
     * The returned result is a ExternalRef designating a promise for a result
     * in the same vat as the target, since that is where the message will be
     * delivered.
     */
    public final Ref sendAll(String verb, Object[] args) {
        Ref outcome = myTargetsRunner.sendAll(myTarget, verb, args);
        return new ExternalRef(myTargetsRunner, outcome);
    }

    /**
     * Causes the described message to be E.sent to the target in the
     * target's vat, ignoring the outcome.
     */
    public final void sendAllOnly(String verb, Object[] args) {
        myTargetsRunner.sendAllOnly(myTarget, verb, args);
    }

    /**
     *
     */
    public boolean isResolved() {
        //XXX it actually might be resolved, but it doesn't have enough local
        //identity to act resolved
        return false;
    }

    /**
     *
     */
    /*package*/ void setTarget(Ref newTarget) {
        throw new RuntimeException("Not switchable");
    }

    /**
     *
     */
    /*package*/ void commit() {
        //already committed, do nothing.
    }
}



1.11      +4 -4      e/src/jsrc/org/erights/e/elib/tests/TestMultiQ.java

Index: TestMultiQ.java
===================================================================
RCS file: /cvs/e/src/jsrc/org/erights/e/elib/tests/TestMultiQ.java,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -r1.10 -r1.11
--- TestMultiQ.java	2001/09/06 09:55:53	1.10
+++ TestMultiQ.java	2001/10/03 15:18:30	1.11
@@ -21,7 +21,7 @@
 
 import org.erights.e.develop.exception.PrintStreamWriter;
 import org.erights.e.elib.prim.E;
-import org.erights.e.elib.ref.DeviceRef;
+import org.erights.e.elib.ref.ExternalRef;
 
 /**
  * Worker classes for the mult-queue tester.  This class is instantiated
@@ -33,7 +33,7 @@
  * See TestMultiQMain for the top level story.
  */
 public class TestMultiQ {
-    private DeviceRef otherRef = null;   // our ref to the "other" TestMultiQ.
+    private ExternalRef otherRef = null;   // our ref to the "other" TestMultiQ.
     private String    myName = null;     // the name of this instance.
     private int       myIntVal = 0;      // the counter.
 
@@ -65,9 +65,9 @@
     }
 
     /**
-     * setTarget -- Used to set the DeviceRef of the "other" TestMultiQ.
+     * setTarget -- Used to set the ExternalRef of the "other" TestMultiQ.
      */
-    public void setTarget(DeviceRef ref) {
+    public void setTarget(ExternalRef ref) {
         PrintStreamWriter.out().println(myName + " : setTarget(" + ref + ")");
         otherRef = ref;
         // Set the thread name so our name will show up in thread dumps.



1.12      +5 -5      e/src/jsrc/org/erights/e/elib/tests/TestMultiQMain.java

Index: TestMultiQMain.java
===================================================================
RCS file: /cvs/e/src/jsrc/org/erights/e/elib/tests/TestMultiQMain.java,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -r1.11 -r1.12
--- TestMultiQMain.java	2001/09/14 01:35:22	1.11
+++ TestMultiQMain.java	2001/10/03 15:18:30	1.12
@@ -23,7 +23,7 @@
 import org.erights.e.elib.prim.E;
 import org.erights.e.elib.prim.Runner;
 import org.erights.e.elib.prim.BERunner;
-import org.erights.e.elib.ref.DeviceRef;
+import org.erights.e.elib.ref.ExternalRef;
 
 /**
  * TestMultiQMain -- test elib message sending using two run queues.
@@ -55,18 +55,18 @@
         // Also, we'll specify the target object for each ref.
         // Creating the new Runner instances also has the effect of creating
         // and starting a thread for each Runner instance.
-        DeviceRef ref1 = new DeviceRef(new BERunner("t1"),
+        ExternalRef ref1 = new ExternalRef(new BERunner("t1"),
                                        target1);
-        DeviceRef ref2 = new DeviceRef(new BERunner("t2"),
+        ExternalRef ref2 = new ExternalRef(new BERunner("t2"),
                                        target2);
 
-        // Give the target2 DeviceRef to target1.
+        // Give the target2 ExternalRef to target1.
         PrintStreamWriter.out().println("Sending ref2 to target1...");
         E.sendOnly(ref1,            // where to send this -- ref1 ==> target1
                    "setTarget",     // target1's message (method)
                    ref2);           // the arg -- the ref to target2
 
-        // Give the target1 DeviceRef to target2.
+        // Give the target1 ExternalRef to target2.
         PrintStreamWriter.out().println("Sending ref1 to target2...");
         E.sendOnly(ref2,            // where to send this -- ref2 ==> target2
                    "setTarget",     // target2's message (method)