kilim.Continuation Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of kilim Show documentation
Show all versions of kilim Show documentation
Coroutines, continuations, fibers, actors and message passing for the JVM
// copyright 2016 nqzero - offered under the terms of the MIT License
package kilim;
/**
* a minimal bridge or trampoline between woven and unwoven code
* backed by a Fiber
* giving the programmer explicit control over the event loop
* see Task for a more general and easier to use green thread implementation that automatically handles
* the event loop
* see Generator for more user friendly wrapper
*
* to use override execute() and call run()
* each time run() is called, execute runs until it yields, returns or throws an exception
* return value of true means either execute returned or threw an exception (accessible as ex())
* with state stored in an internal Fiber field across invocations
*
* to reuse a Continuation, call reset()
*
* Continuation provides no scheduler - it is entirely the responsibility of the calling code to
* call run() again once the pausing condition has been satisfied
* typically used for state machines and Generators
* or to port an existing event loop to kilim
*
* this is a low level facility, see kilim.examples.Xorshift.X2 for an example of direct use
*/
public abstract class Continuation implements Fiber.Worker {
private static Fiber.MethodRef runnerInfo = new Fiber.MethodRef(Continuation.class.getName(),"run");
static final FakeTask fakeTask = new FakeTask();
public static class FakeTask extends Task {
protected FakeTask() { super(false); }
Fiber.MethodRef getRunnerInfo() {
return runnerInfo;
}
}
/**
* get the stored exception
* @return the stored Exception if execute() has thrown one, otherwise null
*/
public Exception ex() { return ex; }
private Exception ex;
private kilim.Fiber fiber = new kilim.Fiber(fakeTask);
/**
* perform one iteration of execute()
* the first invocation begins as a normal method
* subsequent invocations continue from the most recent yield
*
* @return true if execute returned or threw an Exception (call ex() to retrieve)
*/
public boolean run() throws kilim.NotPausable {
// WARNING: the name of this method must match the name in runnerInfo
try {
fiber.begin();
assert (active=true)==true;
execute( fiber );
assert (active=false)==false;
}
catch (Exception kex) { ex = kex; }
boolean ret = ex==null ? fiber.end() : true;
return ret;
}
private boolean active = false;
/**
* the top level entrypoint for the continuation
* override this method
* cannot be called directly - use run() instead
* use Fiber.yield() to yield control cooperatively and return execution to the caller of run()
*/
public void execute() throws Pausable, Exception {
Task.errNotWoven();
}
/**
* the woven variant of execute() generated by the weaver
* overriding this method will cause the weaver to leave it unchanged
* this is a low level facility (override execute() instead)
* @param fiber the stack information automatically provided by run()
*/
public void execute(kilim.Fiber fiber) {}
/**
* reset the Continuation and corresponding Fiber
* cannot be called inside execute()
* subsequent invocations of run() will enter execute() as a normal method, ie at the beginning
*/
public void reset() {
assert !active : "invalid call to reset() during run()";
ex = null;
fiber.reset();
}
// performance notes:
// i3-2105: 5x Xorshift 5000000 20 --> median: 30.27
// units are nanos per iter
//
// regressions checks:
// assert !active: no change, -ea: +1.21
}