org.erights.e.elib.vat
Class Vat

java.lang.Object
  |
  +--org.erights.e.elib.vat.Vat

public class Vat
extends Object

Untamed: A Vat is a disjoint partitioning of objects.

Each object should ideally be associated with exactly one Vat, and should only be invoked inside that Vat. However, since it would be too costly to add a Vat field to all objects, rather, the object's Vat context is restored prior to invoking the object. This context is captured on enqueueing a message for the object (or enqueueing any other PendingEvent). These events are enqueued onto the event loop of a Runner, which manages the dequeueing. There can be multiple Vats per Runner.

When Vat x is merged into Vat y, this means that both x and y will then be served by the Runner that was serving y.

Author:
Mark S. Miller, Many improvements due to suggestions by E-Dean Tribble

Field Summary
private  boolean myIsMergeable
          Can I still merge?
private  long myNextTicket
          The ticket number to be "dispensed" to the next enqueued Runnable.
private  String myOptName
          For debugging.
private  Runner myRunner
          Should only be used by getRunner(), so that everyone will get the current Runner.
 
Constructor Summary
private Vat(Runner runner, boolean mergeable, String optName)
           
 
Method Summary
 Object callAll(Object rec, String verb, Object[] args)
          Enabled: Wraps E.callAll(rec, verb, args) to ensure we're executing using this Vat.
 Throwable enqueue(Runnable todo)
          Enabled: Enqueue's something for this Runnable's thread to do.
static Vat getCurrentVat()
          Enabled: If called from within a thread servicing a Vat, returns that Vat; otherwise, throws an exception.
static Vat getOptCurrentVat()
          Enabled: If called from within a thread servicing a Vat, returns that Vat; otherwise null.
(package private)  Runner getRunner()
          This returns the current Runner for this Vat, but beware that this may change over time as a result of merging.
 String getRunnerKind()
          Enabled: May be called from any thead.
 Object invoke(Object obj, java.lang.reflect.Method method, Object[] args)
          Enabled: Wraps method.invoke(obj, args) to ensure we're executing using this Vat.
 boolean isCurrent()
          Enabled: Is the current event within this Vat?
 boolean isCurrentRunner()
          Enabled: May be called from any thead.
static Vat make(String runnerKind)
          Enabled: optName defaults to null
