document avian.Continuations

This commit is contained in:
Joel Dice 2009-05-29 18:32:16 -06:00
parent 02fba10614
commit b5cb1692fb
2 changed files with 150 additions and 1 deletions

View File

@ -12,10 +12,159 @@ package avian;
import java.util.concurrent.Callable;
/**
* This class provides access to the Avian VM's continuation support.
*
* <p>A continuation is a snapshot of a thread's call stack which can
* be captured via <code>callWithCurrentContinuation</code> and later
* restored any number of times. We restore this snapshot by either
* feeding it a result (to be returned by
* <code>callWithCurrentContinuation</code>) or feeding it an
* exception (to be thrown by
* <code>callWithCurrentContinuation</code>). Continuations may be
* used to implement features such as coroutines, generators, and
* cooperative multitasking.
*
* <p>This class provides two static methods -
* <code>callWithCurrentContinuation</code> and
* <code>dynamicWind</code> - with similar semantics to the Scheme
* methods <code>call-with-current-continuation</code> and
* <code>dynamic-wind</code>, respectively. Additionally, we define
* how continuations work with respect to native code, exceptions,
* try/finally blocks, synchronized blocks, and multithreading.
*
* <h3>Continuations and Continuation Contexts</h3>
*
* <p>A continuation can be thought of as a singly-linked list of
* stack frames representing the call trace, where the head of the
* list is the frame of the method most recently called (i.e. the top
* of the stack). However, this trace only extends as far as the most
* recent chain of Java frames - it ends just prior to the most recent
* native frame in the stack. The reason for this is that the VM
* cannot, in general, safely capture and restore native frames.
* Therefore, each call from native code to Java (including the
* original invocation of <code>main</code> or
* <code>Thread.run</code>) represents a new continuation context in
* which continuations may be captured, and these will only contain
* frames from within that context.
*
* <p>Calling a continuation (i.e. feeding it a result or exception)
* causes the current continuation to be replaced with the calling
* continuation. When the last method in this new continuation
* returns, it returns to the native frame which created the current
* context, which may not be the same as the context in which that
* continuation was created.
*
* <p>We define the return type of a continuation context as the
* return type of the least-recently called method in the call trace
* (i.e. the end of the list). A continuation may be called from a
* different continuation context than the one in which it was created
* provided the return type of the new context is compatible with the
* original context.
*
* <p>Given a thread executing in continuation context "A" which wants
* to call a continuation created in context "B", the following rules
* apply:
*
* <ul>
*
* <li>If the return type of "A" is <code>void</code>, the return
* type of "B" may be anything, including <code>void</code></li>
*
* <li>If the return type of "A" is a primitive type, the return
* type of "B" must match exactly</li>
*
* <li>If the return type of "A" is an object type, that type must
* assignable from the return type of "B" (i.e. the latter must
* either be the same as the former or a superclass or
* superinterface of it)</li>
*
* </ul>
*
* <p>A thread may call a continuation created by a different thread
* provided the return types are compatible. Multiple threads may
* safely call the same continuation simultaneously without
* synchronization. Any attempt to call a continuation from a context
* with an incompatible return type will result in an
* <code>avian/IncompatibleContinuationException<code> being thrown.
*
* <h3>Winding, Unwinding, and Rewinding</h3>
*
* <p>Traditionally, Java provides one way to wind the execution stack
* (recursive method calls) and two ways to unwind it (normal returns
* and exception unwinding). With continuations, we add a new way to
* (re)wind the stack and a new way to unwind it.
*
* <p>The call stack of a continuation may share frames with other
* continuations - in which case they share a common history. When
* calling a continuation "B" from the current continuation "A", we
* must unwind past any frames which are in "A" but not in "B" and
* rewind past any frames in "B" but not in "A". During this
* unwinding and rewinding, we may pass through synchronized and
* try/finally blocks while going down the old stack and up the new
* stack.
*
* <p>However, unlike the traditional processes of winding and
* unwinding, the VM will ignore these blocks - monitors will not be
* released or acquired and finally blocks will not execute. This is
* by design. The purpose of such a block is to acquire a resource
* before executing a task and release when that task is done. With
* continuations, we may wish to yield control temporarily to another
* continuation while executing such a task, and we might do so
* several times. In such a case we would only want to acquire the
* resource when we start the task and only release it when we're
* finished, regardless of how often we unwound to reach other
* continuations or rewound to return to the next step.
*
* <p>Conversely, we may wish to acquire and release a resource each
* time we (re)wind to or unwind from a continuation, respectively.
* In this case, we use <code>dynamicWind</code> to register functions
* which will run every time that frame is passed, regardless of how
* the stack is wound or unwound.
*/
public abstract class Continuations {
/**
* Captures the current continuation, passing a reference to the
* specified receiver.
*
* <p>This method will either return the result returned by
* <code>receiver.receive(Callback)</code>, propagate the exception
* thrown by that method, return the result passed to the
* handleResult(T) method of the continuation, or throw the
* exception passed to the handleException(Throwable) of the
* continuation.
*/
public static native <T> T callWithCurrentContinuation
(CallbackReceiver<T> receiver) throws Exception;
/**
* Calls the specified "before" and "after" tasks each time a
* continuation containing the call is wound or unwound,
* respectively.
*
* <p>This method first calls <code>before.run()</code>, then
* <code>thunk.call()</code>, and finally <code>after.run()</code>,
* returning the result of the second call. If
* <code>before.run()</code> does not return normally, the second
* and third calls will not happen. If <code>thunk.call()</code>
* throws an exception, <code>after.run()</code>, will be called
* before the exception is propagated.
*
* <p>If <code>thunk.call()</code> calls a continuation (directly or
* via a subroutine) which does not include the current call to
* <code>dynamicWind<code>, <code>after.run()</code> will be called
* before control passes to that continuation. If this call throws
* an exception, the exception will propagate to the current caller
* of <code>dynamicWind</code>.
*
* <p>If <code>thunk.call()</code> creates a continuation which is
* later called from a continuation which does not include the
* current call to <code>dynamicWind</code>,
* <code>before.run()</code> will be called before control passes to
* that continuation. As above, if this call throws an exception,
* the exception will propagate to the current caller of
* <code>dynamicWind</code>.
*/
public static <T> T dynamicWind(Runnable before,
Callable<T> thunk,
Runnable after)

View File

@ -363,7 +363,7 @@ tarball:
.PHONY: javadoc
javadoc:
javadoc -sourcepath classpath -d build/javadoc -subpackages java \
javadoc -sourcepath classpath -d build/javadoc -subpackages avian:java \
-windowtitle "Avian v$(version) Class Library API" \
-doctitle "Avian v$(version) Class Library API" \
-header "Avian v$(version)" \