static Vat make(String runnerKind, String optName)
          Enabled: Makes a Vat onto an obtained Runner of the specified kind.
 Ref mergeInto(Vat other)
          Enabled: If this Vat can still merge, it should eventually merge itself into other's Runner.
 Ref morphInto(String runnerKind)
          Enabled: optName defaults to null
 Ref morphInto(String runnerKind, String optName)
          Enabled: Like mergeInto(org.erights.e.elib.vat.Vat), but merges into a kind of Runner rather than the Runner of a pre-existing Vat.
 void now(Runnable todo)
          Enabled: Schedules a Runnable to execute in a Runner (in the Runner's thread as a separate turn), while also effectively executing as a synchronous call within the requestors's external thread.
 Ref orderlyShutdown(Throwable problem)
          Enabled: Requests this vat to eventually shut down once all already queued events have been processed.
 Ref qSendAll(Object rec, boolean nowFlag, String verb, Object[] args)
          Enabled: Enqueues a 'rec <- verb(args...)' and returns a promise for the result.
 Throwable qSendAllOnly(Object rec, boolean nowFlag, String verb, Object[] args)
          Enabled: Enqueues a 'rec <- verb(args...)' when no conventional result is needed.
 Throwable qSendMsg(Object rec, Message msg)
          Enabled: Enqueues the delivery of msg to rec.
 void requireCurrent()
          Enabled: If not isCurrent(), throw an exception.
static void requireExternal()
          Enabled: If the current thread isn't an external thread, throws an exception.
 void requireKind(String runnerKind)
          Enabled: Requires getRunnerKind() to be runnerKind
 Ref seed(Object rec)
          Enabled: The message defaults to ' <- run()'.
 Ref seed(Object rec, String verb, Object[] args)
          Enabled: Seeds initial computation in a vat and communications between vats.
static Ref sendAll(Object rec, String verb, Object[] args)
          Enabled: Queue the sendAll in the current vat.
static Throwable sendAllOnly(Object rec, String verb, Object[] args)
          Enabled: Queue the sendAllOnly in the current vat.
 void setPriority(int newPriority)
          Enabled: May be called from any thead.
 Vat sprout(String optName)
          Enabled: Returns new Vat sharing my Runner.
(package private)  long takeTicket()
          Dispenses a ticket number for the next enqueued Runnable.
 String toString()
          Suppressed: May be called from any thead.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
 

Field Detail

myRunner

private Runner myRunner
Should only be used by getRunner(), so that everyone will get the current Runner.


myIsMergeable

private boolean myIsMergeable
Can I still merge?


myNextTicket

private long myNextTicket
The ticket number to be "dispensed" to the next enqueued Runnable.

Ie, the ticket number that will be being served when this next Runnable will be run(). May be used for causality tracing.


myOptName

private final String myOptName
For debugging.

Constructor Detail

Vat

private Vat(Runner runner,
            boolean mergeable,
            String optName)
Method Detail

make

public static Vat make(String runnerKind)
Enabled: optName defaults to null

May be called from any thead.

See Also:
make(String, String)

make

public static Vat make(String runnerKind,
                       String optName)
Enabled: Makes a Vat onto an obtained Runner of the specified kind.

May be called from any thead.

Parameters:
runnerKind - says which kind of Runner to make.
optName - If we are making a new Runner, the name is also used to tag it and its thread for debugging purposes.

getOptCurrentVat

public static Vat getOptCurrentVat()
Enabled: If called from within a thread servicing a Vat, returns that Vat; otherwise null.

May be called from any thead.


getCurrentVat

public static Vat getCurrentVat()
Enabled: If called from within a thread servicing a Vat, returns that Vat; otherwise, throws an exception.

May be called from any thead.


requireExternal

public static void requireExternal()
Enabled: If the current thread isn't an external thread, throws an exception.


sendAllOnly

public static Throwable sendAllOnly(Object rec,
                                    String verb,
                                    Object[] args)
Enabled: Queue the sendAllOnly in the current vat.


sendAll

public static Ref sendAll(Object rec,
                          String verb,
                          Object[] args)
Enabled: Queue the sendAll in the current vat.


toString

public String toString()
Suppressed: May be called from any thead.

Overrides:
toString in class Object
Returns:
a string representation of the object.

getRunner

Runner getRunner()
This returns the current Runner for this Vat, but beware that this may change over time as a result of merging.


isCurrent

public boolean isCurrent()
Enabled: Is the current event within this Vat?

If it is, we say we are executing inside this Vat.

v.isCurrent() implies getCurrentVat() == v.

May be called from any thead.


requireCurrent

public void requireCurrent()
Enabled: If not isCurrent(), throw an exception.

May be called from any thead.


getRunnerKind

public String getRunnerKind()
Enabled: May be called from any thead.

See Also:
Runner.getRunnerKind()

requireKind

public void requireKind(String runnerKind)
Enabled: Requires getRunnerKind() to be runnerKind


isCurrentRunner

public boolean isCurrentRunner()
Enabled: May be called from any thead.

See Also:
Runner.isCurrent()

setPriority

public void setPriority(int newPriority)
Enabled: May be called from any thead.

See Also:
Runner.setPriority(int)

takeTicket

long takeTicket()
Dispenses a ticket number for the next enqueued Runnable.

Ie, the ticket number that will be being served when this next Runnable will be run(). May be used for causality tracing.

Ticket counts are incremented separately per Vat rather than per Runner, and so must be understood relative to the enqueueing Vat.


seed

public Ref seed(Object rec,
                String verb,
                Object[] args)
Enabled: Seeds initial computation in a vat and communications between vats.

Use for bootstrapping to boot-comm-system. This is an inherently dangerous operation -- use only if you know what you're doing; do not provide this ability directly to untrusted code. Most code should instead the emaker org.erights.e.elang.interp.seedVatAuthor.

While treating rec as if it were a member of this vat, seed will enqueue a

    rec <- verb(args...)
to occur in this vat and return a promise for the result, just as if rec were a proper boot-ref to an object already in this vat, and the above message had simply been sent from the current vat on this boot-ref. In particular, the treatment of the arguments and return result is exactly according to this story. The only cheating is in regards to rec itself. As with BootShuttle, this is safe only when all the mutable state transitively reachable from rec is no longer reachable from any other vat (typically, not from the current vat -- the vat of origin), or that any possibly shared mutable state is managed in a conventionally thread-safe manner.

This is typically used by having computation in the current vat create a thunk (a non-argument function) that, when invoked, creates the mutable state for a new service, and creates and returns the new service in the scope of that mutable state. The caller of seed in the current vat then has a boot-ref to the new service, which is executing in this vat. For this specific pattern, the seed/1 function is provided as a convenience.

Once we have auditors working, then we may provide a safe form of these operations that only accept DeepFrozen objects as rec.


seed

public Ref seed(Object rec)
Enabled: The message defaults to ' <- run()'.

See Also:
seed(Object, String, Object[])

enqueue

public Throwable enqueue(Runnable todo)
Enabled: Enqueue's something for this Runnable's thread to do.

May be called from any thead.

Returns:
Why wasn't 'todo' queued? It isn't queued if this vat or comm connection is shut down, in which case the returned problem explains why. If null is returned, then the event was queued, though it may still not arrive.

qSendMsg

public Throwable qSendMsg(Object rec,
                          Message msg)
Enabled: Enqueues the delivery of msg to rec.

The sending context is the sending context captured in msg.

May be called from any thead.

XXX to be made non-public. Uses outside this package should use boot-refs instead.

Returns:
Why wasn't 'todo' queued? It isn't queued if this vat or comm connection is shut down, in which case the returned problem explains why. If null is returned, then the event was queued, though it may still not arrive.

qSendAllOnly

public Throwable qSendAllOnly(Object rec,
                              boolean nowFlag,
                              String verb,
                              Object[] args)
Enabled: Enqueues a 'rec <- verb(args...)' when no conventional result is needed.

May be called from any thead.

XXX to be made non-public. Uses outside this package should use boot-refs instead.

Returns:
Why wasn't this event queued? It isn't queued if this vat or comm connection is shut down, in which case the returned problem explains why. If null is returned, then the event was queued, though it may still not arrive.

qSendAll

public Ref qSendAll(Object rec,
                    boolean nowFlag,
                    String verb,
                    Object[] args)
Enabled: Enqueues a 'rec <- verb(args...)' and returns a promise for the result.

If this vat is shut down, the returned reference is immediately broken (by a complaint explaining why). Otherwise, if it becomes known that this event might never be delivered, then the reference eventually becomes broken with a complaint explaining why.

May be called from any thead.

XXX to be made non-public. Uses outside this package should use boot-refs instead.


now

public void now(Runnable todo)
Enabled: Schedules a Runnable to execute in a Runner (in the Runner's thread as a separate turn), while also effectively executing as a synchronous call within the requestors's external thread.

Note: As of 0.8.20, we require that the caller's thread be external, in order to avoid a deadlock danger created by mergeInto(org.erights.e.elib.vat.Vat). The danger is that if we allow Runner x to block waiting on Runner y, then if y is redirected to x (if y's Vat is mergedInto one of x's Vats), then x would then be waiting on x. The old guard test to check if the caller is in the same Runner as the callee doesn't help, since that test says they are different prior to x blocking.

In most ways this can be thought of as a symmetric rendezvous between the calling external thread and the callee Runner thread. The reason we specify that the Runnable is executed specifically in the callee's Vat (and its associated Runner and thread) is so that thread-scoped state (such as getCurrentVat() will be according to the callee's Vat.

If todo throws a problem rather than successfully returning, then now() rethrows that problem as well.

If this vat is shut down, or shuts down before todo is executed, then a complaint about that is thrown and 'todo' is never executed.

May be called from any external thread.


invoke

public Object invoke(Object obj,
                     java.lang.reflect.Method method,
                     Object[] args)
              throws IllegalAccessException,
                     java.lang.reflect.InvocationTargetException
Enabled: Wraps method.invoke(obj, args) to ensure we're executing using this Vat.

Must be called from within this Runner, and either within this Vat, or between PendingEvents of this Runner. In the latter case, this invocation becomes like a PendingEvent, but with a ticket count of -1.

IllegalAccessException
java.lang.reflect.InvocationTargetException
See Also:
callAll/3

callAll

public Object callAll(Object rec,
                      String verb,
                      Object[] args)
Enabled: Wraps E.callAll(rec, verb, args) to ensure we're executing using this Vat.

Must be called from within this Runner, and either within this Vat, or between PendingEvents of this Runner. In the latter case, this invocation becomes like a PendingEvent, but with a ticket count of -1.

See Also:
invoke/3

sprout

public Vat sprout(String optName)
Enabled: Returns new Vat sharing my Runner.

The new Vat isn't mergeable whether or not I am. This makes

     def v2 := v1.sprout("foo")
like
     def v2 := vatMaker.make("headless", "foo")
     v2.mergeInto(v1)
except that it's as if the merge happens immediately.

May be called from any thead.


mergeInto

public Ref mergeInto(Vat other)
Enabled: If this Vat can still merge, it should eventually merge itself into other's Runner.

If the redirect attempt succeeds, it transfers the ability to redirect this Vat further to the other Vat. Likewise, when this Vat is redirected, all events queued by this Vat and any Vat that has merged into this Vat are merged into the other Vat, since these earlier Vats have transfered their merging power to this Vat.

XXX It is unclear whether this is the right abstraction, or whether we should instead provide a migrate operation that requeues just the events queued by a given Vat. Currently, we choose mergeInto, since it has a simpler implementation -- just migrate an entire HeadlessRunner's queue and shut down its thread.

May be called from any thead.

Returns:
When the redirect operation actually happens (in its own turn to avoid atomicity problems), the returned Ref resolves to 'null' if the redirect attempt succeeds, or a broken reference if it fails.

orderlyShutdown

public Ref orderlyShutdown(Throwable problem)
Enabled: Requests this vat to eventually shut down once all already queued events have been processed.

A shutdown does a merge into a DeadRunner.

May be called from any thead.

Returns:
As with mergeInto(org.erights.e.elib.vat.Vat)

morphInto

public Ref morphInto(String runnerKind)
Enabled: optName defaults to null

May be called from any thead.

See Also:
morphInto(String, String)

morphInto

public Ref morphInto(String runnerKind,
                     String optName)
Enabled: Like mergeInto(org.erights.e.elib.vat.Vat), but merges into a kind of Runner rather than the Runner of a pre-existing Vat.

This is just an optimization, as

     v1.morphInto("awt")
is equivalent to
     def v2 := vatMaker.make("awt")
     v1.mergeInto(v2)
but without bothering to create v2.

May be called from any thead.



comments?